Manhuagui helper

Improve Manhuagui

  1. // ==UserScript==
  2. // @name Manhuagui helper
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.2
  5. // @description Improve Manhuagui
  6. // @author You
  7. // @match https://www.manhuagui.com/update/*
  8. // @match https://www.manhuagui.com/comic/*
  9. // @icon https://www.google.com/s2/favicons?sz=64&domain=manhuagui.com
  10. // @grant none
  11. // @license MIT
  12. // ==/UserScript==
  13.  
  14. (function() {
  15. 'use strict';
  16.  
  17. const appState = loadAppState();
  18. const appStateWatchers = [];
  19. var appStateIsDirty = false;
  20. var dirtyAppStateKeys = {};
  21.  
  22. var scrollIsDirty = false;
  23.  
  24. function loadAppState() {
  25. try {
  26. const value = localStorage.getItem('appState');
  27. return value ? JSON.parse(value) : {};
  28. } catch (e) {
  29. console.error(e);
  30. return {};
  31. }
  32. }
  33.  
  34. function saveAppState() {
  35. if (!appStateIsDirty) return;
  36.  
  37. localStorage.setItem('appState', JSON.stringify(appState));
  38. appStateIsDirty = false;
  39. }
  40.  
  41. function getAppState(key) {
  42. return Array.isArray(key) ? key.map(k => getAppState(k)) : appState[key];
  43. }
  44.  
  45. function setAppState(key, value) {
  46. if (value !== undefined) {
  47. appState[key] = value;
  48. } else {
  49. delete appState[key];
  50. }
  51.  
  52. appStateIsDirty = true;
  53. requestAnimationFrame(() => saveAppState());
  54.  
  55. dirtyAppStateKeys[key] = true;
  56. requestAnimationFrame(() => notifyAppStateWatchers());
  57. }
  58.  
  59. function watchAppState(key, callback) {
  60. appStateWatchers.push({ key, callback });
  61. callback(getAppState(key));
  62. }
  63.  
  64. function notifyAppStateWatchers() {
  65. if (!Object.entries(dirtyAppStateKeys).length) return;
  66.  
  67. for (const watcher of appStateWatchers) {
  68. const isDirty = Array.isArray(watcher.key) ? watcher.key.some(k => dirtyAppStateKeys[k]) : dirtyAppStateKeys[watcher.key];
  69. if (!isDirty) continue;
  70.  
  71. watcher.callback(getAppState(watcher.key));
  72. }
  73.  
  74. dirtyAppStateKeys = {};
  75. }
  76.  
  77. function notifyScroll() {
  78. if (!scrollIsDirty) return;
  79.  
  80. window.dispatchEvent(new Event('scroll'));
  81. scrollIsDirty = false;
  82. }
  83.  
  84. function scheduleNotifyScroll() {
  85. scrollIsDirty = true;
  86. requestAnimationFrame(() => notifyScroll());
  87. }
  88.  
  89. function createStyle() {
  90. const style = document.createElement('style');
  91. style.textContent = `
  92. .mhgh-item-menu button {
  93. padding: 0px 2px;
  94. }
  95.  
  96. .mhgh-global-menu {
  97. padding: 2px;
  98. background: #fff;
  99. }
  100.  
  101. .mhgh-global-menu button {
  102. padding: 0px 2px;
  103. }
  104. `;
  105. document.head.appendChild(style);
  106. }
  107.  
  108. function createShowButton(container, title) {
  109. const button = document.createElement('button');
  110. button.type = 'button';
  111. button.textContent = 'Show';
  112. button.onclick = () => setAppState(`item.${title}.state`, undefined);
  113. container.appendChild(button);
  114.  
  115. watchAppState(`item.${title}.state`, state => {
  116. button.style.display = state == 'hidden' ? '' : 'none';
  117. });
  118. }
  119.  
  120. function createHideButton(container, title) {
  121. const button = document.createElement('button');
  122. button.type = 'button';
  123. button.textContent = 'Hide';
  124. button.onclick = () => setAppState(`item.${title}.state`, 'hidden');
  125. container.appendChild(button);
  126.  
  127. watchAppState(`item.${title}.state`, state => {
  128. button.style.display = state === undefined || state == 'like' ? '' : 'none';
  129. });
  130. }
  131.  
  132. function createLikeButton(container, title) {
  133. const button = document.createElement('button');
  134. button.type = 'button';
  135. button.textContent = 'Like';
  136. button.onclick = () => setAppState(`item.${title}.state`, 'like');
  137. container.appendChild(button);
  138.  
  139. watchAppState(`item.${title}.state`, state => {
  140. button.style.display = state != 'like' ? '' : 'none';
  141. });
  142. }
  143.  
  144. function createItemMenu(container, title) {
  145. const div = document.createElement('div');
  146. div.className = 'mhgh-item-menu';
  147. div.style.position = 'absolute';
  148. div.style.top = 0;
  149. div.style.right = '26px';
  150. div.style.zIndex = 10;
  151. container.appendChild(div);
  152.  
  153. createShowButton(div, title);
  154. createHideButton(div, title);
  155. createLikeButton(div, title);
  156. }
  157.  
  158. function createItem(container) {
  159. const title = container.querySelector('a.cover').getAttribute('title');
  160.  
  161. container.style.position = 'relative';
  162.  
  163. createItemMenu(container, title);
  164.  
  165. watchAppState([`item.${title}.state`, 'showAll'], ([state, showAll]) => {
  166. const hidden = state == 'hidden';
  167. const oldDisplay = container.style.display;
  168. container.style.display = showAll || !hidden ? '' : 'none';
  169. container.style.opacity = showAll && hidden ? .5 : '';
  170.  
  171. if (container.style.display != oldDisplay) {
  172. scheduleNotifyScroll();
  173. }
  174. });
  175. }
  176.  
  177. function createBookCoverItem(container) {
  178. const title = container.querySelector('img').getAttribute('alt');
  179.  
  180. container.style.position = 'relative';
  181.  
  182. createItemMenu(container, title);
  183. }
  184.  
  185. function createShowAllButton(container) {
  186. const button = document.createElement('button');
  187. button.type = 'button';
  188. button.textContent = 'Show all';
  189. button.onclick = () => setAppState(`showAll`, '1');
  190. container.appendChild(button);
  191.  
  192. watchAppState('showAll', showAll => {
  193. button.style.display = showAll ? 'none' : '';
  194. });
  195. }
  196.  
  197. function createHideUnwantedButton(container) {
  198. const button = document.createElement('button');
  199. button.type = 'button';
  200. button.textContent = 'Hide unwanted';
  201. button.onclick = () => setAppState(`showAll`, undefined);
  202. container.appendChild(button);
  203.  
  204. watchAppState('showAll', showAll => {
  205. button.style.display = showAll ? '' : 'none';
  206. });
  207. }
  208.  
  209. function createGlobalMenu(container) {
  210. const div = document.createElement('div');
  211. div.className = 'mhgh-global-menu';
  212. div.style.position = 'fixed';
  213. div.style.bottom = 0;
  214. div.style.right = '10px';
  215. div.style.zIndex = 100;
  216. container.appendChild(div);
  217.  
  218. createShowAllButton(div);
  219. createHideUnwantedButton(div);
  220. }
  221.  
  222. createStyle();
  223.  
  224. document.querySelectorAll('.latest-list li').forEach(e => createItem(e));
  225. document.querySelectorAll('.book-cover.fl').forEach(e => createBookCoverItem(e));
  226. createGlobalMenu(document.body);
  227. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址