|
7 | 7 | // @license GPL-3.0 License |
8 | 8 | // @tag kevingrillet |
9 | 9 | // @tag mangademon.com |
10 | | -// @version 0.5.5 |
| 10 | +// @version 1.0 |
11 | 11 |
|
12 | 12 | // @homepageURL https://github.com/kevingrillet/Userscripts/ |
13 | 13 | // @supportURL https://github.com/kevingrillet/Userscripts/issues |
14 | 14 | // @downloadURL https://raw.githubusercontent.com/kevingrillet/Userscripts/main/user.js/[MangaDemon]%20Tweaks.user.js |
15 | 15 | // @updateURL https://raw.githubusercontent.com/kevingrillet/Userscripts/main/user.js/[MangaDemon]%20Tweaks.user.js |
16 | 16 |
|
| 17 | +// @match https://ciorti.online/* |
17 | 18 | // @match https://comicdemons.com/* |
18 | 19 | // @match https://demoncomics.org/* |
| 20 | +// @match https://demonicscans.org/* |
19 | 21 | // @match https://demonreader.org/* |
20 | 22 | // @match https://demontoon.com/* |
21 | 23 | // @match https://manga-demon.org/* |
22 | 24 | // @match https://mgdemon.org/* |
23 | 25 | // @icon https://www.google.com/s2/favicons?sz=64&domain=demoncomics.org |
24 | | -// @grant none |
| 26 | +// @grant GM_registerMenuCommand |
25 | 27 | // @run-at document-end |
26 | 28 | // ==/UserScript== |
27 | 29 |
|
28 | 30 | (function () { |
29 | 31 | 'use strict'; |
30 | 32 |
|
| 33 | + // Configuration constants |
| 34 | + const CONFIG = { |
| 35 | + AUTO_NEXT_SPEED: 0.5 * 1000, // 0.5s |
| 36 | + AUTO_NEXT_BOOKMARK_SPEED: 1 * 1000, // 1s |
| 37 | + SCROLL_SPEED: 1000 / 60, // ~16.67ms (60fps) |
| 38 | + SCROLL_VALUE: 48, // pixels per scroll |
| 39 | + PRERENDER_TYPE: 'prerender', // or 'prefetch' |
| 40 | + ENABLE_REL: true, // enable/disable rel attribute |
| 41 | + }; |
| 42 | + |
| 43 | + const KEYS = { |
| 44 | + PREVIOUS: ['ArrowLeft', 'KeyA', 'KeyQ'], |
| 45 | + SCROLL_UP: ['ArrowUp', 'KeyW', 'KeyZ'], |
| 46 | + NEXT: ['ArrowRight', 'KeyD'], |
| 47 | + SCROLL_DOWN: ['ArrowDown', 'KeyS'], |
| 48 | + }; |
| 49 | + |
| 50 | + const SELECTORS = { |
| 51 | + BOOKMARKS_CONTAINER: '#bookmarks-container', |
| 52 | + BUTTON_NEXT: '.nextchap', |
| 53 | + BUTTON_PREVIOUS: '.prevchap', |
| 54 | + CHAPTER_TITLE: 'h1', |
| 55 | + PROGRESS_BAR: '#my_progress_bar', |
| 56 | + UPDATES_CHECK: '.updates-check-available span', |
| 57 | + }; |
| 58 | + |
31 | 59 | /** BOOKMARK SECTION */ |
32 | 60 | function sortBookmarks() { |
| 61 | + const container = document.querySelector(SELECTORS.BOOKMARKS_CONTAINER); |
| 62 | + if (!container) { |
| 63 | + console.warn('[MangaDemon Tweaks] Bookmarks container not found'); |
| 64 | + return; |
| 65 | + } |
| 66 | + |
| 67 | + function extractChapterNumber(text) { |
| 68 | + return Number(text?.replace(/[^0-9.-]+/g, '') || 0); |
| 69 | + } |
| 70 | + |
33 | 71 | function sortFunc(a, b) { |
34 | | - let aCard = a.querySelectorAll('.chapternumber'), |
35 | | - bCard = b.querySelectorAll('.chapternumber'); |
36 | | - |
37 | | - let aVal = Number(aCard[1].innerText.replace('Last Chapter ', '')) - Number(aCard[0].innerText.replace('Last Chapter Read ', '')), |
38 | | - bVal = Number(bCard[1].innerText.replace('Last Chapter ', '')) - Number(bCard[0].innerText.replace('Last Chapter Read ', '')); |
39 | | - |
40 | | - if (aVal !== 0 && bVal !== 0 && aVal !== bVal) { |
41 | | - return aVal - bVal; |
42 | | - } else if (aVal === 0 && bVal !== 0) { |
43 | | - return 1; |
44 | | - } else if (aVal !== 0 && bVal === 0) { |
45 | | - return -1; |
46 | | - } |
47 | | - let aTitle = a.querySelector('.novel-title').innerText, |
48 | | - bTitle = b.querySelector('.novel-title').innerText; |
| 72 | + const aCard = a.querySelectorAll(SELECTORS.UPDATES_CHECK); |
| 73 | + const bCard = b.querySelectorAll(SELECTORS.UPDATES_CHECK); |
| 74 | + |
| 75 | + const aVal = extractChapterNumber(aCard[1]?.innerText) - extractChapterNumber(aCard[0]?.innerText); |
| 76 | + const bVal = extractChapterNumber(bCard[1]?.innerText) - extractChapterNumber(bCard[0]?.innerText); |
| 77 | + |
| 78 | + if (aVal !== 0 && bVal !== 0 && aVal !== bVal) return aVal - bVal; |
| 79 | + if (aVal === 0 && bVal !== 0) return 1; |
| 80 | + if (aVal !== 0 && bVal === 0) return -1; |
| 81 | + |
| 82 | + const aTitle = a.querySelector(SELECTORS.CHAPTER_TITLE)?.innerText || ''; |
| 83 | + const bTitle = b.querySelector(SELECTORS.CHAPTER_TITLE)?.innerText || ''; |
49 | 84 | return aTitle.localeCompare(bTitle); |
50 | 85 | } |
51 | 86 |
|
52 | | - let elUl = document.querySelector(':scope .latestupdates ul'); |
53 | | - |
54 | | - Array.from(elUl.getElementsByTagName('li')) |
55 | | - .sort((a, b) => sortFunc(a, b)) |
56 | | - .forEach((elLi) => elUl.appendChild(elLi)); |
| 87 | + const items = Array.from(container.getElementsByTagName('li')); |
| 88 | + items.sort(sortFunc).forEach((item) => container.appendChild(item)); |
57 | 89 | } |
58 | 90 |
|
59 | 91 | /** CHAPTEUR SECTION */ |
60 | | - var autoNextSpeed = 0.5 * 1000, // .5 s |
61 | | - autoNextBookmarkSpeed = 1 * 1000, // +1 s |
62 | | - buttonNext = document.querySelector('.nextchap'), |
63 | | - buttonPrevious = document.querySelector('.prevchap'), |
64 | | - doRel = true, // does rel is added on scroll |
65 | | - head = document.head, |
66 | | - rel = 'prerender', // prerender/prefetch; |
67 | | - scrollInterval, |
68 | | - scrollSpeed = 1000 / 60, // 1/60 s |
69 | | - scrollValue = 48; // px; |
| 92 | + const NAVIGATION = { |
| 93 | + next: document.querySelector(SELECTORS.BUTTON_NEXT), |
| 94 | + previous: document.querySelector(SELECTORS.BUTTON_PREVIOUS), |
| 95 | + }; |
| 96 | + |
| 97 | + let scrollInterval; |
| 98 | + |
| 99 | + function _get_window_height() { |
| 100 | + return window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight || 0; |
| 101 | + } |
| 102 | + |
| 103 | + function _get_window_Yscroll() { |
| 104 | + return window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop || 0; |
| 105 | + } |
| 106 | + function _get_doc_height() { |
| 107 | + return Math.max( |
| 108 | + document.body.scrollHeight || 0, |
| 109 | + document.documentElement.scrollHeight || 0, |
| 110 | + document.body.offsetHeight || 0, |
| 111 | + document.documentElement.offsetHeight || 0, |
| 112 | + document.body.clientHeight || 0, |
| 113 | + document.documentElement.clientHeight || 0 |
| 114 | + ); |
| 115 | + } |
| 116 | + |
| 117 | + function _get_scroll_percentage() { |
| 118 | + try { |
| 119 | + const windowScroll = _get_window_Yscroll(); |
| 120 | + const windowHeight = _get_window_height(); |
| 121 | + const docHeight = _get_doc_height(); |
| 122 | + |
| 123 | + if (docHeight === 0) { |
| 124 | + console.warn('[MangaDemon Tweaks] Invalid document height'); |
| 125 | + return 0; |
| 126 | + } |
| 127 | + |
| 128 | + return ((windowScroll + windowHeight) / docHeight) * 100; |
| 129 | + } catch (error) { |
| 130 | + console.error('[MangaDemon Tweaks] Error calculating scroll percentage:', error); |
| 131 | + return 0; |
| 132 | + } |
| 133 | + } |
70 | 134 |
|
71 | 135 | function addProgressBar() { |
72 | 136 | let elDiv = document.body.appendChild(document.createElement('div')); |
|
103 | 167 | }`); |
104 | 168 |
|
105 | 169 | let processScroll = () => { |
106 | | - let docElem = document.documentElement, |
107 | | - docBody = document.body, |
108 | | - scrollTop = docElem.scrollTop || docBody.scrollTop, |
109 | | - scrollBottom = (docElem.scrollHeight || docBody.scrollHeight) - window.innerHeight, |
110 | | - scrollPercent = (scrollTop / scrollBottom) * 100 + '%'; |
111 | | - document.getElementById('my_progress_bar').style.setProperty('--scrollAmount', scrollPercent); |
112 | | - document.getElementById('my_progress_bar').innerHTML = Math.round((scrollTop / scrollBottom) * 100) + '%'; |
| 170 | + let scrollPercent = _get_scroll_percentage() - 1; |
| 171 | + document.getElementById(SELECTORS.PROGRESS_BAR).style.setProperty('--scrollAmount', scrollPercent + '%'); |
| 172 | + document.getElementById(SELECTORS.PROGRESS_BAR).innerHTML = Math.round(scrollPercent) + '%'; |
113 | 173 | }; |
114 | 174 |
|
115 | 175 | document.addEventListener('scroll', processScroll); |
116 | 176 | } |
117 | 177 |
|
118 | 178 | function addStyles(css) { |
119 | | - let style = head.appendChild(document.createElement('style')); |
| 179 | + let style = document.head.appendChild(document.createElement('style')); |
120 | 180 | style.type = 'text/css'; |
121 | 181 | style.innerHTML = css; |
122 | 182 | } |
|
126 | 186 | if (Math.round(window.innerHeight + window.scrollY) >= document.body.offsetHeight - 10) { |
127 | 187 | setTimeout(function () { |
128 | 188 | if (Math.round(window.innerHeight + window.scrollY) >= document.body.offsetHeight - 10) { |
129 | | - if (buttonNext && buttonNext !== undefined) { |
| 189 | + if (NAVIGATION.next && NAVIGATION.next !== undefined) { |
130 | 190 | goNext(); |
131 | 191 | } else { |
132 | 192 | setTimeout(function () { |
133 | 193 | goBookmark(); |
134 | | - }, autoNextBookmarkSpeed); // wait 4 secs |
| 194 | + }, CONFIG.AUTO_NEXT_BOOKMARK_SPEED); // wait 4 secs |
135 | 195 | } |
136 | 196 | } |
137 | | - }, autoNextSpeed); // wait 1 secs |
| 197 | + }, CONFIG.AUTO_NEXT_SPEED); // wait 1 secs |
138 | 198 | } |
139 | 199 | } |
140 | 200 |
|
141 | 201 | function goBookmark() { |
142 | | - window.location.href = window.location.origin + '/following.php'; |
| 202 | + window.location.href = window.location.origin + '/bookmarks.php'; |
143 | 203 | } |
144 | 204 | function goNext() { |
145 | | - if (buttonNext) { |
146 | | - buttonNext.click(); |
| 205 | + if (NAVIGATION.next?.href) { |
| 206 | + window.location.href = NAVIGATION.next.href; |
147 | 207 | } |
148 | 208 | } |
149 | 209 | function goPrevious() { |
150 | | - if (buttonPrevious) { |
151 | | - buttonPrevious.click(); |
| 210 | + if (NAVIGATION.previous?.href) { |
| 211 | + window.location.href = NAVIGATION.previous.href; |
152 | 212 | } |
153 | 213 | } |
154 | 214 |
|
155 | 215 | function prerender(force) { |
156 | | - if (!doRel) return; |
| 216 | + if (!CONFIG.ENABLE_REL) return; |
157 | 217 | force = force || false; |
158 | | - if (buttonNext && buttonNext !== undefined) { |
159 | | - if (buttonNext.rel === 'nofollow') { |
| 218 | + if (NAVIGATION.next && NAVIGATION.next !== undefined) { |
| 219 | + if (NAVIGATION.next.rel === 'nofollow') { |
160 | 220 | if (force || Math.round(window.innerHeight + window.scrollY) >= document.body.offsetHeight * 0.75) { |
161 | | - let link = head.appendChild(document.createElement('link')); |
162 | | - link.setAttribute('rel', rel); |
163 | | - link.setAttribute('href', buttonNext.href); |
164 | | - buttonNext.setAttribute('rel', rel); |
| 221 | + let link = document.head.appendChild(document.createElement('link')); |
| 222 | + link.setAttribute('rel', CONFIG.PRERENDER_TYPE); |
| 223 | + link.setAttribute('href', NAVIGATION.next.href); |
| 224 | + NAVIGATION.next.setAttribute('rel', CONFIG.PRERENDER_TYPE); |
165 | 225 | console.debug('Prerender added.'); |
166 | 226 | } |
167 | 227 | } |
|
170 | 230 | function startScrolling(value) { |
171 | 231 | scrollInterval = setInterval(function () { |
172 | 232 | window.scrollBy(0, value); |
173 | | - }, scrollSpeed); |
| 233 | + }, CONFIG.SCROLL_SPEED); |
174 | 234 | } |
175 | 235 | function stopScrolling() { |
176 | 236 | clearInterval(scrollInterval); |
177 | 237 | scrollInterval = null; |
178 | 238 | } |
179 | 239 |
|
| 240 | + function handleKeyDown(event) { |
| 241 | + if (event.ctrlKey || event.code === 'MetaLeft' || event.code === 'MetaRight') { |
| 242 | + return; |
| 243 | + } |
| 244 | + |
| 245 | + if (KEYS.PREVIOUS.includes(event.code)) { |
| 246 | + goPrevious(); |
| 247 | + } else if (KEYS.SCROLL_UP.includes(event.code)) { |
| 248 | + stopScrolling(); |
| 249 | + startScrolling(-CONFIG.SCROLL_VALUE); |
| 250 | + } else if (KEYS.NEXT.includes(event.code)) { |
| 251 | + goNext(); |
| 252 | + } else if (KEYS.SCROLL_DOWN.includes(event.code)) { |
| 253 | + stopScrolling(); |
| 254 | + startScrolling(CONFIG.SCROLL_VALUE); |
| 255 | + } |
| 256 | + } |
| 257 | + |
| 258 | + function handleKeyUp(event) { |
| 259 | + if (KEYS.SCROLL_UP.includes(event.code) || KEYS.SCROLL_DOWN.includes(event.code)) { |
| 260 | + stopScrolling(); |
| 261 | + } |
| 262 | + } |
| 263 | + |
| 264 | + const PAGE_TYPE = { |
| 265 | + isBookmarkPage: () => window.location.href.includes('/bookmarks.php'), |
| 266 | + isChapterPage: () => window.location.href.includes('/title/') && window.location.href.includes('/chapter/'), |
| 267 | + }; |
| 268 | + |
180 | 269 | /** MAIN SECTION */ |
181 | 270 | window.addEventListener('load', function () { |
182 | | - if (window.location.href.indexOf('/following.php') > -1) { |
| 271 | + if (PAGE_TYPE.isBookmarkPage()) { |
183 | 272 | sortBookmarks(); |
184 | | - } else if (window.location.href.indexOf('/manga/') > -1 && window.location.href.indexOf('/chapter/') > -1) { |
| 273 | + } else if (PAGE_TYPE.isChapterPage()) { |
185 | 274 | addProgressBar(); |
186 | 275 |
|
187 | 276 | window.onscroll = function () { |
188 | 277 | autoNext(); |
189 | 278 | prerender(); |
190 | 279 | }; |
191 | 280 |
|
192 | | - document.addEventListener('keydown', (event) => { |
193 | | - if (event.ctrlKey || event.code === 'MetaLeft' || event.code === 'MetaRight') { |
194 | | - return; |
195 | | - } |
196 | | - if (event.code === 'ArrowLeft' || event.code === 'KeyA' || event.code === 'KeyQ') { |
197 | | - goPrevious(); |
198 | | - } else if (event.code === 'ArrowUp' || event.code === 'KeyW' || event.code === 'KeyZ') { |
199 | | - stopScrolling(); |
200 | | - startScrolling(-scrollValue); |
201 | | - } else if (event.code === 'ArrowRight' || event.code === 'KeyD') { |
202 | | - goNext(); |
203 | | - } else if (event.code === 'ArrowDown' || event.code === 'KeyS') { |
204 | | - stopScrolling(); |
205 | | - startScrolling(scrollValue); |
206 | | - } |
207 | | - }); |
208 | | - |
209 | | - document.addEventListener('keyup', (event) => { |
210 | | - if (event.code === 'ArrowUp' || event.code === 'KeyW' || event.code === 'KeyZ' || event.code === 'ArrowDown' || event.code === 'KeyS') { |
211 | | - stopScrolling(); |
212 | | - } |
213 | | - }); |
| 281 | + document.addEventListener('keydown', handleKeyDown); |
| 282 | + document.addEventListener('keyup', handleKeyUp); |
214 | 283 | } |
215 | 284 | }); |
| 285 | + |
| 286 | + if (PAGE_TYPE.isBookmarkPage()) { |
| 287 | + GM_registerMenuCommand('Sort bookmarks', function () { |
| 288 | + sortBookmarks(); |
| 289 | + }); |
| 290 | + } |
216 | 291 | })(); |
0 commit comments