Advertisement
Guest User

Updated/Fixed boorutagparser

a guest
Jul 21st, 2016
252
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name         Booru Tag Parser
  3. // @namespace    http://average.website
  4. // @version      1.1.2derpibooru
  5. // @description  Copy current post tags and rating on boorus and illustration2vec in to the clipboard for easy import in to a program or another booru.
  6. // @author       William Moodhe
  7. // @downloadURL  https://github.com/JetBoom/boorutagparser/raw/master/boorutagparser.user.js
  8. // @updateURL    https://github.com/JetBoom/boorutagparser/raw/master/boorutagparser.user.js
  9.  
  10. // Illustration2Vec
  11. // @include      *demo.illustration2vec.net*
  12.  
  13. // Catch-all for boorus
  14. // @include      *booru*/post*
  15. // @include      *booru*/*?page=post*
  16. // @include      *booru*/?page=post
  17.  
  18. // Boorus with weird names
  19. // @include      *rule34.xxx/index.php?page=post*
  20. // @include      *chan.sankakucomplex.com/post/show/*
  21. // @include      *chan.sankakucomplex.com/?tags=*
  22. // @include      *idol.sankakucomplex.com/post/show/*
  23. // @include      *idol.sankakucomplex.com/?tags=*
  24. // @include      *behoimi.org/post/show/*
  25. // @include      *e621.net/post/show/*
  26. // @include      *konachan.com/post/*
  27. // @include      *konachan.net/post/*
  28. // @include      *shimmie.katawa-shoujo.com/post/*
  29. // @include      *rule34.paheal.net/post/*
  30. // @include      *rule34hentai.net/post/*
  31. // @include      *tbib.org/index.php?page=post*
  32. // @include      *yande.re/post/*
  33. // @include      /^https?://derpiboo\.ru/[1-9]+/
  34. // @include      /^https?://derpibooru\.org/[1-9]+/
  35. // @include      /^https?://trixiebooru\.org/[1-9]+/
  36.  
  37. // nhentai
  38. // @include      *nhentai.net/g/*
  39.  
  40. // @run-at       document-end
  41. // @grant        GM_setClipboard
  42. // @grant        GM_setValue
  43. // @grant        GM_getValue
  44. // @grant        GM_xmlhttpRequest
  45.  
  46. // ==/UserScript==
  47. /* jshint -W097 */
  48. 'use strict';
  49.  
  50. ///////
  51.  
  52. var copy_key_code = GM_getValue('copy_key_code', 221); // ] key
  53. var download_key_code = GM_getValue('download_key_code', 220); // \ key
  54. var copy_sound = GM_getValue('copy_sound', 'http://heavy.noxiousnet.com/boorucopy.ogg');
  55. var iv2_confidence_rating = GM_getValue('iv2_confidence_rating', 20.0);
  56. var attach_explicit = GM_getValue('attach_explicit', true);
  57. var attach_gid = GM_getValue('attach_gid', true);
  58. var div_top = GM_getValue('div_top', false);
  59.  
  60.  
  61. ///////
  62.  
  63. var tags_selector = 'h5, b';
  64. var button_style = 'font:11px monospace;font-weight:0;border:1px solid black;background:#eee;color:#000;display:block;width:90%;margin:2px auto;z-index:9999;';
  65. var div_style = 'opacity:0.2;position:fixed;width:240px;right:2px;top:2px;text-align:center;font:11px monospace;font-weight:0;border:1px solid black;background:rgba(255,255,255,0.8);z-index:9999;';
  66.  
  67. function replaceAll(str, originalstr, newstr)
  68. {
  69.     return str.split(originalstr).join(newstr);
  70. }
  71.  
  72. function insertTags(tags, selector, prefix, stripns)
  73. {
  74.     if (typeof stripns === "undefined") {
  75.         stripns = false;
  76.     }
  77.  
  78.     var elements = document.querySelectorAll(selector);
  79.  
  80.     for (var i=0; i < elements.length; i++)
  81.     {
  82.         var element = elements[i];
  83.         var text = element.innerHTML;
  84.         if (text.length > 1) // Don't copy - + or ?
  85.         {
  86.             text = replaceAll(text, '_', ' ');
  87.             text = replaceAll(text, '&gt;', '>');
  88.             text = replaceAll(text, '&lt;', '<');
  89.  
  90.             if (stripns) {
  91.                 text = text.match(".*?:(.*)")[1];
  92.             }
  93.  
  94.             tags[tags.length] = prefix+text;
  95.         }
  96.     }
  97. }
  98.  
  99. function insertRating(tags, selector)
  100. {
  101.     var elements = document.querySelectorAll(selector);
  102.  
  103.     for (var i=0; i < elements.length; i++)
  104.     {
  105.         var element = elements[i];
  106.         var text = element.innerHTML;
  107.         text = replaceAll(text.toLowerCase().trim(), ' ', '');
  108.  
  109.         if (text.indexOf('rating:explicit') >= 0)
  110.         {
  111.             tags[tags.length] = 'rating:explicit';
  112.             break;
  113.         }
  114.         else if (text.indexOf('rating:questionable') >= 0)
  115.         {
  116.             tags[tags.length] = 'rating:questionable';
  117.             break;
  118.         }
  119.         else if (text.indexOf('rating:safe') >= 0)
  120.         {
  121.             tags[tags.length] = 'rating:safe';
  122.             break;
  123.         }
  124.     }
  125. }
  126.  
  127. function copyNHentaiTags(noRating, callback)
  128. {
  129.     // nhentai has a json output we can use.
  130.     // Which is nice because the tags are available even if viewing an individual file.
  131.  
  132.     var id = window.location.href.match('/g/(\\d+)/*')[1];
  133.     if (!id)
  134.         return;
  135.  
  136.     id = Number(id);
  137.  
  138.     fetch('http://nhentai.net/g/' + id + '/json').then(function(response) {
  139.         return response.json();
  140.     }).then(function(json) {
  141.         var tags = [];
  142.  
  143.         if (json.tags)
  144.         {
  145.             for (var i=0; i < json.tags.length; i++)
  146.             {
  147.                 var tagtype = json.tags[i][1];
  148.                 var tag = json.tags[i][2];
  149.  
  150.                 // maintain schema consistency
  151.                 if (tagtype == 'group')
  152.                     tagtype = 'studio';
  153.                 else if (tagtype == 'parody')
  154.                     tagtype = 'series';
  155.                 else if (tagtype == 'artist')
  156.                     tagtype = 'creator';
  157.  
  158.                 if (tagtype != 'tag')
  159.                     tag = tagtype + ':' + tag;
  160.  
  161.                 tags[tags.length] = tag;
  162.             }
  163.         }
  164.  
  165.         if (attach_explicit)
  166.             tags[tags.length] = 'rating:explicit';
  167.  
  168.         if (attach_gid && json.id)
  169.             tags[tags.length] = 'gallery:' + json.id;
  170.  
  171.         copyTagsToClipboard(tags);
  172.  
  173.         if (callback)
  174.             callback(tags);
  175.     }).catch(function(err) {
  176.         console.log('couldn\'t get json!');
  177.     });
  178. }
  179.  
  180. function copyBooruTags(noRating)
  181. {
  182.     var tags = [];
  183.     // Instead of having a list of boorus and their tags and tag structures I just make a big catch-all.
  184.  
  185.     // danbooru-like
  186.     insertTags(tags, '#tag-list li.category-3 > a.search-tag', 'series:');
  187.     insertTags(tags, '#tag-list li.category-1 > a.search-tag', 'creator:');
  188.     insertTags(tags, '#tag-list li.category-4 > a.search-tag', 'character:');
  189.     insertTags(tags, '#tag-list li.category-0 > a.search-tag', '');
  190.  
  191.     // lolibooru-like
  192.     insertTags(tags, 'li.tag-type-copyright > a', 'series:');
  193.     insertTags(tags, 'li.tag-type-author > a', 'creator:');
  194.     insertTags(tags, 'li.tag-type-artist > a', 'creator:');
  195.     insertTags(tags, 'li.tag-type-character > a', 'character:');
  196.     insertTags(tags, 'li.tag-type-model > a', 'model:');
  197.     insertTags(tags, 'li.tag-type-general > a', '');
  198.     insertTags(tags, 'li.tag-type-studio > a', 'studio:');
  199.     insertTags(tags, 'li.tag-type-circle > a', 'studio:');
  200.     insertTags(tags, 'li.tag-type-medium > a', 'medium:');
  201.     insertTags(tags, 'li.tag-type-style > a', 'medium:');
  202.     insertTags(tags, 'li.tag-type-meta > a', 'meta:');
  203.     insertTags(tags, 'li.tag-type-species > a', 'species:');
  204.     insertTags(tags, 'li.tag-type-faults > a', 'fault:');
  205.  
  206.     // derpibooru-like
  207.     insertTags(tags, '.tag-list .tag.tag-ns-artist > a', 'creator:', true);
  208.     insertTags(tags, '.tag-list .tag.tag-ns-oc > a', 'character:', true);
  209.     insertTags(tags, '.tag-list .tag.tag-system > a', 'rating:');
  210.     insertTags(tags, '.tag-list [class="dropdown tag"] > a', ''); // generic tags on derpibooru do not have a "namespace" class of their own, this seems to be the best way to match generic tags
  211.     insertTags(tags, '.tag-list [class="dropdown tag tag-user-watched"] > a', ''); //also grabs tags users have watched, the generic tag code doesn't grab these
  212.     insertTags(tags, '.tag-list [class="dropdown tag tag-user-hidden"] > a', ''); //also grabs tags users have hidden, the generic tag code doesn't grab these
  213.     insertTags(tags, '.tag-list [class="dropdown tag tag-user-spoilered"] > a', ''); //also grabs tags users have set to spoiler, the generic tag code doesn't grab these
  214.    
  215.     // booru.org-like
  216.     insertTags(tags, '#tag_list li a', '');
  217.  
  218.     // paheal-like
  219.     insertTags(tags, 'a.tag_name', '');
  220.  
  221.     if (!noRating)
  222.     {
  223.         // danbooru-like
  224.         insertRating(tags, '#post-information > ul li');
  225.  
  226.         // lolibooru-like
  227.         insertRating(tags, '#stats > ul li');
  228.  
  229.         // booru.org-like
  230.         insertRating(tags, '#tag_list ul');
  231.     }
  232.  
  233.     copyTagsToClipboard(tags);
  234.  
  235.     return tags;
  236. }
  237.  
  238. function insertI2VTags(tags, selector, prefix, confidenceRequired)
  239. {
  240.     var elements = document.querySelectorAll(selector);
  241.     for (var i=1; i < elements.length; i++)
  242.     {
  243.         var element = elements[i];
  244.  
  245.         if (confidenceRequired > 0)
  246.         {
  247.             var confidence = element.children[3].children[0].innerHTML;
  248.             confidence = confidence.substr(0, confidence.length - 1);
  249.             confidence = Number(confidence);
  250.  
  251.             if (confidence < confidenceRequired)
  252.                 continue;
  253.         }
  254.  
  255.         var tag = element.children[1].innerHTML;
  256.  
  257.         tag = replaceAll(tag, '_', ' ');
  258.  
  259.         if (prefix)
  260.             tag = prefix + tag;
  261.  
  262.         tags[tags.length] = tag;
  263.  
  264.         if (prefix == 'rating') // only add one rating
  265.             break;
  266.     }
  267. }
  268.  
  269. function copyI2VTags(confidenceRequired, noGeneral, noRating)
  270. {
  271.     var tags = [];
  272.  
  273.     insertI2VTags(tags, 'table#copyright_root tr', 'series:', confidenceRequired);
  274.     insertI2VTags(tags, 'table#character_root tr', 'character:', confidenceRequired);
  275.  
  276.     if (!noGeneral)
  277.         insertI2VTags(tags, 'table#general_root tr', '', confidenceRequired);
  278.  
  279.     if (!noRating)
  280.         insertI2VTags(tags, 'table#rating_root tr', 'rating:', confidenceRequired);
  281.  
  282.     copyTagsToClipboard(tags);
  283.  
  284.     return tags;
  285. }
  286.  
  287. function doCopyAll(callback)
  288. {
  289.     control.style.opacity = '1';
  290.  
  291.     if (window.location.href.indexOf('nhentai.net') >= 0)
  292.         copyNHentaiTags(null, callback);
  293.     else if (window.location.href.indexOf('illustration2vec.net') >= 0)
  294.         callback(copyI2VTags(iv2_confidence_rating, false));
  295.     else
  296.         callback(copyBooruTags());
  297. }
  298.  
  299. function copyTagsToClipboard(tags)
  300. {
  301.     GM_setClipboard(tags.join('\n'));
  302.  
  303.     var buttontext = '';
  304.  
  305.     if (tags.length > 0)
  306.     {
  307.         playCopySound();
  308.         buttontext = 'copied ' +  tags.length +' tag(s)';
  309.     }
  310.     else
  311.         buttontext = 'nothing to copy!';
  312.  
  313.     var button = document.querySelector('button#copytagsbutton');
  314.     if (button)
  315.     {
  316.         button.innerHTML = buttontext;
  317.         setTimeout(function(){ button.innerHTML = 'copy tags'; }, 3000);
  318.     }
  319. }
  320.  
  321. function doOptions()
  322. {
  323.     optionsArea.style.display = optionsArea.style.display == 'none' ? 'block' : 'none';
  324. }
  325.  
  326. function makeDownloadRequest(href, tags)
  327. {
  328.     if (!tags)
  329.         tags = [];
  330.  
  331.     GM_xmlhttpRequest({
  332.         'method':'POST',
  333.         'url':'http://localhost:14007/download?' + href,
  334.         'data':tags.join(','),
  335.         'anonymous':true,
  336.         'timeout':12500,
  337.         'onerror':function() { alert('Error downloading to your local server. Is boorutagparser-server running?\nGet it at github.com/JetBoom/boorutagparser-server if you do not have it.'); }
  338.     });
  339. }
  340.  
  341. function doDownload()
  342. {
  343.     var a = document.querySelector('a#highres, a[itemprop="contentSize"], a.original-file-unchanged, li > a[href*="/images/"], section#image-container > a > img, img#image, img[src*="/_images/"], a[href*="/img/download/"]');
  344.     if (!a)
  345.         return;
  346.  
  347.     var href = a.src || a.href;
  348.  
  349.     doCopyAll(function(tags) { makeDownloadRequest(href, tags); } );
  350. }
  351.  
  352. function doc_keyUp(e)
  353. {
  354.     if (e.keyCode == copy_key_code)
  355.         doCopyAll();
  356.     else if (e.keyCode == download_key_code)
  357.         doDownload();
  358. }
  359. document.addEventListener('keyup', doc_keyUp, false);
  360.  
  361. var elements = document.querySelectorAll(tags_selector);
  362. for (var i=0; i < elements.length; i++)
  363. {
  364.     var element = elements[i];
  365.     if (element.innerHTML == 'Tags')
  366.     {
  367.         element.onclick = copyBooruTags;
  368.         break;
  369.     }
  370. }
  371.  
  372. if (copy_sound.length > 0)
  373. {
  374.     var audio = document.createElement("audio");
  375.     audio.src = copy_sound;
  376.     audio.preload = false;
  377. }
  378.  
  379. function playCopySound()
  380. {
  381.     if (audio && copy_sound.length > 0)
  382.         audio.play();
  383. }
  384.  
  385. function doChangeConfidence(e)
  386. {
  387.     iv2_confidence_rating = Number(optionForConfidence.value);
  388.     captionForConfidence.innerHTML = 'iv2 min confidence: ' + iv2_confidence_rating + '%';
  389.     GM_setValue('iv2_confidence_rating', iv2_confidence_rating);
  390. }
  391.  
  392. function doChangeCopySound(e)
  393. {
  394.     copy_sound = String(optionForCopySound.value);
  395.     GM_setValue('copy_sound', copy_sound);
  396.  
  397.     if (audio)
  398.         audio.src = copy_sound;
  399. }
  400.  
  401. function doChangeAttachExplicit(e)
  402. {
  403.     attach_explicit = optionForAttachExplicit.checked;
  404.     GM_setValue('attach_explicit', attach_explicit);
  405. }
  406.  
  407. function doChangeAttachGID(e)
  408. {
  409.     attach_gid = optionForAttachGID.checked;
  410.     GM_setValue('attach_gid', attach_gid);
  411. }
  412.  
  413. function doChangeDivTop(e)
  414. {
  415.     div_top = optionForDivTop.checked;
  416.     GM_setValue('div_top', div_top);
  417.  
  418.     if (div_top)
  419.     {
  420.         control.style.top = '2px';
  421.         control.style.bottom = '';
  422.     }
  423.     else
  424.     {
  425.         control.style.top = '';
  426.         control.style.bottom = '2px';
  427.     }
  428. }
  429.  
  430. var control = document.createElement('div');
  431. control.id = 'boorutagparser';
  432. control.setAttribute('style', div_style);
  433. control.onmouseenter = function(e) { this.style.opacity = 1; };
  434. control.onmouseleave = function(e) { this.style.opacity = 0.2; };
  435. document.body.appendChild(control);
  436.  
  437. var copyButton = document.createElement('button');
  438. copyButton.innerHTML = 'copy tags';
  439. copyButton.id = 'copytagsbutton';
  440. copyButton.setAttribute('style', button_style);
  441. copyButton.onclick = doCopyAll;
  442. control.appendChild(copyButton);
  443.  
  444. var optionsButton = document.createElement('button');
  445. optionsButton.innerHTML = 'options';
  446. optionsButton.id = 'optionsbutton';
  447. optionsButton.setAttribute('style', button_style);
  448. optionsButton.onclick = doOptions;
  449. control.appendChild(optionsButton);
  450.  
  451. var downloadButton = document.createElement('button');
  452. downloadButton.innerHTML = 'download with tags';
  453. downloadButton.id = 'downloadbutton';
  454. downloadButton.setAttribute('style', button_style);
  455. downloadButton.onclick = doDownload;
  456. control.appendChild(downloadButton);
  457.  
  458. var optionsArea = document.createElement('div');
  459. optionsArea.id = 'optionsarea';
  460. optionsArea.setAttribute('style', 'display:none;');
  461. control.appendChild(optionsArea);
  462.  
  463. if (window.location.href.indexOf('illustration2vec.net') >= 0)
  464. {
  465.     var captionForConfidence = document.createElement('span');
  466.     captionForConfidence.id = 'captionconfidence';
  467.     captionForConfidence.innerHTML = 'iv2 min confidence: ' + iv2_confidence_rating + '%';
  468.     optionsArea.appendChild(captionForConfidence);
  469.  
  470.     var optionForConfidence = document.createElement('input');
  471.     optionForConfidence.id = 'optionsconfidence';
  472.     optionForConfidence.setAttribute('type', 'range');
  473.     optionForConfidence.setAttribute('value', iv2_confidence_rating);
  474.     optionForConfidence.setAttribute('min', 0);
  475.     optionForConfidence.setAttribute('max', 100);
  476.     optionForConfidence.onchange = doChangeConfidence;
  477.     optionsArea.appendChild(optionForConfidence);
  478. }
  479.  
  480. if (window.location.href.indexOf('nhentai.net/g/') >= 0)
  481. {
  482.     var optionForAttachExplicit = document.createElement('input');
  483.     optionForAttachExplicit.setAttribute('type', 'checkbox');
  484.     optionForAttachExplicit.checked = attach_explicit;
  485.     optionForAttachExplicit.onchange = doChangeAttachExplicit;
  486.     optionsArea.appendChild(optionForAttachExplicit);
  487.  
  488.     var captionForAttachExplicit = document.createElement('span');
  489.     captionForAttachExplicit.innerHTML = 'add rating:explicit<br>';
  490.     optionsArea.appendChild(captionForAttachExplicit);
  491.  
  492.     var optionForAttachGID = document.createElement('input');
  493.     optionForAttachGID.setAttribute('type', 'checkbox');
  494.     optionForAttachGID.checked = attach_gid;
  495.     optionForAttachGID.onchange = doChangeAttachGID;
  496.     optionsArea.appendChild(optionForAttachGID);
  497.  
  498.     var captionForAttachGID = document.createElement('span');
  499.     captionForAttachGID.innerHTML = 'add gallery:id#<br>';
  500.     optionsArea.appendChild(captionForAttachGID);
  501. }
  502.  
  503. var captionForCopySound = document.createElement('span');
  504. captionForCopySound.id = 'captioncopysound';
  505. captionForCopySound.innerHTML = 'copy sound url';
  506. optionsArea.appendChild(captionForCopySound);
  507.  
  508. var optionForCopySound = document.createElement('input');
  509. optionForCopySound.id = 'optionssound';
  510. optionForCopySound.setAttribute('value', copy_sound);
  511. optionForCopySound.setAttribute('style', 'display:block;font-size:10px;width:90%;margin:1px auto;');
  512. optionForCopySound.onchange = doChangeCopySound;
  513. optionsArea.appendChild(optionForCopySound);
  514.  
  515. var optionForDivTop = document.createElement('input');
  516. optionForDivTop.setAttribute('type', 'checkbox');
  517. optionForDivTop.checked = div_top;
  518. optionForDivTop.onchange = doChangeDivTop;
  519. optionsArea.appendChild(optionForDivTop);
  520.  
  521. var captionForDivTop = document.createElement('span');
  522. captionForDivTop.innerHTML = 'attach to top of page<br>';
  523. optionsArea.appendChild(captionForDivTop);
  524.  
  525. var version = document.createElement('div');
  526. version.innerHTML = GM_info.script.version;
  527. version.setAttribute('style', 'font-size:8px;');
  528. optionsArea.appendChild(version);
  529.  
  530. doChangeDivTop();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement