billy-herrington-utils 1.4.3 → 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.
@@ -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,8 +52,173 @@ class LazyImgLoader {
92
52
  this.lazyImgObserver.observe(img);
93
53
  }
94
54
  }
95
- function circularShift(n, c = 6, s = 1) {
96
- return (n + s) % c || c;
55
+ function stringToWords(s) {
56
+ return s.split(",").map((s2) => s2.trim().toLowerCase()).filter((_) => _);
57
+ }
58
+ function sanitizeStr(s) {
59
+ return s?.replace(/\n|\t/, " ").replace(/ {2,}/, " ").trim().toLowerCase() || "";
60
+ }
61
+ class DataFilter {
62
+ constructor(rules, state) {
63
+ __publicField(this, "filters");
64
+ __publicField(this, "filterPublic", () => {
65
+ return (v) => {
66
+ const isPublic = !this.rules.isPrivate(v.element);
67
+ return {
68
+ tag: "filter-public",
69
+ condition: this.state.filterPublic && isPublic
70
+ };
71
+ };
72
+ });
73
+ __publicField(this, "filterPrivate", () => {
74
+ return (v) => {
75
+ const isPrivate = this.rules.isPrivate(v.element);
76
+ return {
77
+ tag: "filter-private",
78
+ condition: this.state.filterPrivate && isPrivate
79
+ };
80
+ };
81
+ });
82
+ __publicField(this, "filterHD", () => {
83
+ return (v) => {
84
+ const isHD = this.rules.isHD(v.element);
85
+ return {
86
+ tag: "filter-hd",
87
+ condition: this.state.filterHD && isHD
88
+ };
89
+ };
90
+ });
91
+ __publicField(this, "filterDuration", () => {
92
+ return (v) => {
93
+ const notInRange = v.duration < this.state.filterDurationFrom || v.duration > this.state.filterDurationTo;
94
+ return {
95
+ tag: "filter-duration",
96
+ condition: this.state.filterDuration && notInRange
97
+ };
98
+ };
99
+ });
100
+ __publicField(this, "filterExclude", () => {
101
+ const tags = DataManager.filterDSLToRegex(this.state.filterExcludeWords);
102
+ return (v) => {
103
+ const containTags = tags.some((tag) => tag.test(v.title));
104
+ return {
105
+ tag: "filter-exclude",
106
+ condition: this.state.filterExclude && containTags
107
+ };
108
+ };
109
+ });
110
+ __publicField(this, "filterInclude", () => {
111
+ const tags = DataManager.filterDSLToRegex(this.state.filterIncludeWords);
112
+ return (v) => {
113
+ const containTagsNot = tags.some((tag) => !tag.test(v.title));
114
+ return {
115
+ tag: "filter-include",
116
+ condition: this.state.filterInclude && containTagsNot
117
+ };
118
+ };
119
+ });
120
+ this.rules = rules;
121
+ this.state = state;
122
+ this.state = state;
123
+ const methods = Object.getOwnPropertyNames(this);
124
+ this.filters = methods.reduce((acc, k) => {
125
+ if (k in this.state) {
126
+ acc[k] = this[k];
127
+ GM_addStyle(`.filter-${k.toLowerCase().slice(6)} { display: none !important; }`);
128
+ }
129
+ return acc;
130
+ }, {});
131
+ }
132
+ }
133
+ class DataManager {
134
+ constructor(rules, state) {
135
+ __publicField(this, "rules");
136
+ __publicField(this, "state");
137
+ __publicField(this, "data");
138
+ __publicField(this, "lazyImgLoader");
139
+ __publicField(this, "dataFilters");
140
+ __publicField(this, "applyFilters", (filters, offset = 0) => {
141
+ const filtersToApply = Object.keys(filters).filter((k) => Object.hasOwn(this.dataFilters, k)).map((k) => this.dataFilters[k]());
142
+ if (filtersToApply.length === 0) return;
143
+ const updates = [];
144
+ let offset_counter = 1;
145
+ for (const v of this.data.values()) {
146
+ if (++offset_counter > offset) {
147
+ for (const f of filtersToApply) {
148
+ const { tag, condition } = f(v);
149
+ updates.push(() => v.element.classList.toggle(tag, condition));
150
+ }
151
+ }
152
+ }
153
+ requestAnimationFrame(() => {
154
+ updates.forEach((update) => {
155
+ update();
156
+ });
157
+ });
158
+ });
159
+ __publicField(this, "filterAll", (offset) => {
160
+ const filters = Object.assign(
161
+ {},
162
+ ...Object.keys(this.dataFilters).map((f) => ({
163
+ [f]: this.state[f]
164
+ }))
165
+ );
166
+ this.applyFilters(filters, offset);
167
+ });
168
+ __publicField(this, "parseData", (html, container, removeDuplicates = false, shouldLazify = true) => {
169
+ const thumbs = this.rules.getThumbs(html);
170
+ const data_offset = this.data.size;
171
+ for (const thumbElement of thumbs) {
172
+ const url = this.rules.getThumbUrl(thumbElement);
173
+ if (!url || this.data.has(url)) {
174
+ if (removeDuplicates) thumbElement.remove();
175
+ continue;
176
+ }
177
+ const data = this.rules.getThumbData(thumbElement);
178
+ this.data.set(url, { element: thumbElement, ...data });
179
+ if (shouldLazify) {
180
+ const { img, imgSrc } = this.rules.getThumbImgData(thumbElement);
181
+ this.lazyImgLoader.lazify(thumbElement, img, imgSrc);
182
+ }
183
+ const parent = container || this.rules.container;
184
+ if (!parent.contains(thumbElement)) parent.appendChild(thumbElement);
185
+ }
186
+ this.filterAll(data_offset);
187
+ });
188
+ this.rules = rules;
189
+ this.state = state;
190
+ this.data = /* @__PURE__ */ new Map();
191
+ this.lazyImgLoader = new LazyImgLoader(
192
+ (target) => !this.isFiltered(target)
193
+ );
194
+ this.dataFilters = new DataFilter(rules, state).filters;
195
+ const targets = [window, globalThis.unsafeWindow].filter(Boolean);
196
+ targets.forEach((w) => {
197
+ Object.assign(w, {
198
+ sortByViews: () => this.sort("view"),
199
+ sortByDuration: () => this.sort("duration")
200
+ });
201
+ });
202
+ }
203
+ static filterDSLToRegex(str) {
204
+ const toFullWord = (w) => `(^|\\ )${w}($|\\ )`;
205
+ const str_ = str.replace(/f:(\w+)/g, (_, w) => toFullWord(w));
206
+ return stringToWords(str_).map((expr) => new RegExp(expr, "i"));
207
+ }
208
+ isFiltered(el) {
209
+ return el.className.includes("filtered");
210
+ }
211
+ sort(propName) {
212
+ if (this.data.size < 2) return;
213
+ const sorted = Array.from(this.data.keys()).sort((b, a) => {
214
+ return this.data.get(a)[propName] - this.data.get(b)[propName];
215
+ });
216
+ const container = this.data.get(sorted[0]).element.parentElement;
217
+ sorted.forEach((s) => {
218
+ const e = this.data.get(s).element;
219
+ container.append(e);
220
+ });
221
+ }
97
222
  }
98
223
  function parseDom(html) {
99
224
  const parsed = new DOMParser().parseFromString(html, "text/html").body;
@@ -203,37 +328,94 @@ function objectToFormData(object) {
203
328
  Object.entries(object).forEach(([k, v]) => formData.append(k, v));
204
329
  return formData;
205
330
  }
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");
331
+ class InfiniteScroller {
332
+ constructor({
333
+ enabled = true,
334
+ delay = 350,
335
+ writeHistory = false,
336
+ paginationOffset,
337
+ paginationLast,
338
+ paginationElement,
339
+ paginationUrlGenerator,
340
+ handleHtmlCallback,
341
+ alternativeGenerator,
342
+ intersectionObservable
343
+ }) {
344
+ __publicField(this, "paginationGenerator");
345
+ __publicField(this, "enabled");
346
+ __publicField(this, "delay");
347
+ __publicField(this, "paginationOffset");
348
+ __publicField(this, "paginationLast");
349
+ __publicField(this, "writeHistory");
350
+ __publicField(this, "handleHtmlCallback");
351
+ __publicField(this, "onScrollCBs", []);
352
+ __publicField(this, "generatorConsumer", async () => {
353
+ if (!this.enabled) return false;
354
+ const { value: { url, offset } = {}, done } = await this.paginationGenerator.next();
355
+ if (!done) {
356
+ const nextPageHTML = await fetchHtml(url);
357
+ const prevScrollPos = document.documentElement.scrollTop;
358
+ this.paginationOffset = offset;
359
+ this.handleHtmlCallback(nextPageHTML);
360
+ this._onScroll();
361
+ window.scrollTo(0, prevScrollPos);
362
+ if (this.writeHistory) {
363
+ history.replaceState({}, "", url);
364
+ }
365
+ }
366
+ return !done;
367
+ });
368
+ this.enabled = enabled;
215
369
  this.delay = delay;
216
- this.startImmediate = startImmediate;
370
+ this.writeHistory = writeHistory;
371
+ this.paginationOffset = paginationOffset;
372
+ this.paginationLast = paginationLast;
373
+ this.handleHtmlCallback = handleHtmlCallback;
374
+ this.paginationGenerator = alternativeGenerator?.() ?? InfiniteScroller.createPaginationGenerator(
375
+ paginationOffset,
376
+ paginationLast,
377
+ paginationUrlGenerator
378
+ );
379
+ const observable = intersectionObservable || paginationElement;
380
+ Observer.observeWhile(observable, this.generatorConsumer, this.delay);
217
381
  }
218
- start(callback, callbackFinal) {
219
- this.stop();
220
- this.callbackFinal = callbackFinal;
221
- if (this.startImmediate) callback();
222
- this.tick = window.setInterval(callback, this.delay);
382
+ onScroll(callback, initCall = false) {
383
+ if (initCall) callback(this);
384
+ this.onScrollCBs.push(callback);
385
+ return this;
223
386
  }
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;
387
+ _onScroll() {
388
+ this.onScrollCBs.forEach((cb) => {
389
+ cb(this);
390
+ });
391
+ }
392
+ static *createPaginationGenerator(currentPage, totalPages, generateURL) {
393
+ for (let offset = currentPage + 1; offset <= totalPages; offset++) {
394
+ const url = generateURL(offset);
395
+ yield { url, offset };
232
396
  }
233
397
  }
234
398
  }
235
- function isMob() {
236
- return /iPhone|Android/i.test(navigator.userAgent);
399
+ function createInfiniteScroller(store, handleHtmlCallback, rules) {
400
+ const enabled = store.state.infiniteScrollEnabled;
401
+ const iscroller = new InfiniteScroller({
402
+ enabled,
403
+ handleHtmlCallback,
404
+ ...rules
405
+ }).onScroll(({ paginationLast, paginationOffset }) => {
406
+ store.localState.pagIndexLast = paginationLast;
407
+ store.localState.pagIndexCur = paginationOffset;
408
+ }, true);
409
+ store.subscribe(() => {
410
+ iscroller.enabled = store.state.infiniteScrollEnabled;
411
+ });
412
+ return iscroller;
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);
237
419
  }
238
420
  async function computeAsyncOneAtTime(iterable) {
239
421
  const res = [];
@@ -296,368 +478,74 @@ class AsyncPool {
296
478
  this.pool.push("p" in x ? x : { v: x, p: 0 });
297
479
  }
298
480
  }
299
- function chunks(arr, n) {
300
- return Array.from({ length: Math.ceil(arr.length / n) }, (_, i) => arr.slice(i * n, i * n + n));
301
- }
302
- function range(size, startAt = 1, step = 1) {
303
- return Array.from({ length: size }, (_, index) => startAt + index * step);
304
- }
305
- class DataFilter {
306
- constructor(rules, state) {
307
- __publicField(this, "state");
308
- __publicField(this, "rules");
309
- __publicField(this, "filters");
310
- __publicField(this, "filterPublic", () => {
311
- return (v) => {
312
- const isPublic = !this.rules.IS_PRIVATE(v.element);
313
- return {
314
- tag: "filter-public",
315
- condition: this.state.filterPublic && isPublic
316
- };
317
- };
318
- });
319
- __publicField(this, "filterPrivate", () => {
320
- return (v) => {
321
- const isPrivate = this.rules.IS_PRIVATE(v.element);
322
- return {
323
- tag: "filter-private",
324
- condition: this.state.filterPrivate && isPrivate
325
- };
326
- };
327
- });
328
- __publicField(this, "filterHD", () => {
329
- return (v) => {
330
- const isHD = this.rules.IS_HD(v.element);
331
- return {
332
- tag: "filter-hd",
333
- condition: this.state.filterHD && isHD
334
- };
335
- };
336
- });
337
- __publicField(this, "filterDuration", () => {
338
- return (v) => {
339
- const notInRange = v.duration < this.state.filterDurationFrom || v.duration > this.state.filterDurationTo;
340
- return {
341
- tag: "filter-duration",
342
- condition: this.state.filterDuration && notInRange
343
- };
344
- };
345
- });
346
- __publicField(this, "filterExclude", () => {
347
- const tags = DataManager.filterDSLToRegex(this.state.filterExcludeWords);
348
- return (v) => {
349
- const containTags = tags.some((tag) => tag.test(v.title));
350
- return {
351
- tag: "filter-exclude",
352
- condition: this.state.filterExclude && containTags
353
- };
354
- };
355
- });
356
- __publicField(this, "filterInclude", () => {
357
- const tags = DataManager.filterDSLToRegex(this.state.filterIncludeWords);
358
- return (v) => {
359
- const containTagsNot = tags.some((tag) => !tag.test(v.title));
360
- return {
361
- tag: "filter-include",
362
- condition: this.state.filterInclude && containTagsNot
363
- };
364
- };
365
- });
366
- this.state = state;
367
- this.rules = rules;
368
- const methods = Object.getOwnPropertyNames(this);
369
- this.filters = methods.reduce((acc, k) => {
370
- if (k in this.state) {
371
- acc[k] = this[k];
372
- GM_addStyle(`.filter-${k.toLowerCase().slice(6)} { display: none !important; }`);
373
- }
374
- return acc;
375
- }, {});
376
- }
481
+ function isMob() {
482
+ return /iPhone|Android/i.test(navigator.userAgent);
377
483
  }
378
- class DataManager {
379
- constructor(rules, state) {
380
- __publicField(this, "rules");
381
- __publicField(this, "state");
382
- __publicField(this, "data");
383
- __publicField(this, "lazyImgLoader");
384
- __publicField(this, "dataFilters");
385
- __publicField(this, "applyFilters", (filters, offset = 0) => {
386
- const filtersToApply = Object.keys(filters).filter((k) => Object.hasOwn(this.dataFilters, k)).map((k) => this.dataFilters[k]());
387
- if (filtersToApply.length === 0) return;
388
- const updates = [];
389
- let offset_counter = 1;
390
- for (const v of this.data.values()) {
391
- if (++offset_counter > offset) {
392
- for (const f of filtersToApply) {
393
- const { tag, condition } = f(v);
394
- updates.push(() => v.element.classList.toggle(tag, condition));
395
- }
396
- }
397
- }
398
- requestAnimationFrame(() => {
399
- updates.forEach((update) => update());
400
- });
401
- });
402
- __publicField(this, "filterAll", (offset) => {
403
- const filters = Object.assign(
404
- {},
405
- ...Object.keys(this.dataFilters).map((f) => ({
406
- [f]: this.state[f]
407
- }))
408
- );
409
- this.applyFilters(filters, offset);
410
- });
411
- __publicField(this, "parseData", (html, container, removeDuplicates = false, shouldLazify = true) => {
412
- const thumbs = this.rules.GET_THUMBS(html);
413
- const data_offset = this.data.size;
414
- for (const thumbElement of thumbs) {
415
- const url = this.rules.THUMB_URL(thumbElement);
416
- if (!url || this.data.has(url)) {
417
- if (removeDuplicates) thumbElement.remove();
418
- continue;
419
- }
420
- const data = this.rules.THUMB_DATA(thumbElement);
421
- this.data.set(url, { element: thumbElement, ...data });
422
- if (shouldLazify) {
423
- const { img, imgSrc } = this.rules.THUMB_IMG_DATA(thumbElement);
424
- this.lazyImgLoader.lazify(thumbElement, img, imgSrc);
425
- }
426
- const parent = container || this.rules.CONTAINER;
427
- if (!parent.contains(thumbElement)) parent.appendChild(thumbElement);
428
- }
429
- this.filterAll(data_offset);
430
- });
431
- this.rules = rules;
432
- this.state = state;
433
- this.data = /* @__PURE__ */ new Map();
434
- this.lazyImgLoader = new LazyImgLoader(
435
- (target) => !this.isFiltered(target)
436
- );
437
- this.dataFilters = new DataFilter(rules, state).filters;
438
- [window, unsafeWindow || {}].forEach((w) => {
439
- Object.assign(w, {
440
- sortByViews: () => this.sort("view"),
441
- sortByDuration: () => this.sort("duration")
442
- });
443
- });
444
- }
445
- static filterDSLToRegex(str) {
446
- const toFullWord = (w) => `(^|\\ )${w}($|\\ )`;
447
- const str_ = str.replace(/f\:(\w+)/g, (_, w) => toFullWord(w));
448
- return stringToWords(str_).map((expr) => new RegExp(expr, "i"));
449
- }
450
- isFiltered(el) {
451
- return el.className.includes("filtered");
452
- }
453
- sort(propName) {
454
- if (this.data.size < 2) return;
455
- const sorted = Array.from(this.data.keys()).sort((b, a) => {
456
- return this.data.get(a)[propName] - this.data.get(b)[propName];
457
- });
458
- const container = this.data.get(sorted[0]).element.parentElement;
459
- sorted.forEach((s) => {
460
- const e = this.data.get(s).element;
461
- container.append(e);
462
- });
484
+ function listenEvents(dom, events, callback) {
485
+ for (const e of events) {
486
+ dom.addEventListener(e, callback, true);
463
487
  }
464
488
  }
465
- class InfiniteScroller {
466
- constructor({
467
- enabled = true,
468
- delay = 350,
469
- writeHistory = false,
470
- paginationOffset,
471
- paginationLast,
472
- paginationElement,
473
- paginationUrlGenerator,
474
- handleHtmlCallback,
475
- alternativeGenerator,
476
- intersectionObservable
477
- }) {
478
- __publicField(this, "paginationGenerator");
479
- __publicField(this, "enabled");
480
- __publicField(this, "delay");
481
- __publicField(this, "paginationOffset");
482
- __publicField(this, "paginationLast");
483
- __publicField(this, "writeHistory");
484
- __publicField(this, "handleHtmlCallback");
485
- __publicField(this, "onScrollCBs", []);
486
- __publicField(this, "generatorConsumer", async () => {
487
- if (!this.enabled) return false;
488
- const {
489
- value: { url, offset } = {},
490
- done
491
- } = await this.paginationGenerator.next();
492
- if (!done) {
493
- const nextPageHTML = await fetchHtml(url);
494
- const prevScrollPos = document.documentElement.scrollTop;
495
- this.paginationOffset = offset;
496
- this.handleHtmlCallback(nextPageHTML);
497
- this._onScroll();
498
- window.scrollTo(0, prevScrollPos);
499
- if (this.writeHistory) {
500
- history.replaceState({}, "", url);
501
- }
502
- }
503
- return !done;
504
- });
505
- this.enabled = enabled;
489
+ class Tick {
490
+ constructor(delay, startImmediate = true) {
491
+ __publicField(this, "tick");
492
+ __publicField(this, "callbackFinal");
506
493
  this.delay = delay;
507
- this.writeHistory = writeHistory;
508
- this.paginationOffset = paginationOffset;
509
- this.paginationLast = paginationLast;
510
- this.handleHtmlCallback = handleHtmlCallback;
511
- this.paginationGenerator = alternativeGenerator?.() ?? InfiniteScroller.createPaginationGenerator(
512
- paginationOffset,
513
- paginationLast,
514
- paginationUrlGenerator
515
- );
516
- const observable = intersectionObservable || paginationElement;
517
- Observer.observeWhile(observable, this.generatorConsumer, this.delay);
518
- }
519
- onScroll(callback, initCall = false) {
520
- if (initCall) callback(this);
521
- this.onScrollCBs.push(callback);
522
- return this;
494
+ this.startImmediate = startImmediate;
523
495
  }
524
- _onScroll() {
525
- this.onScrollCBs.forEach((cb) => cb(this));
496
+ start(callback, callbackFinal) {
497
+ this.stop();
498
+ this.callbackFinal = callbackFinal;
499
+ if (this.startImmediate) callback();
500
+ this.tick = window.setInterval(callback, this.delay);
526
501
  }
527
- static *createPaginationGenerator(currentPage, totalPages, generateURL) {
528
- for (let offset = currentPage + 1; offset <= totalPages; offset++) {
529
- const url = generateURL(offset);
530
- yield { url, offset };
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;
531
510
  }
532
511
  }
533
512
  }
534
- function createInfiniteScroller(store, handleHtmlCallback, rules) {
535
- const enabled = store.state.infiniteScrollEnabled;
536
- const iscroller = new InfiniteScroller({
537
- enabled,
538
- handleHtmlCallback,
539
- ...rules
540
- }).onScroll(({ paginationLast, paginationOffset }) => {
541
- store.localState.pagIndexLast = paginationLast;
542
- store.localState.pagIndexCur = paginationOffset;
543
- }, true);
544
- store.subscribe(() => {
545
- iscroller.enabled = store.state.infiniteScrollEnabled;
546
- });
547
- return iscroller;
513
+ function circularShift(n, c = 6, s = 1) {
514
+ return (n + s) % c || c;
548
515
  }
549
- class RulesHelper {
550
- constructor(options) {
551
- __publicField(this, "delay", 250);
552
- __publicField(this, "IS_VIDEO_PAGE");
553
- __publicField(this, "IS_SEARCH_PAGE");
554
- __publicField(this, "paginationElement");
555
- __publicField(this, "paginationOffset");
556
- __publicField(this, "paginationLast");
557
- __publicField(this, "URL_DATA");
558
- __publicField(this, "paginationUrlGenerator", (offset) => {
559
- const opt = this.options.paginationUrlGenerator;
560
- if (typeof opt === "function") return opt(offset);
561
- const url = new URL(location.href);
562
- if (opt.searchPage) {
563
- url.searchParams.set(opt.searchPage, offset.toString());
564
- return url.href;
565
- }
566
- if (opt.pathnameLast) {
567
- if (url.pathname === "/") url.pathname = "/1";
568
- if (/\d+$/.test(url.pathname)) {
569
- url.pathname = url.pathname.replace(/\d+$/, offset.toString());
570
- } else {
571
- url.pathname = `${url.pathname}/${offset}`;
572
- }
573
- return url.href;
574
- }
575
- return url.href;
576
- });
577
- __publicField(this, "_IS_VIDEO_PAGE", () => {
578
- if (typeof this.options.IS_VIDEO_PAGE === "boolean") {
579
- return this.options.IS_VIDEO_PAGE;
580
- }
581
- return this.options.IS_VIDEO_PAGE.test(location.pathname);
582
- });
583
- __publicField(this, "_IS_SEARCH_PAGE", () => {
584
- if (typeof this.options.IS_SEARCH_PAGE === "boolean") {
585
- return this.options.IS_SEARCH_PAGE;
586
- }
587
- return this.options.IS_SEARCH_PAGE.test(location.pathname);
588
- });
589
- __publicField(this, "_paginationElement", (html = document) => {
590
- if (typeof this.options.paginationElement === "function") {
591
- return this.options.paginationElement(html);
592
- }
593
- return [...html.querySelectorAll(this.options.paginationElement)].pop();
594
- });
595
- __publicField(this, "CONTAINER", (html = document) => {
596
- if (typeof this.options.CONTAINER === "function") {
597
- return this.options.CONTAINER(html);
598
- }
599
- return [...html.querySelectorAll(this.options.CONTAINER)].pop();
600
- });
601
- __publicField(this, "THUMB_URL", (thumb) => {
602
- if (typeof this.options.THUMB_URL === "string") {
603
- return thumb.querySelector(this.options.THUMB_URL).href || "";
604
- }
605
- return this.options.THUMB_URL(thumb);
606
- });
607
- __publicField(this, "GET_THUMBS", (html) => {
608
- if (typeof this.options.GET_THUMBS === "string") {
609
- return [...html.querySelectorAll(this.options.GET_THUMBS)];
610
- }
611
- return this.options.GET_THUMBS(html);
612
- });
613
- __publicField(this, "THUMB_DATA", (thumb) => {
614
- const opt = this.options.THUMB_DATA;
615
- if (typeof opt === "function") return opt(thumb);
616
- let title = sanitizeStr(thumb.querySelector(opt.title)?.innerText || "");
617
- if (opt.uploader) {
618
- const uploader = sanitizeStr(
619
- thumb.querySelector(opt.title)?.innerText || ""
620
- );
621
- title = `${title} user:${uploader}`;
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
+ });
622
542
  }
623
- const duration = !opt.duration ? 0 : timeToSeconds(
624
- sanitizeStr(thumb.querySelector(opt.duration)?.innerText || "")
625
- );
626
- return { title, duration };
627
- });
628
- __publicField(this, "THUMB_IMG_DATA", (thumb) => {
629
- const opt = this.options.THUMB_IMG_DATA;
630
- if (typeof opt === "function") return opt(thumb);
631
- const result = {};
632
- if (opt.img) {
633
- const img = thumb.querySelector(opt.img);
634
- const imgSrc = img.getAttribute(opt.imgSrc || "data-src") || img.getAttribute("src");
635
- if (opt.lazyloading) {
636
- img.classList.remove(opt.lazyloading);
637
- }
638
- Object.assign(result, { img, imgSrc });
639
- if (img.complete && img.getAttribute("src") && !img.src.includes("data:image")) {
640
- return {};
641
- }
642
- } else return {};
643
- });
644
- this.options = options;
645
- this.delay = options?.delay || this.delay;
646
- this.paginationOffset = this.options.paginationOffset;
647
- this.paginationLast = this.options.paginationLast;
648
- this.IS_VIDEO_PAGE = this._IS_VIDEO_PAGE();
649
- this.IS_SEARCH_PAGE = this._IS_SEARCH_PAGE();
650
- this.paginationElement = this._paginationElement();
651
- if (options.URL_DATA) {
652
- this.URL_DATA = options.URL_DATA;
653
- Object.assign(this, this.URL_DATA());
654
543
  }
655
- }
656
- router(store, handleHtmlCallback) {
657
- if (!this.options.router) return;
658
- const scroller = createInfiniteScroller(store, handleHtmlCallback, this);
659
- this.options.router(this, store, handleHtmlCallback, scroller);
660
- }
544
+ return acc;
545
+ }, {});
546
+ }
547
+ function parseCSSUrl(s) {
548
+ return s.replace(/url\("|\"\).*/g, "");
661
549
  }
662
550
  export {
663
551
  AsyncPool,
@@ -666,7 +554,6 @@ export {
666
554
  LazyImgLoader,
667
555
  MOBILE_UA,
668
556
  Observer,
669
- RulesHelper,
670
557
  Tick,
671
558
  chunks,
672
559
  circularShift,