EH – Page Scrobbler

Visualize GID and add the ability to easily jump or scrobble

  1. // ==UserScript==
  2. // @name EH – Page Scrobbler
  3. // @namespace fabulous.cupcake.jp.net
  4. // @version 2022.11.03.1
  5. // @description Visualize GID and add the ability to easily jump or scrobble
  6. // @author FabulousCupcake
  7. // @license MIT
  8. // @runat document-start
  9. // @include /https?:\/\/(e-|ex)hentai\.org\/.*/
  10. // ==/UserScript==
  11.  
  12. const stylesheet = `
  13.  
  14. .search-scrobbler {
  15. width: 800px;
  16. outline: 1px cyan dashed;
  17. margin: 0 auto;
  18. padding: 20px 0 0 0;
  19. display: flex;
  20. flex-direction: column;
  21. gap: 0.5em;
  22. }
  23.  
  24. .search-scrobbler .bar {
  25. display: block;
  26. width: 800px;
  27. height: 25px;
  28. border: 1px solid red;
  29. box-sizing: border-box;
  30. position: relative;
  31. }
  32.  
  33. .search-scrobbler .bar .bar-cursor {
  34. width: 1px;
  35. height: 100%;
  36. background: #0f0;
  37. }
  38.  
  39. .search-scrobbler .bar-wrapper {
  40. display: flex;
  41. flex-direction: column;
  42. }
  43.  
  44. .search-scrobbler .bar-labels {
  45. width: 100%;
  46. display: flex;
  47. flex-direction: row;
  48. justify-content: space-between;
  49. }
  50.  
  51. .search-scrobbler .bar-hover {
  52. display: block;
  53. width: 1px;
  54. height: 100%;
  55. background: #f0f;
  56. position: absolute;
  57. }
  58.  
  59. .search-scrobbler .bar-hovertext {
  60. position: absolute;
  61. outline: 1px solid #f0f;
  62. top: -1.5em;
  63. }
  64.  
  65. .search-scrobbler,
  66. .search-scrobbler * {
  67. outline: 0px none !important;
  68. }
  69.  
  70. `;
  71.  
  72. const injectStylesheet = () => {
  73. const stylesheetEl = document.createElement("style");
  74. stylesheetEl.innerHTML = stylesheet;
  75. document.body.appendChild(stylesheetEl);
  76. }
  77.  
  78. const hasGalleryListTable = () => {
  79. return !!document.querySelector(".itg.gltm");
  80. }
  81.  
  82. const tryUpdateKnownMaxGID = GID => {
  83. const url = new URL(location.href);
  84. if (url.pathname !== "/") return;
  85. if (url.search !== "") return;
  86.  
  87. const maxGID = document.querySelector(".itg tr:nth-child(2) .glname a").href.match(/\/(\d+)\//)?.[1];
  88. localStorage.setItem("EHPS-maxGID", maxGID);
  89. }
  90.  
  91. const addPageScrobbler = () => {
  92. const insertInitialElement = () => {
  93. const hook = document.querySelector(".searchnav");
  94.  
  95. const maxGID = localStorage.getItem("EHPS-maxGID");
  96. let cursorGID = new URL(location.href).searchParams.get("next");
  97. if (!cursorGID) {
  98. // No searchparams, use last row in page
  99. cursorGID = document.querySelector(".itg tr:last-child .glname a").href.match(/\/(\d+)\//)?.[1];
  100. }
  101.  
  102. const cursorLeftMargin = cursorGID / maxGID * 100;
  103.  
  104. const el = `
  105. <div class="search-scrobbler">
  106. <div class="bar-wrapper bar-full">
  107. <div class="bar">
  108. <div class="bar-cursor" style="margin-left: ${cursorLeftMargin}%">${cursorGID}</div>
  109. </div>
  110. <div class="bar-labels">
  111. <div class="bar-min">1</div>
  112. <div class="bar-max">${maxGID}</div>
  113. </div>
  114. </div>
  115. </div>`;
  116. hook.insertAdjacentHTML("beforebegin", el);
  117. }
  118.  
  119. const addEventListeners = () => {
  120. const addHoverElement = offset => {
  121. /* This may happen because bar-hover kinda blocking and screws up the offsetX value */
  122. /* We need it for the link though */
  123. if (offset <2) return;
  124.  
  125. document.querySelector(".bar-hover")?.remove();
  126.  
  127. const maxGID = localStorage.getItem("EHPS-maxGID");
  128. const width = 800;
  129. const hoverGID = (offset / 800 * maxGID).toFixed(0);
  130.  
  131. const url = new URL(location.href);
  132. url.searchParams.set("next", hoverGID);
  133.  
  134. const hook = document.querySelector(".bar-full .bar");
  135. const el = `
  136. <a class="bar-hover" href="${url}" style="left: ${offset}px;">
  137. <div class="bar-hovertext">${hoverGID}</div>
  138. </a>`;
  139. hook.insertAdjacentHTML("afterbegin", el);
  140. }
  141.  
  142. const handler = e => {
  143. addHoverElement(e.offsetX);
  144. }
  145.  
  146. const el = document.querySelector(".bar-full .bar");
  147. el.addEventListener("mousemove", handler);
  148. }
  149.  
  150. insertInitialElement();
  151. addEventListeners();
  152. }
  153.  
  154. const main = () => {
  155. if (!hasGalleryListTable()) return;
  156. tryUpdateKnownMaxGID();
  157. injectStylesheet();
  158. addPageScrobbler();
  159. }
  160.  
  161. main();