EH Gallery Quick Tag Voting

Adds upvote and downvote button on the left and right sides of tags in EH Gallery to allow faster and easier tag voting.

  1. // ==UserScript==
  2. // @name EH Gallery Quick Tag Voting
  3. // @author FabulousCupcake
  4. // @namespace http://fabulous.cupcake.jp.net/
  5. // @description Adds upvote and downvote button on the left and right sides of tags in EH Gallery to allow faster and easier tag voting.
  6. // @include /^https?://(ex|(g\.)?e-)hentai\.org/g/\d+?/\w{10}/?/
  7. // @version r5
  8. // @grant GM_addStyle
  9. // @grant unsafeWindow
  10. // ==/UserScript==
  11.  
  12. // Config
  13. // ----------
  14. const config = {
  15. "debug" : false, // Enable debugging?
  16. "selective_tags": false, // Affect only tags w/ dashed borders ( those with <100 power and still yield tagging points )
  17. "invert_buttons": false, // Invert buttons ( [+|tag|-] by default, [-|tag|+] if inverted )
  18. "short_buttons": true, // Shorter buttons ( [+|tag|-] ,instead of [+++|---] overlay )
  19. "upvote_only": false, // Upvote only ( [+|tag ] )
  20. };
  21.  
  22.  
  23. // Stylesheet
  24. // ----------
  25. var qt_button_width_default = (config.short_buttons ? "18px" : "35%");
  26. var qt_button_width_elongated = (config.short_buttons ? "35%" : "68%");
  27. var stylesheet = `
  28. .gt, .gtl {
  29. position: relative;
  30. }
  31.  
  32. .qtvote {
  33. display: block;
  34. width: ${qt_button_width_default};
  35. min-width: 18px;
  36. height: 18px;
  37. float: left;
  38. position: absolute;
  39. top: -1px;
  40. cursor: pointer;
  41. opacity: 0.2;
  42. transition: all 200ms ease;
  43. border: inherit;
  44. box-sizing: border-box;
  45. }
  46.  
  47. .qtvote:hover {
  48. width: ${qt_button_width_elongated} !important;
  49. opacity: 0.9;
  50. }
  51.  
  52. .qtvote.up { background: rgba(0,200,0,0.6); }
  53. .qtvote.down { background: rgba(255,0,0,0.6); }
  54.  
  55. .qtvote.left { left: -1px; border-radius: 5px 0 0 5px; border-right: none; }
  56. .qtvote.right { right: -1px; border-radius: 0 5px 5px 0; border-left: none; }
  57.  
  58. .tup ~ .qtvote.up, .tdn ~ .qtvote.down { display: none; }
  59. .tup ~ .qtvote.down, .tdn ~ .qtvote.up { width: ${qt_button_width_elongated}; }
  60.  
  61. .qtvote.hide { display: none; }
  62. .tup ~ .qtvote.hide, .tdn ~ qtvote.hide { display: block; }
  63.  
  64. `;
  65.  
  66.  
  67. // Utilities
  68. // ----------
  69. function dlog(msg) {
  70. if ( config.debug ) {
  71. console.log(`EHGQT: ${msg}`);
  72. }
  73. }
  74.  
  75.  
  76. // Core
  77. // ----------
  78.  
  79. function insertElements() {
  80. // Fetch to-be-inserted elements
  81. var filter = '.gtl' + (config.selective_tags ? '' : ', .gt');
  82. var tags = document.querySelectorAll(filter);
  83.  
  84. // Build insert material
  85. var leftvote = ( config.invert_buttons ? "down" : "up" );
  86. var rightvote = ( config.invert_buttons ? "up" : "down" );
  87. if ( config.upvote_only ) {
  88. config.invert_buttons ? leftvote += ' hide' : rightvote += ' hide';
  89. }
  90. var elleft = `<div class="qtvote left ${leftvote}"></div>`;
  91. var elright = `<div class="qtvote right ${rightvote}"></div>`;
  92.  
  93.  
  94. // Insert the elements to the queried tags
  95. for( var i=0; i<tags.length; i+=1 ) {
  96. tags[i].insertAdjacentHTML('beforeend' , elleft);
  97. tags[i].insertAdjacentHTML('beforeend' , elright);
  98. }
  99.  
  100. dlog('insertElements() executed.');
  101. }
  102.  
  103. function insertStylesheet() {
  104. var stylesheetEl = document.createElement('style');
  105. stylesheetEl.innerHTML = stylesheet;
  106. document.body.appendChild(stylesheetEl);
  107. }
  108.  
  109. function hookEvents() {
  110. var voteups = document.querySelectorAll('.qtvote.up');
  111. var votedowns = document.querySelectorAll('.qtvote.down');
  112.  
  113. for(var i=0; i<voteups.length; i+=1) {
  114. voteups[i].addEventListener("click", quickVote);
  115. }
  116.  
  117. for(var i=0; i<votedowns.length; i+=1) {
  118. votedowns[i].addEventListener("click", quickVote);
  119. }
  120.  
  121. dlog('hookEvents() executed.');
  122. }
  123.  
  124. function quickVote(e) {
  125. // Extract tagname and vote value
  126. var tag = e.target.parentElement.id.substr(3);
  127. var vote = ( e.target.classList.toString().match('up') ? 1 : -1 );
  128.  
  129. // Replace "_" with " " in tag
  130. tag = tag.replace(/_/g, ' ');
  131.  
  132. // Send the vote!
  133. unsafeWindow.send_vote(tag, vote);
  134. dlog("quickVote() executed");
  135. dlog(`tag = ${tag}`);
  136. dlog(`vote = ${vote}`);
  137. }
  138.  
  139. function main() {
  140. insertStylesheet();
  141. insertElements();
  142. hookEvents();
  143. dlog("main() executed");
  144. }
  145.  
  146. function init() {
  147. // Call main
  148. main();
  149.  
  150. // Create a Mutation Observer, since the taglists are reloaded once the votes are sent
  151. var observer = new MutationObserver(main);
  152. var target = document.getElementById('taglist');
  153. var config = { childList: true };
  154. observer.observe(target, config);
  155. dlog("MutationObserver is now observing #taglist");
  156. }
  157.  
  158.  
  159. // Init
  160. // ----------
  161. init();