SmoothScroll & Navigation Enhancer

You can quickly access the previous and next episodes, perform smooth scrolling up or down, and even enable or disable full-screen mode. This script is designed to enhance the reading experience of web content such as manga and comics in a more convenient and efficient way.

当前为 2024-08-23 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name SmoothScroll & Navigation Enhancer
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.4
  5. // @description You can quickly access the previous and next episodes, perform smooth scrolling up or down, and even enable or disable full-screen mode. This script is designed to enhance the reading experience of web content such as manga and comics in a more convenient and efficient way.
  6. // @match https://westmanga.fun/*
  7. // @match https://komikcast.cz/*
  8. // @match https://aquamanga.org/read/*
  9. // @match https://www.webtoons.com/*
  10. // @match https://kiryuu.org/*
  11. // @match https://kiryuu.co/*
  12. // @match https://mangatale.co/*
  13. // @match https://mangaku.mom/*
  14. // @match https://manhwatop.com/*
  15. // @match https://komiku.id/*
  16. // @match https://komiknesia.xyz/*
  17. // @grant none
  18. // @license MIT
  19. // ==/UserScript==
  20.  
  21. (function() {
  22. 'use strict';
  23.  
  24. var scrollInterval = null;
  25. var isScrolling = false
  26. var isFullscreen = false;
  27. var activeElement;
  28.  
  29. var smoothScrollSpeed = 10.5; // Kecepatan pengguliran yang mulus
  30. var smoothScrollDelay = 10; // Penundaan di antara setiap langkah pengguliran yang mulus
  31.  
  32. const HOSTS = {
  33. 'westmanga.fun': {
  34. next: '.ch-next-btn',
  35. prev: '.ch-prev-btn'
  36. },
  37. 'komikcast.cz': {
  38. next: '.nextprev a[rel="next"]',
  39. prev: '.nextprev a[rel="prev"]'
  40. },
  41. 'www.webtoons.com': {
  42. next: 'a[title="Episode selanjutnya"]',
  43. prev: 'a[title="Episode sebelumnya"]'
  44. },
  45. 'aquamanga.org': {
  46. next: 'a.btn.next_page',
  47. prev: 'a.btn.prev_page'
  48. },
  49. 'kiryuu.org': {
  50. next: 'a.ch-next-btn',
  51. prev: 'a.ch-prev-btn'
  52. },
  53. 'mangatale.co': {
  54. next: 'a.ch-next-btn',
  55. prev: 'a.ch-prev-btn'
  56. },
  57. 'mangaku.mom': {
  58. prev: 'button.glho.glkp_1:-soup-contains("PREV")',
  59. next: 'button.glho.glkn_1:-soup-contains("NEXT")'
  60. },
  61. 'manhwatop.com': {
  62. prev: '.prev_page',
  63. next: '.next_page'
  64. },
  65. 'komiku.id': {
  66. prev: 'div.nxpr > a.rl:first-of-type',
  67. next: 'div.nxpr > a.rl:last-of-type'
  68. },
  69. 'komiknesia.xyz': {
  70. prev: 'a.ch-prev-btn',
  71. next: 'a.ch-next-btn'
  72. }
  73. };
  74.  
  75. let btnNext, btnPrev;
  76. let host = window.location.host;
  77. if (HOSTS[host]) {
  78. btnNext = HOSTS[host].next;
  79. btnPrev = HOSTS[host].prev;
  80. }
  81.  
  82. const zoomLevel = () => {
  83. return document.body.style.zoom || 1;
  84. }
  85.  
  86. function adjustSmoothScroll() {
  87.  
  88. let zLevel = zoomLevel();
  89.  
  90. smoothScrollSpeed = smoothScrollSpeed * zLevel;
  91. smoothScrollDelay = smoothScrollDelay / zLevel;
  92. }
  93.  
  94. function smoothScrollStep(direction) {
  95. var scrollDistance = direction === 'up' ? -smoothScrollSpeed : smoothScrollSpeed;
  96. window.scrollBy(0, scrollDistance);
  97. }
  98.  
  99. function startSmoothScrolling(direction) {
  100. if (!isScrolling) {
  101. isScrolling = true;
  102. smoothScrollStep(direction);
  103. scrollInterval = setInterval(function() {
  104. smoothScrollStep(direction);
  105. }, smoothScrollDelay);
  106. }
  107. }
  108.  
  109. function stopSmoothScrolling() {
  110. if (isScrolling) {
  111. isScrolling = false;
  112. clearInterval(scrollInterval);
  113. }
  114. }
  115.  
  116. // Deteksi saat zoom berubah
  117. document.addEventListener('zoomchange', adjustSmoothScroll);
  118.  
  119. // Sesuaikan juga saat scroll dihentikan
  120. document.addEventListener('keyup', event => {
  121.  
  122. if (isScrolling) {
  123. stopSmoothScrolling();
  124. adjustSmoothScroll();
  125. }
  126. });
  127.  
  128. adjustSmoothScroll();
  129.  
  130. document.addEventListener('keydown', function(event) {
  131. if ((event.key === 'a' || event.key === 'A' || event.key === 'ArrowLeft') && !event.ctrlKey && !event.altKey && event.key !== 'Tab') {
  132. let prevButton = document.querySelector(btnPrev);
  133. if (prevButton) {
  134. // Periksa elemen yang sedang dalam fokus
  135. activeElement = document.activeElement;
  136. if (!(activeElement && (activeElement.tagName === 'INPUT' || activeElement.tagName === 'TEXTAREA'))) {
  137. // Pengguna tidak sedang mengetik
  138. prevButton.click();
  139. }
  140. }
  141. } else if ((event.key === 'd' || event.key === 'D' || event.key === 'ArrowRight') && !event.ctrlKey && !event.altKey && event.key !== 'Tab') {
  142. let nextButton = document.querySelector(btnNext);
  143. if (nextButton) {
  144. // Periksa elemen yang sedang dalam fokus
  145. activeElement = document.activeElement;
  146. if (!(activeElement && (activeElement.tagName === 'INPUT' || activeElement.tagName === 'TEXTAREA'))) {
  147. // Pengguna tidak sedang mengetik
  148. nextButton.click();
  149. }
  150. }
  151. } else if ((event.key === 's' || event.key === 'S') && !event.ctrlKey && !event.altKey && event.key !== 'Tab') {
  152. // Periksa elemen yang sedang dalam fokus
  153. activeElement = document.activeElement;
  154. if (!(activeElement && (activeElement.tagName === 'INPUT' || activeElement.tagName === 'TEXTAREA'))) {
  155. // Pengguna tidak sedang mengetik
  156. startSmoothScrolling('down');
  157. }
  158. } else if ((event.key === 'w' || event.key === 'W') && !event.ctrlKey && !event.altKey && event.key !== 'Tab') {
  159. // Periksa elemen yang sedang dalam fokus
  160. activeElement = document.activeElement;
  161. if (!(activeElement && (activeElement.tagName === 'INPUT' || activeElement.tagName === 'TEXTAREA'))) {
  162. // Pengguna tidak sedang mengetik
  163. startSmoothScrolling('up');
  164. }
  165. } else if ((event.key === 'f' || event.key === 'F') && !event.ctrlKey && !event.altKey && event.key !== 'Tab') {
  166. // Periksa elemen yang sedang dalam fokus
  167. activeElement = document.activeElement;
  168. if (!(activeElement && (activeElement.tagName === 'INPUT' || activeElement.tagName === 'TEXTAREA'))) {
  169. // Pengguna tidak sedang mengetik, masuk ke mode fullscreen
  170. event.preventDefault();
  171. toggleFullscreen(); // Fungsi Anda untuk masuk/keluar dari mode fullscreen
  172. }
  173. } else if ((event.key === 'q' || event.key === 'Q') && !event.ctrlKey && !event.altKey && event.key !== 'Tab') {
  174. var allChapterButton;
  175. if (window.location.host === 'westmanga.fun') {
  176. allChapterButton = document.querySelector('.allc a');
  177. } else if (window.location.host === 'www.webtoons.com') {
  178. allChapterButton = document.querySelector('a[class="subj NPI=a:end,g:in_id"]');
  179. } else if (window.location.host === 'komiknesia.xyz') {
  180. allChapterButton = document.querySelector('.allc a');
  181. } else if (window.location.host === 'kiryuu.org') {
  182. allChapterButton = document.evaluate("//div[contains(text(), 'Semua chapter ada di')]/a", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
  183. } else if (window.location.host === 'komikcast.cz') {
  184. allChapterButton = document.querySelector('div.allc a');
  185. } else if (window.location.host === 'mangatale.co') {
  186. allChapterButton = document.evaluate("//div[contains(text(), 'All chapters are in ')]/a", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
  187. } else if (window.location.host === 'aquamanga.org') {
  188. // Ambil URL saat ini
  189. var currentUrl = window.location.href;
  190. // Gunakan ekspresi reguler untuk menghapus segmen URL setelah judul komik
  191. var newUrl = currentUrl.replace(/\/read\/([^/]+)\/.*/, '/read/$1/');
  192. // Periksa elemen yang sedang dalam fokus
  193. activeElement = document.activeElement;
  194. if (!(activeElement && (activeElement.tagName === 'INPUT' || activeElement.tagName === 'TEXTAREA'))) {
  195. // Pengguna tidak sedang mengetik memindahkan pengguna ke URL yang telah diubah
  196. window.location.href = newUrl;
  197. }
  198. }
  199. if (allChapterButton) {
  200. // Periksa elemen yang sedang dalam fokus
  201. activeElement = document.activeElement;
  202. if (!(activeElement && (activeElement.tagName === 'INPUT' || activeElement.tagName === 'TEXTAREA'))) {
  203. // Pengguna tidak sedang mengetik
  204. allChapterButton.click();
  205. }
  206. }
  207. }
  208. });
  209.  
  210. function toggleFullscreen() {
  211. if (!isFullscreen) {
  212. enterFullscreen();
  213. } else {
  214. exitFullscreen();
  215. }
  216. isFullscreen = !isFullscreen;
  217. }
  218.  
  219. function enterFullscreen() {
  220. const elem = document.documentElement;
  221. if (elem.requestFullscreen) {
  222. elem.requestFullscreen();
  223. } else if (elem.mozRequestFullScreen) {
  224. elem.mozRequestFullScreen();
  225. } else if (elem.webkitRequestFullscreen) {
  226. elem.webkitRequestFullscreen();
  227. } else if (elem.msRequestFullscreen) {
  228. elem.msRequestFullscreen();
  229. }
  230. }
  231.  
  232. function exitFullscreen() {
  233. if (document.exitFullscreen) {
  234. document.exitFullscreen();
  235. } else if (document.mozCancelFullScreen) {
  236. document.mozCancelFullScreen();
  237. } else if (document.webkitExitFullscreen) {
  238. document.webkitExitFullscreen();
  239. } else if (document.msExitFullscreen) {
  240. document.msExitFullscreen();
  241. }
  242. }
  243.  
  244. document.addEventListener('keyup', function(event) {
  245. if ((event.key === 's' || event.key === 'S' || event.key === 'w' || event.key === 'W') && !event.ctrlKey && !event.altKey && event.key !== 'Tab') {
  246. stopSmoothScrolling();
  247. window.scrollTo(window.pageXOffset, window.pageYOffset); // Menghentikan scroll secara instan
  248. }
  249. });
  250. })();