billy-herrington-utils 1.4.4 → 1.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/billy-herrington-utils.es.js +258 -260
- package/dist/billy-herrington-utils.es.js.map +1 -1
- package/dist/billy-herrington-utils.umd.js +258 -260
- package/dist/billy-herrington-utils.umd.js.map +1 -1
- package/dist/index.d.ts +14 -5
- package/package.json +14 -4
- package/src/index.ts +14 -14
- package/src/types/globals.d.ts +2 -0
- package/src/{data-manager → userscripts/data-manager}/index.ts +19 -12
- package/src/{utils → userscripts}/infinite-scroll/index.ts +6 -7
- package/src/{utils → userscripts}/jabroni-outfit-wrap/index.ts +6 -12
- package/src/userscripts/pagination-parsing/index.ts +51 -0
- package/src/userscripts/pagination-parsing/pagination-strategies/PaginationStrategy.ts +33 -0
- package/src/userscripts/pagination-parsing/pagination-strategies/PaginationStrategyDataParams.ts +57 -0
- package/src/userscripts/pagination-parsing/pagination-strategies/PaginationStrategyPathnameParams.ts +57 -0
- package/src/userscripts/pagination-parsing/pagination-strategies/PaginationStrategySearchParams.ts +47 -0
- package/src/userscripts/pagination-parsing/pagination-strategies/PaginationStrategyTrash.ts +36 -0
- package/src/userscripts/pagination-parsing/pagination-strategies/index.ts +5 -0
- package/src/userscripts/pagination-parsing/pagination-utils/index.ts +27 -0
- package/src/utils/userscript-utils/pagination-strategies.ts +0 -59
|
@@ -1,46 +1,6 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
-
function stringToWords(s) {
|
|
5
|
-
return s.split(",").map((s2) => s2.trim().toLowerCase()).filter((_) => _);
|
|
6
|
-
}
|
|
7
|
-
function sanitizeStr(s) {
|
|
8
|
-
return s?.replace(/\n|\t/, " ").replace(/ {2,}/, " ").trim().toLowerCase() || "";
|
|
9
|
-
}
|
|
10
|
-
function formatTimeToHHMMSS(timeString) {
|
|
11
|
-
const regex = /(?:(\d+)\s*h\s*)?(?:(\d+)\s*mi?n?\s*)?(?:(\d+)\s*sec)?/;
|
|
12
|
-
const match = timeString.match(regex);
|
|
13
|
-
const h = parseInt(match?.[1] || "0");
|
|
14
|
-
const m = parseInt(match?.[2] || "0");
|
|
15
|
-
const s = parseInt(match?.[3] || "0");
|
|
16
|
-
const pad = (num) => String(num).padStart(2, "0");
|
|
17
|
-
return `${pad(h)}:${pad(m)}:${pad(s)}`;
|
|
18
|
-
}
|
|
19
|
-
function timeToSeconds(t) {
|
|
20
|
-
const r = /sec|min|h|m/.test(t) ? formatTimeToHHMMSS(t) : t;
|
|
21
|
-
return (r?.match(/\d+/gm) || [0]).reverse().map((s, i) => parseInt(s) * 60 ** i).reduce((a, b) => a + b);
|
|
22
|
-
}
|
|
23
|
-
function parseIntegerOr(n, or) {
|
|
24
|
-
return ((num) => Number.isNaN(num) ? or : num)(parseInt(n));
|
|
25
|
-
}
|
|
26
|
-
function parseDataParams(str) {
|
|
27
|
-
const paramsStr = decodeURI(str.trim()).split(";");
|
|
28
|
-
return paramsStr.reduce((acc, s) => {
|
|
29
|
-
const parsed = s.match(/([\+\w]+):([\w\-\ ]+)?/);
|
|
30
|
-
if (parsed) {
|
|
31
|
-
const [, key, value] = parsed;
|
|
32
|
-
if (value) {
|
|
33
|
-
key.split("+").forEach((p) => {
|
|
34
|
-
acc[p] = value;
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return acc;
|
|
39
|
-
}, {});
|
|
40
|
-
}
|
|
41
|
-
function parseCSSUrl(s) {
|
|
42
|
-
return s.replace(/url\("|\"\).*/g, "");
|
|
43
|
-
}
|
|
44
4
|
class Observer {
|
|
45
5
|
constructor(callback) {
|
|
46
6
|
__publicField(this, "observer");
|
|
@@ -92,215 +52,11 @@ class LazyImgLoader {
|
|
|
92
52
|
this.lazyImgObserver.observe(img);
|
|
93
53
|
}
|
|
94
54
|
}
|
|
95
|
-
function
|
|
96
|
-
return (
|
|
97
|
-
}
|
|
98
|
-
function parseDom(html) {
|
|
99
|
-
const parsed = new DOMParser().parseFromString(html, "text/html").body;
|
|
100
|
-
return parsed.children.length > 1 ? parsed : parsed.firstElementChild;
|
|
101
|
-
}
|
|
102
|
-
function copyAttributes(target, source) {
|
|
103
|
-
for (const attr of source.attributes) {
|
|
104
|
-
attr.nodeValue && target.setAttribute(attr.nodeName, attr.nodeValue);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
function replaceElementTag(e, tagName) {
|
|
108
|
-
const newTagElement = document.createElement(tagName);
|
|
109
|
-
copyAttributes(newTagElement, e);
|
|
110
|
-
newTagElement.innerHTML = e.innerHTML;
|
|
111
|
-
e.parentNode?.replaceChild(newTagElement, e);
|
|
112
|
-
return newTagElement;
|
|
113
|
-
}
|
|
114
|
-
function getAllUniqueParents(elements) {
|
|
115
|
-
return Array.from(elements).reduce((acc, v) => {
|
|
116
|
-
if (v.parentElement && !acc.includes(v.parentElement)) {
|
|
117
|
-
acc.push(v.parentElement);
|
|
118
|
-
}
|
|
119
|
-
return acc;
|
|
120
|
-
}, []);
|
|
121
|
-
}
|
|
122
|
-
function findNextSibling(el) {
|
|
123
|
-
if (el.nextElementSibling) return el.nextElementSibling;
|
|
124
|
-
if (el.parentElement) return findNextSibling(el.parentElement);
|
|
125
|
-
return null;
|
|
126
|
-
}
|
|
127
|
-
function waitForElementExists(parent, selector, callback) {
|
|
128
|
-
const observer = new MutationObserver((_mutations) => {
|
|
129
|
-
const el = parent.querySelector(selector);
|
|
130
|
-
if (el) {
|
|
131
|
-
observer.disconnect();
|
|
132
|
-
callback(el);
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
observer.observe(document.body, { childList: true, subtree: true });
|
|
136
|
-
}
|
|
137
|
-
function watchElementChildrenCount(element, callback) {
|
|
138
|
-
let count = element.children.length;
|
|
139
|
-
const observer = new MutationObserver((mutationList, observer2) => {
|
|
140
|
-
for (const mutation of mutationList) {
|
|
141
|
-
if (mutation.type === "childList") {
|
|
142
|
-
if (count !== element.children.length) {
|
|
143
|
-
count = element.children.length;
|
|
144
|
-
callback(observer2, count);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
observer.observe(element, { childList: true });
|
|
150
|
-
}
|
|
151
|
-
function watchDomChangesWithThrottle(element, callback, throttle = 1e3, times = Infinity, options = { childList: true, subtree: true, attributes: true }) {
|
|
152
|
-
let lastMutationTime;
|
|
153
|
-
let timeout;
|
|
154
|
-
let times_ = times;
|
|
155
|
-
const observer = new MutationObserver((_mutationList, _observer) => {
|
|
156
|
-
if (times_ !== Infinity && times_ < 1) {
|
|
157
|
-
observer.disconnect();
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
times_--;
|
|
161
|
-
const now = Date.now();
|
|
162
|
-
if (lastMutationTime && now - lastMutationTime < throttle) {
|
|
163
|
-
timeout && clearTimeout(timeout);
|
|
164
|
-
}
|
|
165
|
-
timeout = setTimeout(callback, throttle);
|
|
166
|
-
lastMutationTime = now;
|
|
167
|
-
});
|
|
168
|
-
observer.observe(element, options);
|
|
169
|
-
return observer;
|
|
170
|
-
}
|
|
171
|
-
function downloader(options = { append: "", after: "", button: "", cbBefore: () => {
|
|
172
|
-
} }) {
|
|
173
|
-
const btn = parseDom(options.button);
|
|
174
|
-
if (options.append) document.querySelector(options.append)?.append(btn);
|
|
175
|
-
if (options.after) document.querySelector(options.after)?.after(btn);
|
|
176
|
-
btn.addEventListener("click", (e) => {
|
|
177
|
-
e.preventDefault();
|
|
178
|
-
if (options.cbBefore) options.cbBefore();
|
|
179
|
-
waitForElementExists(document.body, "video", (video) => {
|
|
180
|
-
window.location.href = video.getAttribute("src");
|
|
181
|
-
});
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
function exterminateVideo(video) {
|
|
185
|
-
video.removeAttribute("src");
|
|
186
|
-
video.load();
|
|
187
|
-
video.remove();
|
|
188
|
-
}
|
|
189
|
-
const MOBILE_UA = [
|
|
190
|
-
"Mozilla/5.0 (Linux; Android 10; K)",
|
|
191
|
-
"AppleWebKit/537.36 (KHTML, like Gecko)",
|
|
192
|
-
"Chrome/114.0.0.0 Mobile Safari/537.36"
|
|
193
|
-
].join(" ");
|
|
194
|
-
function fetchWith(url, options = { html: false, mobile: false }) {
|
|
195
|
-
const reqOpts = {};
|
|
196
|
-
if (options.mobile) Object.assign(reqOpts, { headers: new Headers({ "User-Agent": MOBILE_UA }) });
|
|
197
|
-
return fetch(url, reqOpts).then((r) => r.text()).then((r) => options.html ? parseDom(r) : r);
|
|
198
|
-
}
|
|
199
|
-
const fetchHtml = (url) => fetchWith(url, { html: true });
|
|
200
|
-
const fetchText = (url) => fetchWith(url);
|
|
201
|
-
function objectToFormData(object) {
|
|
202
|
-
const formData = new FormData();
|
|
203
|
-
Object.entries(object).forEach(([k, v]) => formData.append(k, v));
|
|
204
|
-
return formData;
|
|
205
|
-
}
|
|
206
|
-
function listenEvents(dom, events, callback) {
|
|
207
|
-
for (const e of events) {
|
|
208
|
-
dom.addEventListener(e, callback, true);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
class Tick {
|
|
212
|
-
constructor(delay, startImmediate = true) {
|
|
213
|
-
__publicField(this, "tick");
|
|
214
|
-
__publicField(this, "callbackFinal");
|
|
215
|
-
this.delay = delay;
|
|
216
|
-
this.startImmediate = startImmediate;
|
|
217
|
-
}
|
|
218
|
-
start(callback, callbackFinal) {
|
|
219
|
-
this.stop();
|
|
220
|
-
this.callbackFinal = callbackFinal;
|
|
221
|
-
if (this.startImmediate) callback();
|
|
222
|
-
this.tick = window.setInterval(callback, this.delay);
|
|
223
|
-
}
|
|
224
|
-
stop() {
|
|
225
|
-
if (this.tick !== void 0) {
|
|
226
|
-
clearInterval(this.tick);
|
|
227
|
-
this.tick = void 0;
|
|
228
|
-
}
|
|
229
|
-
if (this.callbackFinal) {
|
|
230
|
-
this.callbackFinal();
|
|
231
|
-
this.callbackFinal = void 0;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
function isMob() {
|
|
236
|
-
return /iPhone|Android/i.test(navigator.userAgent);
|
|
237
|
-
}
|
|
238
|
-
async function computeAsyncOneAtTime(iterable) {
|
|
239
|
-
const res = [];
|
|
240
|
-
for await (const f of iterable) {
|
|
241
|
-
res.push(await f());
|
|
242
|
-
}
|
|
243
|
-
return res;
|
|
244
|
-
}
|
|
245
|
-
function wait(milliseconds) {
|
|
246
|
-
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
247
|
-
}
|
|
248
|
-
class AsyncPool {
|
|
249
|
-
constructor(max = 1, pool = []) {
|
|
250
|
-
__publicField(this, "cur", 0);
|
|
251
|
-
__publicField(this, "finished");
|
|
252
|
-
__publicField(this, "_resolve");
|
|
253
|
-
this.max = max;
|
|
254
|
-
this.pool = pool;
|
|
255
|
-
this.finished = new Promise((resolve) => {
|
|
256
|
-
this._resolve = resolve;
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
static async doNAsyncAtOnce(max = 1, pool = []) {
|
|
260
|
-
const spool = new AsyncPool(max);
|
|
261
|
-
pool.forEach((f) => spool.push(f));
|
|
262
|
-
return spool.run();
|
|
263
|
-
}
|
|
264
|
-
getHighPriorityFirst(p = 0) {
|
|
265
|
-
if (p > 3 || this.pool.length === 0) return void 0;
|
|
266
|
-
const i = this.pool.findIndex((e) => e.p === p);
|
|
267
|
-
if (i >= 0) {
|
|
268
|
-
const res = this.pool[i].v;
|
|
269
|
-
this.pool.splice(i, 1);
|
|
270
|
-
return res;
|
|
271
|
-
}
|
|
272
|
-
return this.getHighPriorityFirst(p + 1);
|
|
273
|
-
}
|
|
274
|
-
async runTask() {
|
|
275
|
-
this.cur++;
|
|
276
|
-
const f = this.getHighPriorityFirst();
|
|
277
|
-
await f?.();
|
|
278
|
-
this.cur--;
|
|
279
|
-
this.runTasks();
|
|
280
|
-
}
|
|
281
|
-
runTasks() {
|
|
282
|
-
if (!this.pool.length) {
|
|
283
|
-
this._resolve?.(true);
|
|
284
|
-
return;
|
|
285
|
-
}
|
|
286
|
-
if (this.cur < this.max) {
|
|
287
|
-
this.runTask();
|
|
288
|
-
this.runTasks();
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
async run() {
|
|
292
|
-
this.runTasks();
|
|
293
|
-
return this.finished;
|
|
294
|
-
}
|
|
295
|
-
push(x) {
|
|
296
|
-
this.pool.push("p" in x ? x : { v: x, p: 0 });
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
function chunks(arr, n) {
|
|
300
|
-
return Array.from({ length: Math.ceil(arr.length / n) }, (_, i) => arr.slice(i * n, i * n + n));
|
|
55
|
+
function stringToWords(s) {
|
|
56
|
+
return s.split(",").map((s2) => s2.trim().toLowerCase()).filter((_) => _);
|
|
301
57
|
}
|
|
302
|
-
function
|
|
303
|
-
return
|
|
58
|
+
function sanitizeStr(s) {
|
|
59
|
+
return s?.replace(/\n|\t/, " ").replace(/ {2,}/, " ").trim().toLowerCase() || "";
|
|
304
60
|
}
|
|
305
61
|
class DataFilter {
|
|
306
62
|
constructor(rules, state) {
|
|
@@ -395,7 +151,9 @@ class DataManager {
|
|
|
395
151
|
}
|
|
396
152
|
}
|
|
397
153
|
requestAnimationFrame(() => {
|
|
398
|
-
updates.forEach((update) =>
|
|
154
|
+
updates.forEach((update) => {
|
|
155
|
+
update();
|
|
156
|
+
});
|
|
399
157
|
});
|
|
400
158
|
});
|
|
401
159
|
__publicField(this, "filterAll", (offset) => {
|
|
@@ -434,7 +192,8 @@ class DataManager {
|
|
|
434
192
|
(target) => !this.isFiltered(target)
|
|
435
193
|
);
|
|
436
194
|
this.dataFilters = new DataFilter(rules, state).filters;
|
|
437
|
-
[window, unsafeWindow
|
|
195
|
+
const targets = [window, globalThis.unsafeWindow].filter(Boolean);
|
|
196
|
+
targets.forEach((w) => {
|
|
438
197
|
Object.assign(w, {
|
|
439
198
|
sortByViews: () => this.sort("view"),
|
|
440
199
|
sortByDuration: () => this.sort("duration")
|
|
@@ -443,7 +202,7 @@ class DataManager {
|
|
|
443
202
|
}
|
|
444
203
|
static filterDSLToRegex(str) {
|
|
445
204
|
const toFullWord = (w) => `(^|\\ )${w}($|\\ )`;
|
|
446
|
-
const str_ = str.replace(/f
|
|
205
|
+
const str_ = str.replace(/f:(\w+)/g, (_, w) => toFullWord(w));
|
|
447
206
|
return stringToWords(str_).map((expr) => new RegExp(expr, "i"));
|
|
448
207
|
}
|
|
449
208
|
isFiltered(el) {
|
|
@@ -461,6 +220,114 @@ class DataManager {
|
|
|
461
220
|
});
|
|
462
221
|
}
|
|
463
222
|
}
|
|
223
|
+
function parseDom(html) {
|
|
224
|
+
const parsed = new DOMParser().parseFromString(html, "text/html").body;
|
|
225
|
+
return parsed.children.length > 1 ? parsed : parsed.firstElementChild;
|
|
226
|
+
}
|
|
227
|
+
function copyAttributes(target, source) {
|
|
228
|
+
for (const attr of source.attributes) {
|
|
229
|
+
attr.nodeValue && target.setAttribute(attr.nodeName, attr.nodeValue);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
function replaceElementTag(e, tagName) {
|
|
233
|
+
const newTagElement = document.createElement(tagName);
|
|
234
|
+
copyAttributes(newTagElement, e);
|
|
235
|
+
newTagElement.innerHTML = e.innerHTML;
|
|
236
|
+
e.parentNode?.replaceChild(newTagElement, e);
|
|
237
|
+
return newTagElement;
|
|
238
|
+
}
|
|
239
|
+
function getAllUniqueParents(elements) {
|
|
240
|
+
return Array.from(elements).reduce((acc, v) => {
|
|
241
|
+
if (v.parentElement && !acc.includes(v.parentElement)) {
|
|
242
|
+
acc.push(v.parentElement);
|
|
243
|
+
}
|
|
244
|
+
return acc;
|
|
245
|
+
}, []);
|
|
246
|
+
}
|
|
247
|
+
function findNextSibling(el) {
|
|
248
|
+
if (el.nextElementSibling) return el.nextElementSibling;
|
|
249
|
+
if (el.parentElement) return findNextSibling(el.parentElement);
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
function waitForElementExists(parent, selector, callback) {
|
|
253
|
+
const observer = new MutationObserver((_mutations) => {
|
|
254
|
+
const el = parent.querySelector(selector);
|
|
255
|
+
if (el) {
|
|
256
|
+
observer.disconnect();
|
|
257
|
+
callback(el);
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
261
|
+
}
|
|
262
|
+
function watchElementChildrenCount(element, callback) {
|
|
263
|
+
let count = element.children.length;
|
|
264
|
+
const observer = new MutationObserver((mutationList, observer2) => {
|
|
265
|
+
for (const mutation of mutationList) {
|
|
266
|
+
if (mutation.type === "childList") {
|
|
267
|
+
if (count !== element.children.length) {
|
|
268
|
+
count = element.children.length;
|
|
269
|
+
callback(observer2, count);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
observer.observe(element, { childList: true });
|
|
275
|
+
}
|
|
276
|
+
function watchDomChangesWithThrottle(element, callback, throttle = 1e3, times = Infinity, options = { childList: true, subtree: true, attributes: true }) {
|
|
277
|
+
let lastMutationTime;
|
|
278
|
+
let timeout;
|
|
279
|
+
let times_ = times;
|
|
280
|
+
const observer = new MutationObserver((_mutationList, _observer) => {
|
|
281
|
+
if (times_ !== Infinity && times_ < 1) {
|
|
282
|
+
observer.disconnect();
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
times_--;
|
|
286
|
+
const now = Date.now();
|
|
287
|
+
if (lastMutationTime && now - lastMutationTime < throttle) {
|
|
288
|
+
timeout && clearTimeout(timeout);
|
|
289
|
+
}
|
|
290
|
+
timeout = setTimeout(callback, throttle);
|
|
291
|
+
lastMutationTime = now;
|
|
292
|
+
});
|
|
293
|
+
observer.observe(element, options);
|
|
294
|
+
return observer;
|
|
295
|
+
}
|
|
296
|
+
function downloader(options = { append: "", after: "", button: "", cbBefore: () => {
|
|
297
|
+
} }) {
|
|
298
|
+
const btn = parseDom(options.button);
|
|
299
|
+
if (options.append) document.querySelector(options.append)?.append(btn);
|
|
300
|
+
if (options.after) document.querySelector(options.after)?.after(btn);
|
|
301
|
+
btn.addEventListener("click", (e) => {
|
|
302
|
+
e.preventDefault();
|
|
303
|
+
if (options.cbBefore) options.cbBefore();
|
|
304
|
+
waitForElementExists(document.body, "video", (video) => {
|
|
305
|
+
window.location.href = video.getAttribute("src");
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
function exterminateVideo(video) {
|
|
310
|
+
video.removeAttribute("src");
|
|
311
|
+
video.load();
|
|
312
|
+
video.remove();
|
|
313
|
+
}
|
|
314
|
+
const MOBILE_UA = [
|
|
315
|
+
"Mozilla/5.0 (Linux; Android 10; K)",
|
|
316
|
+
"AppleWebKit/537.36 (KHTML, like Gecko)",
|
|
317
|
+
"Chrome/114.0.0.0 Mobile Safari/537.36"
|
|
318
|
+
].join(" ");
|
|
319
|
+
function fetchWith(url, options = { html: false, mobile: false }) {
|
|
320
|
+
const reqOpts = {};
|
|
321
|
+
if (options.mobile) Object.assign(reqOpts, { headers: new Headers({ "User-Agent": MOBILE_UA }) });
|
|
322
|
+
return fetch(url, reqOpts).then((r) => r.text()).then((r) => options.html ? parseDom(r) : r);
|
|
323
|
+
}
|
|
324
|
+
const fetchHtml = (url) => fetchWith(url, { html: true });
|
|
325
|
+
const fetchText = (url) => fetchWith(url);
|
|
326
|
+
function objectToFormData(object) {
|
|
327
|
+
const formData = new FormData();
|
|
328
|
+
Object.entries(object).forEach(([k, v]) => formData.append(k, v));
|
|
329
|
+
return formData;
|
|
330
|
+
}
|
|
464
331
|
class InfiniteScroller {
|
|
465
332
|
constructor({
|
|
466
333
|
enabled = true,
|
|
@@ -484,10 +351,7 @@ class InfiniteScroller {
|
|
|
484
351
|
__publicField(this, "onScrollCBs", []);
|
|
485
352
|
__publicField(this, "generatorConsumer", async () => {
|
|
486
353
|
if (!this.enabled) return false;
|
|
487
|
-
const {
|
|
488
|
-
value: { url, offset } = {},
|
|
489
|
-
done
|
|
490
|
-
} = await this.paginationGenerator.next();
|
|
354
|
+
const { value: { url, offset } = {}, done } = await this.paginationGenerator.next();
|
|
491
355
|
if (!done) {
|
|
492
356
|
const nextPageHTML = await fetchHtml(url);
|
|
493
357
|
const prevScrollPos = document.documentElement.scrollTop;
|
|
@@ -521,7 +385,9 @@ class InfiniteScroller {
|
|
|
521
385
|
return this;
|
|
522
386
|
}
|
|
523
387
|
_onScroll() {
|
|
524
|
-
this.onScrollCBs.forEach((cb) =>
|
|
388
|
+
this.onScrollCBs.forEach((cb) => {
|
|
389
|
+
cb(this);
|
|
390
|
+
});
|
|
525
391
|
}
|
|
526
392
|
static *createPaginationGenerator(currentPage, totalPages, generateURL) {
|
|
527
393
|
for (let offset = currentPage + 1; offset <= totalPages; offset++) {
|
|
@@ -532,10 +398,6 @@ class InfiniteScroller {
|
|
|
532
398
|
}
|
|
533
399
|
function createInfiniteScroller(store, handleHtmlCallback, rules) {
|
|
534
400
|
const enabled = store.state.infiniteScrollEnabled;
|
|
535
|
-
rules.paginationOffset = rules.paginationStrategy.getPaginationOffset();
|
|
536
|
-
rules.paginationLast = rules.paginationStrategy.getPaginationLast();
|
|
537
|
-
rules.paginationUrlGenerator = rules.paginationStrategy.getPaginationUrlGenerator();
|
|
538
|
-
rules.paginationElement = rules.paginationStrategy.getPaginationElement();
|
|
539
401
|
const iscroller = new InfiniteScroller({
|
|
540
402
|
enabled,
|
|
541
403
|
handleHtmlCallback,
|
|
@@ -549,6 +411,142 @@ function createInfiniteScroller(store, handleHtmlCallback, rules) {
|
|
|
549
411
|
});
|
|
550
412
|
return iscroller;
|
|
551
413
|
}
|
|
414
|
+
function chunks(arr, n) {
|
|
415
|
+
return Array.from({ length: Math.ceil(arr.length / n) }, (_, i) => arr.slice(i * n, i * n + n));
|
|
416
|
+
}
|
|
417
|
+
function range(size, startAt = 1, step = 1) {
|
|
418
|
+
return Array.from({ length: size }, (_, index) => startAt + index * step);
|
|
419
|
+
}
|
|
420
|
+
async function computeAsyncOneAtTime(iterable) {
|
|
421
|
+
const res = [];
|
|
422
|
+
for await (const f of iterable) {
|
|
423
|
+
res.push(await f());
|
|
424
|
+
}
|
|
425
|
+
return res;
|
|
426
|
+
}
|
|
427
|
+
function wait(milliseconds) {
|
|
428
|
+
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
429
|
+
}
|
|
430
|
+
class AsyncPool {
|
|
431
|
+
constructor(max = 1, pool = []) {
|
|
432
|
+
__publicField(this, "cur", 0);
|
|
433
|
+
__publicField(this, "finished");
|
|
434
|
+
__publicField(this, "_resolve");
|
|
435
|
+
this.max = max;
|
|
436
|
+
this.pool = pool;
|
|
437
|
+
this.finished = new Promise((resolve) => {
|
|
438
|
+
this._resolve = resolve;
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
static async doNAsyncAtOnce(max = 1, pool = []) {
|
|
442
|
+
const spool = new AsyncPool(max);
|
|
443
|
+
pool.forEach((f) => spool.push(f));
|
|
444
|
+
return spool.run();
|
|
445
|
+
}
|
|
446
|
+
getHighPriorityFirst(p = 0) {
|
|
447
|
+
if (p > 3 || this.pool.length === 0) return void 0;
|
|
448
|
+
const i = this.pool.findIndex((e) => e.p === p);
|
|
449
|
+
if (i >= 0) {
|
|
450
|
+
const res = this.pool[i].v;
|
|
451
|
+
this.pool.splice(i, 1);
|
|
452
|
+
return res;
|
|
453
|
+
}
|
|
454
|
+
return this.getHighPriorityFirst(p + 1);
|
|
455
|
+
}
|
|
456
|
+
async runTask() {
|
|
457
|
+
this.cur++;
|
|
458
|
+
const f = this.getHighPriorityFirst();
|
|
459
|
+
await f?.();
|
|
460
|
+
this.cur--;
|
|
461
|
+
this.runTasks();
|
|
462
|
+
}
|
|
463
|
+
runTasks() {
|
|
464
|
+
if (!this.pool.length) {
|
|
465
|
+
this._resolve?.(true);
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
if (this.cur < this.max) {
|
|
469
|
+
this.runTask();
|
|
470
|
+
this.runTasks();
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
async run() {
|
|
474
|
+
this.runTasks();
|
|
475
|
+
return this.finished;
|
|
476
|
+
}
|
|
477
|
+
push(x) {
|
|
478
|
+
this.pool.push("p" in x ? x : { v: x, p: 0 });
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
function isMob() {
|
|
482
|
+
return /iPhone|Android/i.test(navigator.userAgent);
|
|
483
|
+
}
|
|
484
|
+
function listenEvents(dom, events, callback) {
|
|
485
|
+
for (const e of events) {
|
|
486
|
+
dom.addEventListener(e, callback, true);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
class Tick {
|
|
490
|
+
constructor(delay, startImmediate = true) {
|
|
491
|
+
__publicField(this, "tick");
|
|
492
|
+
__publicField(this, "callbackFinal");
|
|
493
|
+
this.delay = delay;
|
|
494
|
+
this.startImmediate = startImmediate;
|
|
495
|
+
}
|
|
496
|
+
start(callback, callbackFinal) {
|
|
497
|
+
this.stop();
|
|
498
|
+
this.callbackFinal = callbackFinal;
|
|
499
|
+
if (this.startImmediate) callback();
|
|
500
|
+
this.tick = window.setInterval(callback, this.delay);
|
|
501
|
+
}
|
|
502
|
+
stop() {
|
|
503
|
+
if (this.tick !== void 0) {
|
|
504
|
+
clearInterval(this.tick);
|
|
505
|
+
this.tick = void 0;
|
|
506
|
+
}
|
|
507
|
+
if (this.callbackFinal) {
|
|
508
|
+
this.callbackFinal();
|
|
509
|
+
this.callbackFinal = void 0;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
function circularShift(n, c = 6, s = 1) {
|
|
514
|
+
return (n + s) % c || c;
|
|
515
|
+
}
|
|
516
|
+
function formatTimeToHHMMSS(timeString) {
|
|
517
|
+
const regex = /(?:(\d+)\s*h\s*)?(?:(\d+)\s*mi?n?\s*)?(?:(\d+)\s*sec)?/;
|
|
518
|
+
const match = timeString.match(regex);
|
|
519
|
+
const h = parseInt(match?.[1] || "0");
|
|
520
|
+
const m = parseInt(match?.[2] || "0");
|
|
521
|
+
const s = parseInt(match?.[3] || "0");
|
|
522
|
+
const pad = (num) => String(num).padStart(2, "0");
|
|
523
|
+
return `${pad(h)}:${pad(m)}:${pad(s)}`;
|
|
524
|
+
}
|
|
525
|
+
function timeToSeconds(t) {
|
|
526
|
+
const r = /sec|min|h|m/.test(t) ? formatTimeToHHMMSS(t) : t;
|
|
527
|
+
return (r?.match(/\d+/gm) || [0]).reverse().map((s, i) => parseInt(s) * 60 ** i).reduce((a, b) => a + b);
|
|
528
|
+
}
|
|
529
|
+
function parseIntegerOr(n, or) {
|
|
530
|
+
return ((num) => Number.isNaN(num) ? or : num)(parseInt(n));
|
|
531
|
+
}
|
|
532
|
+
function parseDataParams(str) {
|
|
533
|
+
const paramsStr = decodeURI(str.trim()).split(";");
|
|
534
|
+
return paramsStr.reduce((acc, s) => {
|
|
535
|
+
const parsed = s.match(/([\+\w]+):([\w\-\ ]+)?/);
|
|
536
|
+
if (parsed) {
|
|
537
|
+
const [, key, value] = parsed;
|
|
538
|
+
if (value) {
|
|
539
|
+
key.split("+").forEach((p) => {
|
|
540
|
+
acc[p] = value;
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
return acc;
|
|
545
|
+
}, {});
|
|
546
|
+
}
|
|
547
|
+
function parseCSSUrl(s) {
|
|
548
|
+
return s.replace(/url\("|\"\).*/g, "");
|
|
549
|
+
}
|
|
552
550
|
export {
|
|
553
551
|
AsyncPool,
|
|
554
552
|
DataManager,
|