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-12-08 提交的版本,查看 最新版本

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