Danbooru Ajax Interface

New interface to search images on Booru-style sites.

ของเมื่อวันที่ 10-02-2016 ดู เวอร์ชันล่าสุด

  1. // ==UserScript==
  2. // @name Danbooru Ajax Interface
  3. // @namespace http://danbooru.donmai.us
  4. // @description New interface to search images on Booru-style sites.
  5.  
  6. // @include http://danbooru.donmai.us/
  7. // @include http://danbooru.donmai.us/#*
  8. // @include http://www.donmai.us/
  9. // @include http://www.donmai.us/#*
  10. // @include http://donmai.us/
  11. // @include http://donmai.us/#*
  12.  
  13. // @include http://gelbooru.com/
  14. // @include http://gelbooru.com/#*
  15. // @include http://www.gelbooru.com/
  16. // @include http://www.gelbooru.com/#*
  17.  
  18. // @include http://konachan.com/
  19. // @include http://konachan.com/#*
  20. // @include http://konachan.net/
  21. // @include http://konachan.net/#*
  22.  
  23. // @include https://yande.re/post
  24. // @include https://yande.re/post#*
  25.  
  26. // @version 3.141592
  27. // @grant GM_addStyle
  28. // @grant GM_getValue
  29. // @grant GM_setValue
  30. // @grant GM_deleteValue
  31. // @grant GM_xmlhttpRequest
  32. // ==/UserScript==
  33.  
  34. // CONSTANTS
  35. const ratio = ((1 + Math.sqrt(5)) / 2);
  36. const d = document;
  37.  
  38. // NEW SITES CAN BE ADDED NOW
  39. var sites = [
  40. {
  41. name : "Danbooru", // Site name
  42. site : "donmai\.us", // Regular expression check on current url
  43. post : "/post/index.xml", // Relative url to xml post API
  44. note : "/notes.xml", // Relative url to xml note API
  45. list : "/posts/", // Relative url to post listing
  46. page : "/posts/", // Relative url to post page
  47. query : function(tags, images, page, postid) { // Query passed to API
  48. return (postid ? "?group_by=note&limit=99999&search[post_id]=" + postid : "?tags=" + tags + (page ? "&page=" + page + "&limit=" + images : ""));
  49. }
  50. },
  51. {
  52. name : "Gelbooru",
  53. site : "(www\.)?gelbooru\.",
  54. post : "/index.php?page=dapi&s=post&q=index",
  55. note : "/index.php?page=dapi&s=note&q=index&post_id=",
  56. list : "/index.php?page=post&s=list",
  57. page : "/index.php?page=post&s=view&id=",
  58. query : function(tags, images, page, postid) {
  59. return (postid ? postid : "&tags=" + tags + "&limit=" + images + "&pid=" + (page - 1));
  60. }
  61. },
  62. {
  63. name : "Konachan",
  64. site : "konachan\.",
  65. post : "/post.xml",
  66. note : "/note.xml?post_id=",
  67. list : "/post/",
  68. page : "/post/show/",
  69. query : function(tags, images, page, postid) {
  70. return (postid ? postid : "?tags=" + tags + "&limit=" + images + "&page=" + page);
  71. }
  72. },
  73. {
  74. name : "Yande.re",
  75. site : "yande\.re",
  76. post : "/post.xml",
  77. note : "/note.xml?post_id=",
  78. list : "/post/",
  79. page : "/post/show/",
  80. query : function(tags, images, page, postid) {
  81. return (postid ? postid : "?tags=" + tags + "&limit=" + images + "&page=" + page);
  82. }
  83. }
  84. ];
  85.  
  86. var booru;
  87. for(var i = 0; i < sites.length; i++)
  88. if(new RegExp(sites[i].site).test(window.location.hostname))
  89. booru = sites[i];
  90.  
  91. var alltags = GM_getValue("tags", setDefaults("alltags", sites.length));
  92. var allpage = GM_getValue("page", setDefaults("allpage", sites.length));
  93. var allimages = GM_getValue("images", setDefaults("allimages", sites.length));
  94. var allrating = GM_getValue("rating", setDefaults("allrating", sites.length));
  95.  
  96. // PAGE CLEANING
  97. while(d.documentElement.firstChild)
  98. d.documentElement.removeChild(d.documentElement.firstChild);
  99.  
  100. d.documentElement.appendChild(d.createElement("HEAD"));
  101. d.documentElement.appendChild(d.createElement("BODY"));
  102. d.documentElement.firstChild.appendChild(title = d.createElement("TITLE"));
  103. title.appendChild(d.createTextNode(booru.name));
  104.  
  105. GM_addStyle("* { transition: all 2s ease-in-out 0s; } body { margin: 4px; } a { text-decoration: none; color: #0000EE; } img { border: 0px; } .thumb { border: 1px solid WhiteSmoke; min-width: 150px; min-height: 150px; max-width: 150px; max-height: 150px; margin: -1px 0px 0px -1px; padding: 1px; display: flex; justify-content: center; align-items: center; font-size: small; overflow: hidden; } .trans { border: 1px solid Black; background-color: LightYellow; position: absolute; }");
  106. GM_deleteValue("columns");
  107.  
  108. // SCRIPT STARTS HERE
  109. var tags = getValue("alltags", alltags);
  110. var page = getValue("allpage", allpage);
  111. var images = getValue("allimages", allimages);
  112. var rating = getValue("allrating", allrating);
  113.  
  114. var searchTable, searchTr, searchTd, searchForm, aLink, aTags, aReply, aTableBar, aLeftBar, aCenterBar, aRightBar, aTable, aTr1, aTr2, aTr3, aTd1, aTd2, aTd3, aTd4, aTd5, aTd6, aPage, aRS, aRQ, aRE, aFIT, aSD, aLS, aLQ, aLE, aLF, aLD, aImages, aPrev, aSearch, aNext, aTagsDisplay, imagesLayer, overlay, display, innerDisplay, sampleRate = 1;
  115. var cache = [];
  116.  
  117. d.body.appendChild(searchTable = d.createElement("TABLE"));
  118. searchTable.appendChild(searchTr = d.createElement("TR"));
  119. searchTr.setAttribute("style", "vertical-align: top;");
  120. searchTr.appendChild(searchTd = d.createElement("TD"));
  121. searchTd.setAttribute("style", "text-align: center;");
  122.  
  123. searchForm = d.createElement("FORM");
  124. searchForm.addEventListener("submit", function(event) {
  125. tags = aTags.value;
  126. page = Math.max(1, parseInt(aPage.value, 10));
  127. images = Math.max(1, Math.min(parseInt(aImages.value, 10), 100));
  128. rating = (aRS.checked ? "s" : "") + (aRQ.checked ? "q" : "") + (aRE.checked ? "e" : "") + (aFIT.checked ? "f" : "") + (aSD && aSD.checked ? "d" : "");
  129.  
  130. allimages = setValue("images", allimages, images);
  131. allrating = setValue("rating", allrating, rating);
  132.  
  133. search(tags, page);
  134. event.preventDefault();
  135. }, false);
  136.  
  137. searchForm.appendChild(aLink = d.createElement("A"));
  138. aLink.setAttribute("href", booru.list);
  139. aLink.setAttribute("tabindex", "1");
  140. aLink.appendChild(d.createTextNode(booru.name));
  141.  
  142. searchForm.appendChild(d.createElement("BR"));
  143.  
  144. searchForm.appendChild(aTags = d.createElement("INPUT"));
  145. aTags.setAttribute("type", "text");
  146. aTags.setAttribute("cols", 25);
  147. aTags.setAttribute("value", tags);
  148. aTags.setAttribute("tabindex", "2");
  149. aTags.addEventListener("change", function(event) {
  150. aPage.value = 1;
  151. }, false);
  152.  
  153. searchForm.appendChild(d.createElement("P"));
  154.  
  155. searchForm.appendChild(aReply = d.createElement("SPAN"));
  156. aReply.appendChild(d.createTextNode("Nobody here but us chickens!"));
  157.  
  158. searchForm.appendChild(d.createElement("P"));
  159.  
  160. // Slider
  161. aTableBar = d.createElement("TABLE");
  162. aTableBar.appendChild(d.createElement("TR"));
  163. aTableBar.setAttribute("style", "border-collapse: collapse; border: 1px solid Black; width: 100%; padding: 0px");
  164. aLeftBar = d.createElement("TD");
  165. aLeftBar.setAttribute("style", "padding: 0px;");
  166. aTableBar.firstChild.appendChild(aLeftBar);
  167. aCenterBar = d.createElement("TD");
  168. aCenterBar.setAttribute("style", "border: 1px solid Black; padding: 1.5px 0px; background-color: WhiteSmoke; width: 25%; min-width: 1px;");
  169. aTableBar.firstChild.appendChild(aCenterBar);
  170. aRightBar = d.createElement("TD");
  171. aRightBar.setAttribute("style", "padding: 0px; width: 100%;");
  172. aTableBar.firstChild.appendChild(aRightBar);
  173. searchForm.appendChild(aTableBar);
  174.  
  175. // Search options
  176. aTable = d.createElement("TABLE");
  177. aTr1 = d.createElement("TR");
  178.  
  179. aTd1 = d.createElement("TD");
  180. aTd1.appendChild(d.createTextNode("Page:"));
  181. aTr1.appendChild(aTd1);
  182.  
  183. aTd2 = d.createElement("TD");
  184. aPage = d.createElement("INPUT");
  185. aPage.setAttribute("type", "text");
  186. aPage.setAttribute("size", "1");
  187. aPage.setAttribute("value", page);
  188. aPage.setAttribute("tabindex", "3");
  189. aTd2.appendChild(aPage);
  190. aTr1.appendChild(aTd2);
  191.  
  192. aTd3 = d.createElement("TD");
  193. aTd3.setAttribute("style", "text-align: left;");
  194. aTd3.setAttribute("rowspan", "3");
  195.  
  196. aRS = d.createElement("INPUT");
  197. aRS.setAttribute("type", "checkbox");
  198. if(/s/.test(rating)) aRS.setAttribute("checked", "checked");
  199. aLS = d.createElement("LABEL");
  200. aLS.appendChild(aRS);
  201. aLS.appendChild(d.createTextNode("Safe"));
  202.  
  203. aTd3.appendChild(aLS);
  204. aTd3.appendChild(d.createElement("BR"));
  205.  
  206. aRQ = d.createElement("INPUT");
  207. aRQ.setAttribute("type", "checkbox");
  208. if(/q/.test(rating)) aRQ.setAttribute("checked", "checked");
  209. aLQ = d.createElement("LABEL");
  210. aLQ.appendChild(aRQ);
  211. aLQ.appendChild(d.createTextNode("Questionable"));
  212.  
  213. aTd3.appendChild(aLQ);
  214. aTd3.appendChild(d.createElement("BR"));
  215.  
  216. aRE = d.createElement("INPUT");
  217. aRE.setAttribute("type", "checkbox");
  218. if(/e/.test(rating)) aRE.setAttribute("checked", "checked");
  219. aLE = d.createElement("LABEL");
  220. aLE.appendChild(aRE);
  221. aLE.appendChild(d.createTextNode("Explicit"));
  222.  
  223. aTd3.appendChild(aLE);
  224. aTd3.appendChild(d.createElement("BR"));
  225.  
  226. if(booru.name=="Danbooru") {
  227. aSD = d.createElement("INPUT");
  228. aSD.setAttribute("type", "checkbox");
  229. if(/d/.test(rating)) aSD.setAttribute("checked", "checked");
  230. aLD = d.createElement("LABEL");
  231. aLD.appendChild(aSD);
  232. aLD.appendChild(d.createTextNode("Show deleted"));
  233.  
  234. aTd3.appendChild(aLD);
  235. aTd3.appendChild(d.createElement("BR"));
  236.  
  237. aSD.addEventListener("change", function(event) {
  238. for(var i in cache)
  239. d.getElementById("content").insertBefore(cache[i], d.getElementById("content").childNodes[cache[i].style.getPropertyValue("order")]);
  240.  
  241. setTimeout(function() { // transitions are stupid
  242. deletedlist = d.evaluate("//DIV[@class='thumb'][contains(@style, 'MistyRose')]", d, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
  243. if(aSD.checked) {
  244. for(var n = 0, deleted = null; deleted = deletedlist.snapshotItem(n++); n) {
  245. deleted.style.setProperty("opacity", "1", "");
  246. deleted.style.setProperty("padding", "1px", "");
  247. deleted.style.setProperty("margin", "-1px 0px 0px -1px", "");
  248. deleted.style.setProperty("border-width", "1px", "");
  249. deleted.style.setProperty("min-width", "150px", "");
  250. deleted.style.setProperty("max-width", "150px", "");
  251. }
  252. } else {
  253. cache.length = 0;
  254. for(var n = 0, deleted = null; deleted = deletedlist.snapshotItem(n++); n) {
  255. deleted.style.setProperty("opacity", "0", "");
  256. deleted.style.setProperty("padding", "0px", "");
  257. deleted.style.setProperty("margin", "0px", "");
  258. deleted.style.setProperty("border-width", "0px", "");
  259. deleted.style.setProperty("min-width", "0px", "");
  260. deleted.style.setProperty("max-width", "0px", "");
  261. cache.push(deleted);
  262. }
  263. }
  264. }, 25);
  265. }, false);
  266. } else {
  267. rating.replace("d", "");
  268. }
  269. aTr1.appendChild(aTd3);
  270.  
  271. aTr2 = d.createElement("TR");
  272.  
  273. aTd4 = d.createElement("TD");
  274. aTd4.appendChild(d.createTextNode("Images:"));
  275. aTr2.appendChild(aTd4);
  276.  
  277. aTd5 = d.createElement("TD");
  278. aImages = d.createElement("INPUT");
  279. aImages.setAttribute("type", "text");
  280. aImages.setAttribute("size", "1");
  281. aImages.setAttribute("value", images);
  282. aImages.setAttribute("tabindex", "4");
  283. aTd5.appendChild(aImages);
  284. aTr2.appendChild(aTd5);
  285.  
  286. aTr3 = d.createElement("TR");
  287.  
  288. aTd6 = d.createElement("TD");
  289. aTd6.setAttribute("colspan", "2");
  290. aFIT = d.createElement("INPUT");
  291. aFIT.setAttribute("type", "checkbox");
  292. aFIT.setAttribute("tabindex", "5");
  293. if(/f/.test(rating)) aFIT.setAttribute("checked", "checked");
  294. aLF = d.createElement("LABEL");
  295. aLF.appendChild(aFIT);
  296. aLF.appendChild(d.createTextNode("Fit width"));
  297.  
  298. aTd6.appendChild(aLF);
  299. aTr3.appendChild(aTd6);
  300.  
  301. aTable.appendChild(aTr1);
  302. aTable.appendChild(aTr2);
  303. aTable.appendChild(aTr3);
  304. searchForm.appendChild(aTable);
  305.  
  306. searchForm.appendChild(d.createElement("HR"));
  307.  
  308. searchForm.appendChild(aPrev = d.createElement("INPUT"));
  309. aPrev.setAttribute("type", "button");
  310. aPrev.setAttribute("value", "<");
  311. aPrev.setAttribute("disabled", "disabled");
  312. aPrev.addEventListener("click", function(event) {
  313. search(tags, --page);
  314. }, false);
  315.  
  316. searchForm.appendChild(aSearch = d.createElement("INPUT"));
  317. aSearch.setAttribute("type", "submit");
  318. aSearch.setAttribute("value", "Search");
  319.  
  320. searchForm.appendChild(aNext = d.createElement("INPUT"));
  321. aNext.setAttribute("type", "button");
  322. aNext.setAttribute("value", ">");
  323. aNext.setAttribute("disabled", "disabled");
  324. aNext.addEventListener("click", function(event) {
  325. search(tags, ++page);
  326. }, false);
  327.  
  328. searchForm.appendChild(d.createElement("HR"));
  329.  
  330. searchForm.appendChild(aTagsDisplay = d.createElement("DIV"));
  331. aTagsDisplay.setAttribute("style", "overflow-x: hidden;");
  332.  
  333. searchTd.appendChild(searchForm);
  334. searchTr.appendChild(imagesLayer = d.createElement("TD"));
  335.  
  336. fixsize = (searchTd.getBoundingClientRect().right - searchTd.getBoundingClientRect().left) + "px";
  337. searchTd.style.setProperty("min-width", fixsize, "important");
  338. searchTd.style.setProperty("max-width", fixsize, "important");
  339.  
  340. // "Lightbox"
  341. overlay = d.createElement("DIV");
  342. overlay.setAttribute("style", "display: none; position: fixed; top: 0px; left: 0px; width: 100%; height: 100%; background-color: Black; opacity: 0.8;");
  343. innerDisplay = d.createElement("DIV");
  344. innerDisplay.setAttribute("id", "innerDisplay");
  345. innerDisplay.setAttribute("style", "background-color: White; display: inline-block; padding: 10px; min-width: 200px; min-height: 200px; border-radius: 10px;");
  346. display = d.createElement("TABLE");
  347. display.setAttribute("style", "display: none; position: absolute; top: 0px; left: 0px; width: 100%; height: 100%; text-align: center; vertical-align: middle;");
  348. display.appendChild(d.createElement("TR"));
  349. display.firstChild.appendChild(d.createElement("TD"));
  350. display.firstChild.firstChild.appendChild(innerDisplay);
  351.  
  352. d.body.insertBefore(display, d.body.firstChild);
  353. d.body.insertBefore(overlay, d.body.firstChild);
  354.  
  355. if(!window.location.origin)
  356. window.location.origin = (window.location.protocol + "//" + window.location.host);
  357.  
  358. if(window.location.hash)
  359. search(window.location.hash.split("#")[1], 1);
  360.  
  361. var requestPost, requestNote, requestCount;
  362.  
  363. function search(newtags, newpage) {
  364. if(requestPost)
  365. requestPost.abort();
  366. if(requestNote)
  367. requestNote.abort();
  368. if(requestCount)
  369. requestCount.abort();
  370.  
  371. aTags.value = tags = newtags;
  372. aPage.value = page = newpage;
  373. aImages.value = images;
  374.  
  375. alltags = setValue("tags", alltags, tags);
  376. allpage = setValue("page", allpage, page);
  377.  
  378. aPrev.disabled = (newpage < 2);
  379. aRS.checked = /s/.test(rating);
  380. aRQ.checked = /q/.test(rating);
  381. aRE.checked = /e/.test(rating);
  382.  
  383. if(/^sf?d?$/.test(rating))
  384. newtags += " rating:safe";
  385. if(/^qf?d?$/.test(rating))
  386. newtags += " rating:questionable";
  387. if(/^ef?d?$/.test(rating))
  388. newtags += " rating:explicit";
  389. if(/^qef?d?$/.test(rating))
  390. newtags += " -rating:safe";
  391. if(/^sef?d?$/.test(rating))
  392. newtags += " -rating:questionable";
  393. if(/^sqf?d?$/.test(rating))
  394. newtags += " -rating:explicit";
  395.  
  396. if(imagesLayer.hasChildNodes())
  397. imagesLayer.removeChild(imagesLayer.firstChild);
  398.  
  399. imagesLayer.appendChild(d.createTextNode("Loading..."));
  400. requestPost = GM_xmlhttpRequest({
  401. method : "GET",
  402. url : window.location.origin + booru.post + booru.query(encodeURIComponent(newtags), images, page),
  403. headers : {
  404. "Accept" : "application/xml",
  405. "Cookie" : d.cookie
  406. },
  407. overrideMimeType : "application/xml; charset=utf-8",
  408. onload : function(response) {
  409. getContent(new DOMParser().parseFromString(response.responseText, "application/xml"), newtags);
  410. }
  411. });
  412. }
  413.  
  414. function showContent(xmldoc) {
  415. if(imagesLayer.hasChildNodes())
  416. imagesLayer.removeChild(imagesLayer.firstChild);
  417.  
  418. aReply.textContent = "Nobody here but us chickens!";
  419.  
  420. var posts = xmldoc.evaluate("posts", xmldoc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
  421. if(!posts) {
  422. reason = xmldoc.evaluate("response/@reason", xmldoc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
  423. if(reason)
  424. imagesLayer.textContent = reason.nodeValue;
  425. else
  426. imagesLayer.textContent = "Something broke.";
  427. return;
  428. }
  429. var post = xmldoc.evaluate("posts/post", xmldoc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  430. if(((parseInt(posts.getAttribute("offset"), 10) + 1) > posts.getAttribute("count")) & posts.getAttribute("count") > 0) {
  431. search(tags, Math.ceil(parseInt(posts.getAttribute("count"), 10) / images));
  432. return;
  433. }
  434.  
  435. if(posts.getAttribute("count") > 0) aReply.textContent = "Found " + posts.getAttribute("count") + ", showing " + (parseInt(posts.getAttribute("offset"), 10) + 1) + "-" + (Math.min(posts.getAttribute("count"), parseInt(posts.getAttribute("offset"), 10) + images));
  436. aLeftBar.style.setProperty("width", (posts.getAttribute("offset") / posts.getAttribute("count") * 100) + "%");
  437. aCenterBar.style.setProperty("width", (images / posts.getAttribute("count") * 100) + "%");
  438.  
  439. aNext.disabled = (page >= Math.ceil(posts.getAttribute("count") / images));
  440.  
  441. imagesLayer.appendChild(content = d.createElement("DIV"));
  442. content.setAttribute("style", "display: flex; flex-flow: row wrap;");
  443. content.setAttribute("id", "content");
  444. cache.length = 0;
  445.  
  446. for(var i = 0; i < images; i++) {
  447. content.appendChild(thumb = d.createElement("DIV"));
  448. data = post.snapshotItem(i);
  449. if(data) {
  450. if(/true/.test(data.getAttribute("has_notes")))
  451. thumb.style.setProperty("background-color", "LightYellow", "");
  452. if(/deleted/.test(data.getAttribute("status"))) {
  453. thumb.style.setProperty("background-color", "MistyRose", "");
  454. thumb.addEventListener("transitionend", function() { if(!aSD.checked) this.remove(); }, false);
  455. if(!aSD.checked) {
  456. thumb.style.setProperty("opacity", "0", "");
  457. thumb.style.setProperty("padding", "0", "");
  458. thumb.style.setProperty("margin", "0", "");
  459. thumb.style.setProperty("border-width", "0px", "");
  460. thumb.style.setProperty("min-width", "0px", "");
  461. thumb.style.setProperty("max-width", "0px", "");
  462. cache.push(thumb);
  463. thumb.remove();
  464. }
  465. }
  466.  
  467. var image = d.createElement("IMG");
  468. image.setAttribute("width", (data.getAttribute("preview_width") || "auto"));
  469. image.setAttribute("height", (data.getAttribute("preview_height") || "auto"));
  470. image.setAttribute("src", data.getAttribute("preview_url"));
  471. image.setAttribute("id", data.getAttribute("id"));
  472. image.setAttribute("alt", data.getAttribute("tags").trim());
  473. image.setAttribute("title", data.getAttribute("tags").trim() + " rating:" + data.getAttribute("rating").replace(/e$/, "Explicit").replace(/s$/, "Safe").replace(/q$/, "Questionable") + " score:" + data.getAttribute("score"));
  474.  
  475. if(/\.zip$/.test(data.getAttribute("file_url")))
  476. data.setAttribute("file_url", data.getAttribute("file_url").replace("data/", "data/sample/sample-").replace(".zip", ".webm"));
  477.  
  478. image.setAttribute("fullsize", data.getAttribute("file_url"));
  479. image.setAttribute("fullwidth", data.getAttribute("width"));
  480. image.setAttribute("fullheight", data.getAttribute("height"));
  481. image.setAttribute("notes", data.getAttribute("has_notes"));
  482. image.setAttribute("md5", data.getAttribute("md5"));
  483.  
  484. // Show tags on sidebar
  485. image.addEventListener("click", function(event) {
  486. if(aTagsDisplay.hasChildNodes())
  487. aTagsDisplay.removeChild(aTagsDisplay.firstChild);
  488. aTagsDisplay.appendChild(d.createElement("DIV"));
  489.  
  490. var tagnames = this.getAttribute("alt").split(" ");
  491. for(var t = 0; t < tagnames.length; t++) {
  492. var taglink = d.createElement("A");
  493. taglink.appendChild(d.createTextNode(tagnames[t]));
  494. taglink.setAttribute("href", "#" + tagnames[t]);
  495. taglink.addEventListener("click", function(event) {
  496. aTags.value = this.textContent;
  497. aPage.value = 1;
  498. aSearch.click();
  499. event.preventDefault();
  500. }, false);
  501. aTagsDisplay.firstChild.appendChild(taglink);
  502. aTagsDisplay.firstChild.appendChild(document.createElement("BR"));
  503. }
  504.  
  505. // CTRL + click to show only the tags
  506. if(event.ctrlKey) return;
  507.  
  508. // "Lightbox" by VIPPER ("How do I jQuery?")
  509. while(innerDisplay.hasChildNodes())
  510. innerDisplay.removeChild(innerDisplay.firstChild);
  511.  
  512. overlay.addEventListener("click", function(event) {
  513. if(event.target.id) return;
  514. overlay.style.setProperty("display", "none", "");
  515. display.style.setProperty("display", "none", "");
  516. window.removeEventListener("keydown", keylistener, false);
  517. window.removeEventListener("keyup", saveimage, false);
  518. }, false);
  519.  
  520. display.addEventListener("click", function(event) {
  521. if(event.target.id) return;
  522. overlay.style.setProperty("display", "none", "");
  523. display.style.setProperty("display", "none", "");
  524. window.removeEventListener("keydown", keylistener, false);
  525. window.removeEventListener("keyup", saveimage, false);
  526. }, false);
  527.  
  528. display.addEventListener("dblclick", function(event) {
  529. overlay.style.setProperty("display", "none", "");
  530. display.style.setProperty("display", "none", "");
  531. window.removeEventListener("keydown", keylistener, false);
  532. window.removeEventListener("keyup", saveimage, false);
  533. }, false);
  534.  
  535. if(/\.swf$/.test(this.getAttribute("fullsize"))) {
  536. fullsize = d.createElement("EMBED");
  537. } else if(/\.webm$|\.zip$/.test(this.getAttribute("fullsize"))) {
  538. fullsize = d.createElement("VIDEO");
  539. fullsize.setAttribute("controls", true);
  540. fullsize.setAttribute("loop", true);
  541. fullsize.setAttribute("autoplay", true);
  542. if(/\.zip$/.test(this.getAttribute("fullsize")))
  543. this.setAttribute("fullsize", this.getAttribute("fullsize").replace("data/", "data/sample/sample-").replace(".zip", ".webm"));
  544. } else {
  545. fullsize = d.createElement("IMG");
  546. fullsize.addEventListener("click", function(event) {
  547. noteDivs = d.evaluate("//DIV[starts-with(@id, 'note')]", d, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
  548. for(var n = 0, note = null; note = noteDivs.snapshotItem(n++); n) {
  549. if(window.getComputedStyle(note, null).getPropertyValue("visibility") == "visible")
  550. note.style.setProperty("visibility", "hidden", "");
  551. else
  552. note.style.setProperty("visibility", "visible", "");
  553. }
  554. }, false);
  555. }
  556. fullsize.setAttribute("src", this.getAttribute("fullsize"));
  557. fullsize.setAttribute("width", this.getAttribute("fullwidth"));
  558. fullsize.setAttribute("height", this.getAttribute("fullheight"));
  559. fullsize.setAttribute("id", this.getAttribute("id"));
  560. fullsize.setAttribute("notes", this.getAttribute("notes"));
  561. fullsize.setAttribute("md5", this.getAttribute("md5"));
  562. fullsize.style.setProperty("transition-property", "none", "");
  563.  
  564. if(fullsize.getAttribute("notes") == "true") {
  565. requestNote = GM_xmlhttpRequest({
  566. method : "GET",
  567. url : window.location.origin + booru.note + booru.query(null, null, null, fullsize.getAttribute("id")),
  568. headers : {
  569. "Accept" : "application/xml",
  570. "Cookie" : d.cookie
  571. },
  572. overrideMimeType : "application/xml; charset=utf-8",
  573. onload : function(response) {
  574. getNotes(new DOMParser().parseFromString(response.responseText, "application/xml"), response.finalUrl);
  575. }
  576. });
  577. }
  578.  
  579. var pagelink = d.createElement("A");
  580. pagelink.setAttribute("href", booru.page + fullsize.getAttribute("id"));
  581. pagelink.appendChild(d.createTextNode(fullsize.getAttribute("id")));
  582.  
  583. innerDisplay.appendChild(fullsize);
  584. innerDisplay.appendChild(d.createElement("BR"));
  585. innerDisplay.appendChild(pagelink);
  586.  
  587. overlay.style.setProperty("display", "", "");
  588. display.style.setProperty("display", "", "");
  589.  
  590. sampleRate = 1;
  591. var clientwidth = Math.min(d.documentElement.clientWidth, d.body.clientWidth) - 22;
  592. if(aFIT.checked && this.getAttribute("fullwidth") > clientwidth) {
  593. sampleRate = clientwidth / this.getAttribute("fullwidth");
  594. fullsize.setAttribute("width", clientwidth);
  595. fullsize.setAttribute("height", Math.floor(this.getAttribute("fullheight") * clientwidth / this.getAttribute("fullwidth")));
  596. }
  597.  
  598. // CTRL+S to save image
  599. window.addEventListener("keydown", keylistener, false);
  600. window.addEventListener("keyup", saveimage, false);
  601. }, false);
  602. var keydown = false;
  603. var keylistener = function(event) {
  604. if(!keydown && event.ctrlKey && event.keyCode == 83) {
  605. event.preventDefault();
  606. event.stopPropagation();
  607. if(!keydown) keydown = true;
  608. }
  609. };
  610. var saveimage = function(event) {
  611. if(!keydown) return;
  612. var imgdown = d.createElement("A");
  613. thumb.appendChild(imgdown);
  614. var sauce = fullsize.src.match(/[^\/]+$/)[0];
  615. if(/%/.test(sauce)) sauce = decodeURIComponent(sauce)
  616. imgdown.setAttribute("download", sauce);
  617. imgdown.setAttribute("href", fullsize.src);
  618. imgdown.click();
  619. keydown = false;
  620. };
  621.  
  622. var link = d.createElement("A");
  623. link.setAttribute("href", data.getAttribute("file_url"));
  624. link.setAttribute("alt", data.getAttribute("id"));
  625. link.appendChild(image);
  626. link.addEventListener("click", function(event) {
  627. event.preventDefault();
  628. }, false);
  629. link.addEventListener("keydown", function(event) {
  630. if(d.body.firstChild.style.getPropertyValue("display") == "none")
  631. return;
  632. if(aFIT.checked && event.keyCode == 37) { // back: listener will be added again
  633. window.removeEventListener("keydown", keylistener, false);
  634. window.removeEventListener("keyup", saveimage, false);
  635. next = this.parentNode.previousElementSibling || this.parentNode.parentNode.lastChild;
  636. next.firstChild.firstChild.click();
  637. next.firstChild.focus();
  638. } else
  639. if(aFIT.checked && event.keyCode == 39) { // next: listener will be added again
  640. window.removeEventListener("keydown", keylistener, false);
  641. window.removeEventListener("keyup", saveimage, false);
  642. next = this.parentNode.nextElementSibling || this.parentNode.parentNode.firstChild;
  643. next.firstChild.firstChild.click();
  644. next.firstChild.focus();
  645. }
  646. }, false);
  647. thumb.setAttribute("class", "thumb");
  648. thumb.style.setProperty("order", i, "");
  649. thumb.appendChild(link);
  650. }
  651. }
  652. }
  653.  
  654. function getContent(xmldoc, newtags) {
  655. if(booru.name == "Danbooru") { // Inject the count where it should be by default...
  656. requestCount = GM_xmlhttpRequest({
  657. method : "GET",
  658. url : window.location.origin + "/counts/posts.xml" + booru.query(encodeURIComponent(newtags)),
  659. headers : {
  660. "Accept" : "application/xml",
  661. "Cookie" : d.cookie
  662. },
  663. overrideMimeType : "application/xml; charset=utf-8",
  664. onload : function(response) {
  665. newxmldoc = new DOMParser().parseFromString(response.responseText, "application/xml");
  666. posts = xmldoc.evaluate("posts", xmldoc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
  667. count = newxmldoc.evaluate("counts/posts", newxmldoc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
  668. if(posts) {
  669. posts.setAttribute("count", count ? count.textContent.trim() : "0");
  670. posts.setAttribute("offset", (page - 1) * images);
  671. }
  672. showContent(xmldoc);
  673. }
  674. });
  675. } else {
  676. showContent(xmldoc);
  677. }
  678. }
  679.  
  680. function showNotes(note, id) {
  681. var offsetx = fullsize.getBoundingClientRect().left + (d.documentElement.scrollLeft || d.body.scrollLeft);
  682. var offsety = fullsize.getBoundingClientRect().top + (d.documentElement.scrollTop || d.body.scrollTop);
  683. var vp_bottom = Math.max(window.innerHeight, innerDisplay.getBoundingClientRect().bottom - innerDisplay.getBoundingClientRect().top);
  684.  
  685. for(var i = 0, ndata = null; ndata = note.snapshotItem(i++); i) {
  686. if(id.match(/[0-9]+$/)[0] != fullsize.getAttribute("id")) continue;
  687. if(d.getElementById("note" + ndata.getAttribute("id"))) continue;
  688.  
  689. var ntop = (parseInt(ndata.getAttribute("y"), 10) + offsety) * sampleRate;
  690. var nleft = (parseInt(ndata.getAttribute("x"), 10) + offsetx) * sampleRate;
  691.  
  692. var noteDiv = d.createElement("DIV");
  693. noteDiv.setAttribute("id", "note" + ndata.getAttribute("id"));
  694. noteDiv.setAttribute("class", "trans");
  695. noteDiv.setAttribute("style", "opacity: 0.4;");
  696. noteDiv.style.setProperty("top", ntop + "px", "");
  697. noteDiv.style.setProperty("left", nleft + "px", "");
  698. noteDiv.style.setProperty("width", ndata.getAttribute("width") * sampleRate + "px", "");
  699. noteDiv.style.setProperty("height", ndata.getAttribute("height") * sampleRate + "px", "");
  700. noteDiv.addEventListener("mouseover", function(event) {
  701. d.getElementById("body" + this.getAttribute("id")).style.setProperty("display", "", "");
  702. }, false);
  703. noteDiv.addEventListener("mouseout", function(event) {
  704. noteclear = setTimeout(function() { d.getElementById("body" + this.getAttribute("id")).style.setProperty("display", "none", ""); }.bind(this), 200);
  705. }, false);
  706. innerDisplay.appendChild(noteDiv);
  707.  
  708. var noteBody = d.createElement("DIV");
  709. noteBody.innerHTML = ndata.getAttribute("body");
  710. noteBody.setAttribute("id", "bodynote" + ndata.getAttribute("id"));
  711. noteBody.setAttribute("class", "trans");
  712. noteBody.setAttribute("style", "color: Black; text-align: left; padding: 4px; z-index: 1" + i + ";");
  713. noteBody.addEventListener("mouseover", function(event) {
  714. clearTimeout(noteclear);
  715. this.style.setProperty("display", "", "");
  716. }, false);
  717. noteBody.addEventListener("mouseout", function(event) {
  718. this.style.setProperty("display", "none", "");
  719. }, false);
  720. innerDisplay.appendChild(noteBody);
  721.  
  722. // this sucks, find another method!
  723. var w = parseInt(ndata.getAttribute("width"), 10) * sampleRate;
  724. var h = parseInt(ndata.getAttribute("height"), 10) * sampleRate;
  725. if(w < h) { w ^= h; h ^= w; w ^= h; } // FUCK YEAH XOR SWAP
  726. while(w / h > ratio) {
  727. w -= ratio;
  728. h += ratio;
  729. }
  730.  
  731. noteBody.style.setProperty("min-width", "-moz-min-content", "");
  732. noteBody.style.setProperty("max-width", w + "px", "");
  733.  
  734. ntop = ntop + 5 + (parseInt(ndata.getAttribute("height"), 10) * sampleRate);
  735. nheight = noteBody.getBoundingClientRect().bottom - noteBody.getBoundingClientRect().top;
  736. if(ntop + nheight > vp_bottom)
  737. noteBody.style.setProperty("top", vp_bottom - nheight + "px", "");
  738. else
  739. noteBody.style.setProperty("top", ntop + "px", "");
  740.  
  741. noteBody.style.setProperty("left", nleft + "px", "");
  742. noteBody.style.setProperty("display", "none", "");
  743. }
  744. }
  745.  
  746. function getNotes(xmldoc, id) {
  747. if(booru.name == "Danbooru") { // Parses the nodes as attributes for each note
  748. notes = xmldoc.evaluate("notes/note/is-active[text() = 'true']/..", xmldoc, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
  749. for(var i = 0, note = null; note = notes.snapshotItem(i++); i) {
  750. while(note.firstChild) {
  751. if(note.firstChild.nodeName != "#text")
  752. note.setAttribute(note.firstChild.nodeName, note.firstChild.textContent);
  753. note.removeChild(note.firstChild);
  754. }
  755. }
  756. showNotes(xmldoc.evaluate("notes/note[@is-active = 'true']", xmldoc, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null), id);
  757. } else {
  758. showNotes(xmldoc.evaluate("notes/note[@is_active = 'true']", xmldoc, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null), id);
  759. }
  760. }
  761.  
  762. function getValue(name, values) {
  763. for(var i = 0; i < sites.length; i++)
  764. if(new RegExp(sites[i].site).test(window.location.hostname)) {
  765. if(eval(values)[i] != "" && !eval(values)[i]) {
  766. values = setValue(name.replace(/all/, ""), values, setDefaults(name, 1));
  767. }
  768. return eval(values)[i];
  769. }
  770. }
  771.  
  772. function setValue(name, values, newvalue) {
  773. for(var i = 0; i < sites.length; i++)
  774. if(new RegExp(sites[i].site).test(window.location.hostname)) {
  775. oldvalue = eval(values);
  776. oldvalue[i] = (newvalue == "" ? "" : newvalue || oldvalue[i]);
  777. GM_setValue(name, JSON.stringify(oldvalue));
  778. return(JSON.stringify(oldvalue));
  779. }
  780. }
  781.  
  782. function setDefaults(name, all) {
  783. var def, string = "[";
  784. for(var i = 0; i < all; i++) {
  785. if(name == "alltags")
  786. def = "\"\"";
  787. if(name == "allpage")
  788. def = "1";
  789. if(name == "allimages")
  790. def = "20";
  791. if(name == "allrating")
  792. def = "\"s\"";
  793. string += (def) + (i < sites.length - 1 ? ", " : "]");
  794. }
  795. return (all > 1 ? string : eval(def));
  796. }