Greasy Fork is available in English.

拷贝漫画简易阅读

简单的拷贝漫画阅读器,J/K 翻页,左右方向键改变章节,分号键奇偶切换,1/2 改变单双页

  1. // ==UserScript==
  2. // @name 拷贝漫画简易阅读
  3. // @namespace http://tampermonkey.net/
  4. // @match *://*.copymanga.com/comic/*/chapter/*
  5. // @match *://*.copymanga.org/comic/*/chapter/*
  6. // @match *://*.copymanga.site/comic/*/chapter/*
  7. // @match *://*.copymanga.tv/comic/*/chapter/*
  8. // @match *://*.mangacopy.com/comic/*/chapter/*
  9. // @grant none
  10. // @version 1.25
  11. // @author chemPolonium
  12. // @description 简单的拷贝漫画阅读器,J/K 翻页,左右方向键改变章节,分号键奇偶切换,1/2 改变单双页
  13. // @run-at document-end
  14. // @license GPLv3
  15. // ==/UserScript==
  16.  
  17. /* jshint esversion: 6 */
  18. /* jshint multistr: true */
  19. (function() {
  20. 'use strict';
  21.  
  22. document.getElementsByClassName('header')[0].remove();
  23.  
  24. let comicContainerFluid = document.getElementsByClassName('container-fluid comicContent')[0];
  25. comicContainerFluid.style.paddingRight = '0px';
  26. comicContainerFluid.style.paddingLeft = '0px';
  27.  
  28. let comicContainer = comicContainerFluid.children[0];
  29. comicContainer.style.marginRight = '0px';
  30. comicContainer.style.marginLeft = '0px';
  31. comicContainer.style.setProperty('min-width', '10px', 'important');
  32. comicContainer.style.setProperty('max-width', '100%', 'important');
  33.  
  34. let comicList = comicContainer.children[0];
  35. comicList.style.paddingTop = '0px';
  36. comicList.style.marginBottom = '0px';
  37. comicList.style.setProperty('min-width', '10px', 'important');
  38. comicList.style.setProperty('max-width', '100%', 'important');
  39. comicList.style.setProperty('width', '100%', 'important');
  40. comicList.style.display = 'grid';
  41. comicList.style.direction = 'rtl';
  42.  
  43. let comicListChildren = comicList.children;
  44. let currentImageIndex = 0;
  45.  
  46. let comicIndex = document.getElementsByClassName('comicIndex')[0];
  47.  
  48. function refreshIndex() {
  49. comicIndex.textContent = currentImageIndex;
  50. }
  51.  
  52. function getImage(imageIndex) {
  53. return comicListChildren[imageIndex].children[0];
  54. }
  55.  
  56. function getCurrentImage() {
  57. return getImage(currentImageIndex);
  58. }
  59.  
  60. function moveToCurrentImage() {
  61. if (currentImageIndex == 0) {
  62. window.scrollTo(0, 0);
  63. } else {
  64. window.scrollTo(0, getCurrentImage().offsetTop);
  65. }
  66. }
  67.  
  68. let pageNumPerScreen = 2;
  69.  
  70. function preloadImage() {
  71. // simulate the scroll for preload
  72. // the script is like this: total client height / 3 < window scrollY then not load
  73. // so first scroll Y to 0
  74. window.scrollTo(0, 0);
  75. for (let i = 0; i < pageNumPerScreen; i++) {
  76. // window.dispatchEvent(scrollEvent);
  77. window.onscroll();
  78. // dispatch the scroll event for preload
  79. }
  80. // this function will scroll Y to 0
  81. }
  82.  
  83. function moveImageIndex(x) {
  84. let newImageIndex = currentImageIndex + x;
  85. if (newImageIndex < comicList.children.length && newImageIndex >= 0) {
  86. currentImageIndex = newImageIndex;
  87. }
  88. }
  89.  
  90. function setSingleAlign(imageIndex) {
  91. if (pageNumPerScreen == 1)
  92. {
  93. comicListChildren[imageIndex].children[0].style.objectPosition = 'center';
  94. // ('style', 'text-align: center;');
  95. }
  96. if (pageNumPerScreen == 2)
  97. {
  98. comicListChildren[imageIndex].children[0].style.objectPosition = (imageIndex % 2 == 0) ? 'left' : 'right';
  99. }
  100. }
  101.  
  102. function setAlign() {
  103. for (let imageIndex = 0; imageIndex < comicListChildren.length; imageIndex++) {
  104. setSingleAlign(imageIndex);
  105. }
  106. }
  107.  
  108. function setPageNumPerScreen(pageNum) {
  109. comicList.style.gridTemplateColumns = 'repeat(' + String(pageNum) + ', 1fr)';
  110. moveToCurrentImage();
  111. pageNumPerScreen = pageNum;
  112. setAlign();
  113. }
  114.  
  115. setPageNumPerScreen(2);
  116.  
  117. function onePageDown() {
  118. preloadImage();
  119. moveImageIndex(pageNumPerScreen);
  120. moveToCurrentImage();
  121. refreshIndex();
  122. }
  123.  
  124. function onePageUp() {
  125. moveImageIndex(-pageNumPerScreen);
  126. moveToCurrentImage();
  127. refreshIndex();
  128. }
  129.  
  130. function createTitlePage() {
  131. let titlePage = document.createElement('li');
  132. let titlePageDiv = document.createElement('div');
  133. let titlePageTitle = document.createElement('p');
  134. titlePageTitle.appendChild(document.createTextNode(document.title));
  135. titlePageTitle.setAttribute('style', 'color: white;\
  136. font-size: xx-large;\
  137. max-width: 30vw;\
  138. margin-top: 30%;\
  139. margin-right: 20%;\
  140. white-space: normal;');
  141. titlePageDiv.appendChild(titlePageTitle);
  142. titlePage.appendChild(titlePageDiv);
  143. return titlePage;
  144. }
  145.  
  146. function resizeImage(targetli) {
  147. targetli.style.height = '100vh';
  148. targetli.style.maxWidth = '100%';
  149. targetli.firstChild.style.setProperty('height', '100%', 'important');
  150. targetli.firstChild.style.setProperty('width', '100%', 'important');
  151. targetli.firstChild.style.objectFit = 'contain';
  152. }
  153.  
  154. function setAllPages() {
  155. for (let i = 1; i < comicListChildren.length; i++) {
  156. if (comicListChildren[i].children[0]) {
  157. resizeImage(comicListChildren[i]);
  158. }
  159. }
  160. }
  161.  
  162. let titlePage = createTitlePage();
  163.  
  164. let parityChanged = false;
  165.  
  166. function switchParity() {
  167. if (parityChanged) {
  168. comicListChildren[0].remove();
  169. } else {
  170. comicList.insertAdjacentElement('afterbegin', titlePage);
  171. }
  172. parityChanged = !parityChanged;
  173. setAlign();
  174. moveToCurrentImage();
  175. }
  176.  
  177. let footer = document.getElementsByClassName('footer')[0];
  178. let footerChildren = footer.children;
  179. let prevChapterHref = footerChildren[1].children[0].href;
  180. let nextChapterHref = footerChildren[3].children[0].href;
  181. let chapterListHref = footerChildren[4].children[0].href;
  182.  
  183. function toggleFullScreen() {
  184. if (!document.fullscreenElement) {
  185. document.documentElement.requestFullscreen();
  186. } else {
  187. if (document.exitFullscreen) {
  188. document.exitFullscreen();
  189. }
  190. }
  191. }
  192.  
  193. document.addEventListener('keydown', (event) => {
  194. switch (event.code) {
  195. case 'ArrowRight':
  196. window.location = nextChapterHref;
  197. break;
  198. case 'ArrowLeft':
  199. window.location = prevChapterHref;
  200. break;
  201. case 'KeyK':
  202. onePageUp();
  203. break;
  204. case 'KeyJ':
  205. onePageDown();
  206. break;
  207. case 'KeyL':
  208. window.location = chapterListHref;
  209. break;
  210. case 'KeyR':
  211. setAllPages();
  212. break;
  213. case 'KeyF':
  214. toggleFullScreen();
  215. break;
  216. case 'Semicolon':
  217. switchParity();
  218. break;
  219. case 'Digit1':
  220. setPageNumPerScreen(1);
  221. break;
  222. case 'Digit2':
  223. setPageNumPerScreen(2);
  224. break;
  225. default:
  226. console.log('key: ' + event.key + ' code: ' + event.code);
  227. }
  228. });
  229.  
  230. footer.remove();
  231.  
  232. let firstLoad = true;
  233.  
  234. const comicListObserverConfig = { childList: true };
  235.  
  236. const firstLoadCallback = () => {
  237. if (firstLoad && comicListChildren.length > 0) {
  238. firstLoad = false;
  239. switchParity();
  240. // 有时脚本加载得慢,会导致前几页来不及修改大小,因此第一次直接全设置一遍
  241. setAllPages();
  242. }
  243. };
  244.  
  245. const comicListCallback = (mutationList, observer) => {
  246. for (const mutation of mutationList) {
  247. firstLoadCallback();
  248. for (const targetli of mutation.addedNodes) {
  249. resizeImage(targetli);
  250. // 一般一次也就加载一页或两页,加载两页的话只设置最后一页的左右是不够的
  251. setSingleAlign(comicListChildren.length - 2);
  252. setSingleAlign(comicListChildren.length - 1);
  253. }
  254. }
  255. };
  256.  
  257. const comicListObserver = new MutationObserver(comicListCallback);
  258.  
  259. comicListObserver.observe(comicList, comicListObserverConfig);
  260.  
  261. // 有的时候会出现列表加载完了,脚本还没加载上的情况,这时候 MutationObserver 会失效
  262. // 这个时候就手动加个延时当作第一次调用
  263. setTimeout(firstLoadCallback, 50);
  264.  
  265. // 下面是旧版的监听方式,已经被 observer 取代
  266. // comicList.addEventListener('DOMNodeInserted', (event) => {
  267. // if (firstLoad && comicListChildren.length > 2) {
  268. // firstLoad = false;
  269. // switchParity();
  270. // }
  271. // resizeImage(event.target);
  272. // // event.target.style.height = '100vh';
  273. // // event.target.style.maxWidth = '100%';
  274. // // event.target.firstChild.style.setProperty('height', '100%', 'important');
  275. // // event.target.firstChild.style.setProperty('width', '100%', 'important');
  276. // // event.target.firstChild.style.objectFit = 'contain';
  277. // setSingleAlign(comicListChildren.length - 1);
  278. // });
  279.  
  280. })();