danbooru "you may like"

base visit history recommand posts

// ==UserScript==
// @name        danbooru "you may like"
// @name:zh-CN        danbooru "you may like"
// @name:zh-TW        danbooru "you may like"
// @name:ja        danbooru "you may like"
// @namespace   danbooru_preference_push
// @supportURL  https://github.com/zhuzemin
// @description base visit history recommand posts
// @description:ja base visit history recommand posts
// @description:zh-TW  base visit history recommand posts
// @description:zh-CN base visit history recommand posts
// @include     https://danbooru.donmai.us/
// @include     https://danbooru.donmai.us/posts/*
// @version     1.11
// @grant       GM_xmlhttpRequest
// @grant         GM_registerMenuCommand
// @grant         GM_setValue
// @grant         GM_getValue
// @run-at      document-start
// @author      zhuzemin
// @license     Mozilla Public License 2.0; http://www.mozilla.org/MPL/2.0/
// @license     CC Attribution-ShareAlike 4.0 International; http://creativecommons.org/licenses/by-sa/4.0/
// @connect-src danbooru.donmai.us
// ==/UserScript==
var config = {
    'debug': false
}
var debug = config.debug ? console.log.bind(console)  : function () {
};

var hostname;
var ContentPane;
var ContentPaneChildNum;
var FilledChildNum;
var ObjectGalleryPage;
var ObjectGallery;
var VisitTags;
var FavTags;
var VisitLinks;
var BlackTags;
var DivCount;
var TotalPage;
class Gallery{
    constructor(href,other=null) {
        this.method = 'GET';
        this.url = href;
        this.headers = {
            'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey',
            'Referer': window.location.href,
        };
        this.charset = 'text/plain;charset=utf8';
        this.other=other;
    }
}
class GalleryPage{
    constructor(keyword,other=null) {
        this.method = 'GET';
        this.url = "https://"+hostname+"/posts?page="+keyword;
        this.headers = {
            'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey',
            'Referer': window.location.href,
        };
        this.charset = 'text/plain;charset=utf8';
        this.other=other;
    }
}

// prepare UserPrefs
setUserPref(
    'BlockTags',
    'multi-work series;translated;original;',
    'Set BlockTags',
    `These Tags will not be factor for recommand. split with ";". Example: multi-work series;translated;original`,
    ','
);

function init() {
    debug("init");
    VisitTags={};
    VisitLinks=[];
    try{
        VisitTags=JSON.parse(GM_getValue("VisitTags"));
        VisitLinks=GM_getValue("VisitLinks").split(",");
            BlackTags=GM_getValue("BlackTags");
    }catch(e){
        debug("Not VisitTags.");
    }
    if(BlackTags==undefined){
        BlackTags="";

    }
    debug("BlackTags: "+BlackTags);
    if(window.location.href.includes("https://danbooru.donmai.us/posts/")){
        if(!VisitLinks.includes(window.location.href)){
            VisitLinks.push(window.location.href);
            GM_setValue("VisitLinks",VisitLinks.toString());
            var taglist = document.querySelector('#sidebar');
            var links=taglist.querySelectorAll("a.search-tag");
            for(var link of links) {
                var tag = link.innerText;
                if(Object.keys(VisitTags).length>0){
                    var count=1;
                    for(var VisitTag of Object.keys(VisitTags)){
                        if(tag==VisitTag){
                            VisitTags[tag]+=1;
                            break;
                        }
                        else if(count==Object.keys(VisitTags).length){
                            VisitTags[tag]=1;
                        }
                        count++;
                    }
                }
                else{
                    VisitTags[tag]=1;
                }
            }
            GM_setValue("VisitTags",JSON.stringify(VisitTags));
        }
        debug("VisitTags: "+JSON.stringify(VisitTags));
    }
    else{
        CreateButton();
    }
}

function CreateButton(){
    var btn=document.createElement("button");
    btn.type="button";
    btn.onclick="";
    btn.innerHTML=`You may like`;
    btn.addEventListener('click',ShowRecommand);
    var p=document.querySelector("#subnav-menu");
    p.insertBefore(btn,null);
}

function  ShowRecommand() {
    debug("ShowRecommand");
    //window.location.href+="#E-Hentai_Display_Tag_with_thumb";
    FavTags=[];
    GetFavTag();
    debug(FavTags);
    CreateStyle();
    hostname=getLocation(window.location.href).hostname;
    ContentPane=document.querySelector("#posts-container");
    var articles=ContentPane.querySelectorAll("article");
    TotalPage=parseInt(articles[0].getAttribute("id").split("_")[1]);
    ContentPaneChildNum=articles.length;
    debug("ContentPaneChildNum: " +ContentPaneChildNum);
    FilledChildNum=0;
    //clear ContentPane
    while (ContentPane.firstChild) {
        ContentPane.removeChild(ContentPane.firstChild);
    }
    FillPane(TotalPage);
}

function FillPane(TotalPage){
    debug("FillPane");
    var RandomPage = Math.floor(Math.random() * (1000+1 - 0));
            //var RandomPage = Math.floor(Math.random() * (TotalPage/ContentPaneChildNum+1 - 0));
            ObjectGalleryPage=new GalleryPage(RandomPage);
    debug(ObjectGalleryPage.url);
    request(ObjectGalleryPage,SearchGallery);
}

function SearchGallery(responseDetails) {
    debug("SearchGallery");
    var responseText=responseDetails.responseText;
    var dom = new DOMParser().parseFromString(responseText, "text/html");
    var CurrentContentPane=dom.querySelector('#posts-container');
    var divs = CurrentContentPane.querySelectorAll('article');
    debug("divs.length: "+divs.length);
    DivCount=0;
    var href = divs[DivCount].querySelector('a').href;
    ObjectGallery = new Gallery(href,divs);
    //request(ObjectGallery,GetGalleryTag);
    GetGalleryTag(null,divs);
}

function GetGalleryTag(responseDetails,divs) {
    debug("GetGalleryTag");
    try{
        var div=divs[DivCount];
        //var responseText=responseDetails.responseText;
        //var dom = new DOMParser().parseFromString(responseText, "text/html");
        //var taglist = dom.querySelector('#tag-list');
        //var links=taglist.querySelectorAll("a.search-tag");
    //shuffle array
    var shuffle=function (sourceArray) {
        for (var i = 0; i < sourceArray.length - 1; i++) {
            var j = i + Math.floor(Math.random() * (sourceArray.length - i));

            var temp = sourceArray[j];
            sourceArray[j] = sourceArray[i];
            sourceArray[i] = temp;
        }
        return sourceArray;
    }
    
        var FavCount=parseInt(div.getAttribute("data-fav-count"));
        if(FavCount>=30){
        var links=div.getAttribute("data-tags").split(/\s/);
        var href=div.querySelector("a").href;
        var count=0;
        var Break;
    FavTags=shuffle(FavTags);
    debug("FavTags: "+FavTags);
        for(var link of links){
            if(FavTags==0){
                break;
            }
            var tag=link;
            //var tag=link.innerText;
            for(var FavTag of FavTags) {
                if(count>=12||count==FavTags.length){
                    if(!VisitLinks.includes(href) ){
                        ContentPane.insertBefore(div,null);
                        debug("Insert div");
                        debug("FilledChildNum: "+FilledChildNum);
                        count=0;
                        FilledChildNum++;
                        Break=true;
                        break;

                    }
                }
                else if (tag == FavTag.trim()) {
                    //debug("FavTag: " + FavTag);
                    //link.parentNode.className +=" glowbox";
                    count++;
                }
            }
            if(Break){break;}

        }
            
        }

    }
    catch(e){
        debug("Error: "+e);
    }
    if(FilledChildNum<=ContentPaneChildNum) {
        if (DivCount < divs.length-1) {
            if (FilledChildNum == ContentPaneChildNum) {
                debug("finish");
                return;
            }
            else if (FavTags.length == 0) {
                debug("Insert divs");
                for(div of divs){
                    ContentPane.insertBefore(div, null);
                    FilledChildNum++;

                }
            }
            else {
                debug("DivCount: " + DivCount);
                DivCount++;
                GetGalleryTag(null,divs);
            }
        }
        else {
            FillPane(TotalPage);
        }
    }
}

function JsonSort(VisitTags,Method){
    //convert object to array
    var sortable = [];
    for (var VisitTag in VisitTags) {
        if(VisitTag.match(/^\d*$/)==null){
        sortable.push([VisitTag, VisitTags[VisitTag]]);
            
        }
    }
    //sort by reverse
    sortable.sort(function(a, b) {
        return a[1] - b[1];
    }).reverse();
var array;
if(Method=="shuffle"){
    //shuffle array
    var shuffle=function (sourceArray) {
        for (var i = 0; i < sourceArray.length - 1; i++) {
            var j = i + Math.floor(Math.random() * (sourceArray.length - i));

            var temp = sourceArray[j];
            sourceArray[j] = sourceArray[i];
            sourceArray[i] = temp;
        }
        return sourceArray;
    }
    array=shuffle;
    
}
    else if (Method=="sort"){
        array=sortable;
    }

    //convert array to object
    var ArrayToObj=function (sortable){
        VisitTags={};
        sortable.forEach(function(item){
            VisitTags[item[0]]=item[1]
        })
        return VisitTags;
    }
    
    return ArrayToObj(array);
}

function GetFavTag(){

    VisitTags=JsonSort(VisitTags,"sort");
        debug("VisitTags: "+JSON.stringify(VisitTags));
    var count=0;
    for(var VisitTag of Object.keys(VisitTags)){
        if(VisitTags[VisitTag]==1){
            return;
        }
        else if(!BlackTags.includes(VisitTag.trim())){
            FavTags.push(VisitTag);
            if(count==Math.floor(Object.keys(VisitTags).length/3)) {
                //VisitTags too many, need shuffling
                if(VisitTags[VisitTag]>=Math.floor(Object.keys(VisitTags).length/3)){
                    VisitTags=JsonSort(VisitTags,"shuffle");
                    GM_setValue("VisitTags",JSON.stringify(VisitTags));
                }
                return;
            }
        }
        count++;
    }
}



function getLocation(href) {
    var l = document.createElement("a");
    l.href = href;
    return l;
}


function request(object,func) {
    var retries = 10;
    GM_xmlhttpRequest({
        method: object.method,
        url: object.url,
        headers: object.headers,
        overrideMimeType: object.charset,
        //synchronous: true
        onload: function (responseDetails) {
            if (responseDetails.status != 200) {
                // retry
                if (retries--) {          // *** Recurse if we still have retries
                    setTimeout(request,2000);
                    return;
                }
            }
            //debug(responseDetails);
            //Dowork
            func(responseDetails,object.other);
        }
    })
}
function CreateStyle(){
    debug("Start: CreateStyle");
    var style=document.createElement("style");
    style.setAttribute("type","text/css");
    style.innerHTML=`
.glowbox {
     background: #4c4c4c; 
    //width: 400px;
    margin: 40px 0 0 40px;
    padding: 10px;
    -moz-box-shadow: 0 0 5px 5px #FFFF00;
    -webkit-box-shadow: 0 0 5px 5px #FFFF00;
    box-shadow: 0 0 5px 5px #FFFF00;
}
`;
    debug("Processing: CreateStyle");
    var head=document.querySelector("head");
    head.insertBefore(style,null);
    debug("End: CreateStyle");
}

// setting User Preferences
function setUserPref(varName, defaultVal, menuText, promtText, sep){
    GM_registerMenuCommand(menuText, function() {
        var val = prompt(promtText, GM_getValue(varName, defaultVal));
        if (val === null)  { return; }  // end execution if clicked CANCEL
        // prepare string of variables separated by the separator
        if (sep && val){
            var pat1 = new RegExp('\\s*' + sep + '+\\s*', 'g'); // trim space/s around separator & trim repeated separator
            var pat2 = new RegExp('(?:^' + sep + '+|' + sep + '+$)', 'g'); // trim starting & trailing separator
            //val = val.replace(pat1, sep).replace(pat2, '');
        }
        //val = val.replace(/\s{2,}/g, ' ').trim();    // remove multiple spaces and trim
        GM_setValue(varName, val);
        // Apply changes (immediately if there are no existing highlights, or upon reload to clear the old ones)
        //if(!document.body.querySelector(".THmo")) THmo_doHighlight(document.body);
        //else location.reload();
    });
}

if (document.body) init();
else window.addEventListener('DOMContentLoaded', init);