Sleazy Fork is available in English.

danbooru "you may like"

base visit history recommand posts

  1. // ==UserScript==
  2. // @name danbooru "you may like"
  3. // @name:zh-CN danbooru "you may like"
  4. // @name:zh-TW danbooru "you may like"
  5. // @name:ja danbooru "you may like"
  6. // @namespace danbooru_preference_push
  7. // @supportURL https://github.com/zhuzemin
  8. // @description base visit history recommand posts
  9. // @description:ja base visit history recommand posts
  10. // @description:zh-TW base visit history recommand posts
  11. // @description:zh-CN base visit history recommand posts
  12. // @include https://danbooru.donmai.us/
  13. // @include https://danbooru.donmai.us/posts/*
  14. // @version 1.11
  15. // @grant GM_xmlhttpRequest
  16. // @grant GM_registerMenuCommand
  17. // @grant GM_setValue
  18. // @grant GM_getValue
  19. // @run-at document-start
  20. // @author zhuzemin
  21. // @license Mozilla Public License 2.0; http://www.mozilla.org/MPL/2.0/
  22. // @license CC Attribution-ShareAlike 4.0 International; http://creativecommons.org/licenses/by-sa/4.0/
  23. // @connect-src danbooru.donmai.us
  24. // ==/UserScript==
  25. var config = {
  26. 'debug': false
  27. }
  28. var debug = config.debug ? console.log.bind(console) : function () {
  29. };
  30.  
  31. var hostname;
  32. var ContentPane;
  33. var ContentPaneChildNum;
  34. var FilledChildNum;
  35. var ObjectGalleryPage;
  36. var ObjectGallery;
  37. var VisitTags;
  38. var FavTags;
  39. var VisitLinks;
  40. var BlackTags;
  41. var DivCount;
  42. var TotalPage;
  43. class Gallery{
  44. constructor(href,other=null) {
  45. this.method = 'GET';
  46. this.url = href;
  47. this.headers = {
  48. 'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey',
  49. 'Referer': window.location.href,
  50. };
  51. this.charset = 'text/plain;charset=utf8';
  52. this.other=other;
  53. }
  54. }
  55. class GalleryPage{
  56. constructor(keyword,other=null) {
  57. this.method = 'GET';
  58. this.url = "https://"+hostname+"/posts?page="+keyword;
  59. this.headers = {
  60. 'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey',
  61. 'Referer': window.location.href,
  62. };
  63. this.charset = 'text/plain;charset=utf8';
  64. this.other=other;
  65. }
  66. }
  67.  
  68. // prepare UserPrefs
  69. setUserPref(
  70. 'BlockTags',
  71. 'multi-work series;translated;original;',
  72. 'Set BlockTags',
  73. `These Tags will not be factor for recommand. split with ";". Example: multi-work series;translated;original`,
  74. ','
  75. );
  76.  
  77. function init() {
  78. debug("init");
  79. VisitTags={};
  80. VisitLinks=[];
  81. try{
  82. VisitTags=JSON.parse(GM_getValue("VisitTags"));
  83. VisitLinks=GM_getValue("VisitLinks").split(",");
  84. BlackTags=GM_getValue("BlackTags");
  85. }catch(e){
  86. debug("Not VisitTags.");
  87. }
  88. if(BlackTags==undefined){
  89. BlackTags="";
  90.  
  91. }
  92. debug("BlackTags: "+BlackTags);
  93. if(window.location.href.includes("https://danbooru.donmai.us/posts/")){
  94. if(!VisitLinks.includes(window.location.href)){
  95. VisitLinks.push(window.location.href);
  96. GM_setValue("VisitLinks",VisitLinks.toString());
  97. var taglist = document.querySelector('#sidebar');
  98. var links=taglist.querySelectorAll("a.search-tag");
  99. for(var link of links) {
  100. var tag = link.innerText;
  101. if(Object.keys(VisitTags).length>0){
  102. var count=1;
  103. for(var VisitTag of Object.keys(VisitTags)){
  104. if(tag==VisitTag){
  105. VisitTags[tag]+=1;
  106. break;
  107. }
  108. else if(count==Object.keys(VisitTags).length){
  109. VisitTags[tag]=1;
  110. }
  111. count++;
  112. }
  113. }
  114. else{
  115. VisitTags[tag]=1;
  116. }
  117. }
  118. GM_setValue("VisitTags",JSON.stringify(VisitTags));
  119. }
  120. debug("VisitTags: "+JSON.stringify(VisitTags));
  121. }
  122. else{
  123. CreateButton();
  124. }
  125. }
  126.  
  127. function CreateButton(){
  128. var btn=document.createElement("button");
  129. btn.type="button";
  130. btn.onclick="";
  131. btn.innerHTML=`You may like`;
  132. btn.addEventListener('click',ShowRecommand);
  133. var p=document.querySelector("#subnav-menu");
  134. p.insertBefore(btn,null);
  135. }
  136.  
  137. function ShowRecommand() {
  138. debug("ShowRecommand");
  139. //window.location.href+="#E-Hentai_Display_Tag_with_thumb";
  140. FavTags=[];
  141. GetFavTag();
  142. debug(FavTags);
  143. CreateStyle();
  144. hostname=getLocation(window.location.href).hostname;
  145. ContentPane=document.querySelector("#posts-container");
  146. var articles=ContentPane.querySelectorAll("article");
  147. TotalPage=parseInt(articles[0].getAttribute("id").split("_")[1]);
  148. ContentPaneChildNum=articles.length;
  149. debug("ContentPaneChildNum: " +ContentPaneChildNum);
  150. FilledChildNum=0;
  151. //clear ContentPane
  152. while (ContentPane.firstChild) {
  153. ContentPane.removeChild(ContentPane.firstChild);
  154. }
  155. FillPane(TotalPage);
  156. }
  157.  
  158. function FillPane(TotalPage){
  159. debug("FillPane");
  160. var RandomPage = Math.floor(Math.random() * (1000+1 - 0));
  161. //var RandomPage = Math.floor(Math.random() * (TotalPage/ContentPaneChildNum+1 - 0));
  162. ObjectGalleryPage=new GalleryPage(RandomPage);
  163. debug(ObjectGalleryPage.url);
  164. request(ObjectGalleryPage,SearchGallery);
  165. }
  166.  
  167. function SearchGallery(responseDetails) {
  168. debug("SearchGallery");
  169. var responseText=responseDetails.responseText;
  170. var dom = new DOMParser().parseFromString(responseText, "text/html");
  171. var CurrentContentPane=dom.querySelector('#posts-container');
  172. var divs = CurrentContentPane.querySelectorAll('article');
  173. debug("divs.length: "+divs.length);
  174. DivCount=0;
  175. var href = divs[DivCount].querySelector('a').href;
  176. ObjectGallery = new Gallery(href,divs);
  177. //request(ObjectGallery,GetGalleryTag);
  178. GetGalleryTag(null,divs);
  179. }
  180.  
  181. function GetGalleryTag(responseDetails,divs) {
  182. debug("GetGalleryTag");
  183. try{
  184. var div=divs[DivCount];
  185. //var responseText=responseDetails.responseText;
  186. //var dom = new DOMParser().parseFromString(responseText, "text/html");
  187. //var taglist = dom.querySelector('#tag-list');
  188. //var links=taglist.querySelectorAll("a.search-tag");
  189. //shuffle array
  190. var shuffle=function (sourceArray) {
  191. for (var i = 0; i < sourceArray.length - 1; i++) {
  192. var j = i + Math.floor(Math.random() * (sourceArray.length - i));
  193.  
  194. var temp = sourceArray[j];
  195. sourceArray[j] = sourceArray[i];
  196. sourceArray[i] = temp;
  197. }
  198. return sourceArray;
  199. }
  200. var FavCount=parseInt(div.getAttribute("data-fav-count"));
  201. if(FavCount>=30){
  202. var links=div.getAttribute("data-tags").split(/\s/);
  203. var href=div.querySelector("a").href;
  204. var count=0;
  205. var Break;
  206. FavTags=shuffle(FavTags);
  207. debug("FavTags: "+FavTags);
  208. for(var link of links){
  209. if(FavTags==0){
  210. break;
  211. }
  212. var tag=link;
  213. //var tag=link.innerText;
  214. for(var FavTag of FavTags) {
  215. if(count>=12||count==FavTags.length){
  216. if(!VisitLinks.includes(href) ){
  217. ContentPane.insertBefore(div,null);
  218. debug("Insert div");
  219. debug("FilledChildNum: "+FilledChildNum);
  220. count=0;
  221. FilledChildNum++;
  222. Break=true;
  223. break;
  224.  
  225. }
  226. }
  227. else if (tag == FavTag.trim()) {
  228. //debug("FavTag: " + FavTag);
  229. //link.parentNode.className +=" glowbox";
  230. count++;
  231. }
  232. }
  233. if(Break){break;}
  234.  
  235. }
  236. }
  237.  
  238. }
  239. catch(e){
  240. debug("Error: "+e);
  241. }
  242. if(FilledChildNum<=ContentPaneChildNum) {
  243. if (DivCount < divs.length-1) {
  244. if (FilledChildNum == ContentPaneChildNum) {
  245. debug("finish");
  246. return;
  247. }
  248. else if (FavTags.length == 0) {
  249. debug("Insert divs");
  250. for(div of divs){
  251. ContentPane.insertBefore(div, null);
  252. FilledChildNum++;
  253.  
  254. }
  255. }
  256. else {
  257. debug("DivCount: " + DivCount);
  258. DivCount++;
  259. GetGalleryTag(null,divs);
  260. }
  261. }
  262. else {
  263. FillPane(TotalPage);
  264. }
  265. }
  266. }
  267.  
  268. function JsonSort(VisitTags,Method){
  269. //convert object to array
  270. var sortable = [];
  271. for (var VisitTag in VisitTags) {
  272. if(VisitTag.match(/^\d*$/)==null){
  273. sortable.push([VisitTag, VisitTags[VisitTag]]);
  274. }
  275. }
  276. //sort by reverse
  277. sortable.sort(function(a, b) {
  278. return a[1] - b[1];
  279. }).reverse();
  280. var array;
  281. if(Method=="shuffle"){
  282. //shuffle array
  283. var shuffle=function (sourceArray) {
  284. for (var i = 0; i < sourceArray.length - 1; i++) {
  285. var j = i + Math.floor(Math.random() * (sourceArray.length - i));
  286.  
  287. var temp = sourceArray[j];
  288. sourceArray[j] = sourceArray[i];
  289. sourceArray[i] = temp;
  290. }
  291. return sourceArray;
  292. }
  293. array=shuffle;
  294. }
  295. else if (Method=="sort"){
  296. array=sortable;
  297. }
  298.  
  299. //convert array to object
  300. var ArrayToObj=function (sortable){
  301. VisitTags={};
  302. sortable.forEach(function(item){
  303. VisitTags[item[0]]=item[1]
  304. })
  305. return VisitTags;
  306. }
  307. return ArrayToObj(array);
  308. }
  309.  
  310. function GetFavTag(){
  311.  
  312. VisitTags=JsonSort(VisitTags,"sort");
  313. debug("VisitTags: "+JSON.stringify(VisitTags));
  314. var count=0;
  315. for(var VisitTag of Object.keys(VisitTags)){
  316. if(VisitTags[VisitTag]==1){
  317. return;
  318. }
  319. else if(!BlackTags.includes(VisitTag.trim())){
  320. FavTags.push(VisitTag);
  321. if(count==Math.floor(Object.keys(VisitTags).length/3)) {
  322. //VisitTags too many, need shuffling
  323. if(VisitTags[VisitTag]>=Math.floor(Object.keys(VisitTags).length/3)){
  324. VisitTags=JsonSort(VisitTags,"shuffle");
  325. GM_setValue("VisitTags",JSON.stringify(VisitTags));
  326. }
  327. return;
  328. }
  329. }
  330. count++;
  331. }
  332. }
  333.  
  334.  
  335.  
  336. function getLocation(href) {
  337. var l = document.createElement("a");
  338. l.href = href;
  339. return l;
  340. }
  341.  
  342.  
  343. function request(object,func) {
  344. var retries = 10;
  345. GM_xmlhttpRequest({
  346. method: object.method,
  347. url: object.url,
  348. headers: object.headers,
  349. overrideMimeType: object.charset,
  350. //synchronous: true
  351. onload: function (responseDetails) {
  352. if (responseDetails.status != 200) {
  353. // retry
  354. if (retries--) { // *** Recurse if we still have retries
  355. setTimeout(request,2000);
  356. return;
  357. }
  358. }
  359. //debug(responseDetails);
  360. //Dowork
  361. func(responseDetails,object.other);
  362. }
  363. })
  364. }
  365. function CreateStyle(){
  366. debug("Start: CreateStyle");
  367. var style=document.createElement("style");
  368. style.setAttribute("type","text/css");
  369. style.innerHTML=`
  370. .glowbox {
  371. background: #4c4c4c;
  372. //width: 400px;
  373. margin: 40px 0 0 40px;
  374. padding: 10px;
  375. -moz-box-shadow: 0 0 5px 5px #FFFF00;
  376. -webkit-box-shadow: 0 0 5px 5px #FFFF00;
  377. box-shadow: 0 0 5px 5px #FFFF00;
  378. }
  379. `;
  380. debug("Processing: CreateStyle");
  381. var head=document.querySelector("head");
  382. head.insertBefore(style,null);
  383. debug("End: CreateStyle");
  384. }
  385.  
  386. // setting User Preferences
  387. function setUserPref(varName, defaultVal, menuText, promtText, sep){
  388. GM_registerMenuCommand(menuText, function() {
  389. var val = prompt(promtText, GM_getValue(varName, defaultVal));
  390. if (val === null) { return; } // end execution if clicked CANCEL
  391. // prepare string of variables separated by the separator
  392. if (sep && val){
  393. var pat1 = new RegExp('\\s*' + sep + '+\\s*', 'g'); // trim space/s around separator & trim repeated separator
  394. var pat2 = new RegExp('(?:^' + sep + '+|' + sep + '+$)', 'g'); // trim starting & trailing separator
  395. //val = val.replace(pat1, sep).replace(pat2, '');
  396. }
  397. //val = val.replace(/\s{2,}/g, ' ').trim(); // remove multiple spaces and trim
  398. GM_setValue(varName, val);
  399. // Apply changes (immediately if there are no existing highlights, or upon reload to clear the old ones)
  400. //if(!document.body.querySelector(".THmo")) THmo_doHighlight(document.body);
  401. //else location.reload();
  402. });
  403. }
  404.  
  405. if (document.body) init();
  406. else window.addEventListener('DOMContentLoaded', init);
  407.