billy-herrington-utils 1.2.0 → 1.3.0
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 +209 -1
- package/dist/billy-herrington-utils.es.js.map +1 -1
- package/dist/billy-herrington-utils.umd.js +209 -1
- package/dist/billy-herrington-utils.umd.js.map +1 -1
- package/dist/index.d.ts +91 -3
- package/package.json +1 -1
- package/src/data-manager/index.ts +198 -0
- package/src/index.ts +13 -11
- package/src/utils/fetch/index.ts +13 -7
- package/src/utils/infinite-scroll/index.ts +102 -0
- package/src/utils/observers/index.ts +6 -2
|
@@ -147,10 +147,16 @@ function watchElementChildrenCount(element, callback) {
|
|
|
147
147
|
});
|
|
148
148
|
observer.observe(element, { childList: true });
|
|
149
149
|
}
|
|
150
|
-
function watchDomChangesWithThrottle(element, callback, throttle = 1e3, options = { childList: true, subtree: true, attributes: true }) {
|
|
150
|
+
function watchDomChangesWithThrottle(element, callback, throttle = 1e3, times = Infinity, options = { childList: true, subtree: true, attributes: true }) {
|
|
151
151
|
let lastMutationTime;
|
|
152
152
|
let timeout;
|
|
153
|
+
let times_ = times;
|
|
153
154
|
const observer = new MutationObserver((_mutationList, _observer) => {
|
|
155
|
+
if (times_ !== Infinity && times_ < 1) {
|
|
156
|
+
observer.disconnect();
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
times_--;
|
|
154
160
|
const now = Date.now();
|
|
155
161
|
if (lastMutationTime && now - lastMutationTime < throttle) {
|
|
156
162
|
timeout && clearTimeout(timeout);
|
|
@@ -159,6 +165,7 @@ function watchDomChangesWithThrottle(element, callback, throttle = 1e3, options
|
|
|
159
165
|
lastMutationTime = now;
|
|
160
166
|
});
|
|
161
167
|
observer.observe(element, options);
|
|
168
|
+
return observer;
|
|
162
169
|
}
|
|
163
170
|
function downloader(options = { append: "", after: "", button: "", cbBefore: () => {
|
|
164
171
|
} }) {
|
|
@@ -289,8 +296,209 @@ function chunks(arr, n) {
|
|
|
289
296
|
function range(size, startAt = 1, step = 1) {
|
|
290
297
|
return Array.from({ length: size }, (_, index) => startAt + index * step);
|
|
291
298
|
}
|
|
299
|
+
class DataFilter {
|
|
300
|
+
constructor(rules, state) {
|
|
301
|
+
__publicField(this, "state");
|
|
302
|
+
__publicField(this, "rules");
|
|
303
|
+
__publicField(this, "filters");
|
|
304
|
+
__publicField(this, "filterPublic", () => {
|
|
305
|
+
return (v) => {
|
|
306
|
+
const isPublic = !this.rules.IS_PRIVATE(v.element);
|
|
307
|
+
return {
|
|
308
|
+
tag: "filter-public",
|
|
309
|
+
condition: this.state.filterPublic && isPublic
|
|
310
|
+
};
|
|
311
|
+
};
|
|
312
|
+
});
|
|
313
|
+
__publicField(this, "filterPrivate", () => {
|
|
314
|
+
return (v) => {
|
|
315
|
+
const isPrivate = this.rules.IS_PRIVATE(v.element);
|
|
316
|
+
return {
|
|
317
|
+
tag: "filter-private",
|
|
318
|
+
condition: this.state.filterPrivate && isPrivate
|
|
319
|
+
};
|
|
320
|
+
};
|
|
321
|
+
});
|
|
322
|
+
__publicField(this, "filterDuration", () => {
|
|
323
|
+
return (v) => {
|
|
324
|
+
const notInRange = v.duration < this.state.filterDurationFrom || v.duration > this.state.filterDurationTo;
|
|
325
|
+
return {
|
|
326
|
+
tag: "filter-duration",
|
|
327
|
+
condition: this.state.filterDuration && notInRange
|
|
328
|
+
};
|
|
329
|
+
};
|
|
330
|
+
});
|
|
331
|
+
__publicField(this, "filterExclude", () => {
|
|
332
|
+
const tags = DataManager.filterDSLToRegex(this.state.filterExcludeWords);
|
|
333
|
+
return (v) => {
|
|
334
|
+
const containTags = tags.some((tag) => tag.test(v.title));
|
|
335
|
+
return {
|
|
336
|
+
tag: "filter-exclude",
|
|
337
|
+
condition: this.state.filterExclude && containTags
|
|
338
|
+
};
|
|
339
|
+
};
|
|
340
|
+
});
|
|
341
|
+
__publicField(this, "filterInclude", () => {
|
|
342
|
+
const tags = DataManager.filterDSLToRegex(this.state.filterIncludeWords);
|
|
343
|
+
return (v) => {
|
|
344
|
+
const containTagsNot = tags.some((tag) => !tag.test(v.title));
|
|
345
|
+
return {
|
|
346
|
+
tag: "filter-include",
|
|
347
|
+
condition: this.state.filterInclude && containTagsNot
|
|
348
|
+
};
|
|
349
|
+
};
|
|
350
|
+
});
|
|
351
|
+
this.state = state;
|
|
352
|
+
this.rules = rules;
|
|
353
|
+
const methods = Object.getOwnPropertyNames(this);
|
|
354
|
+
this.filters = methods.reduce((acc, k) => {
|
|
355
|
+
if (k in this.state) {
|
|
356
|
+
acc[k] = this[k];
|
|
357
|
+
GM_addStyle(`.filter-${k.toLowerCase().slice(6)} { display: none !important; }`);
|
|
358
|
+
}
|
|
359
|
+
return acc;
|
|
360
|
+
}, {});
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
class DataManager {
|
|
364
|
+
constructor(rules, state) {
|
|
365
|
+
__publicField(this, "rules");
|
|
366
|
+
__publicField(this, "state");
|
|
367
|
+
__publicField(this, "data");
|
|
368
|
+
__publicField(this, "lazyImgLoader");
|
|
369
|
+
__publicField(this, "dataFilters");
|
|
370
|
+
__publicField(this, "applyFilters", (filters, offset = 0) => {
|
|
371
|
+
const filtersToApply = Object.keys(filters).filter((k) => Object.hasOwn(this.dataFilters, k)).map((k) => this.dataFilters[k]());
|
|
372
|
+
if (filtersToApply.length === 0) return;
|
|
373
|
+
const updates = [];
|
|
374
|
+
let offset_counter = 1;
|
|
375
|
+
for (const v of this.data.values()) {
|
|
376
|
+
if (++offset_counter > offset) {
|
|
377
|
+
for (const f of filtersToApply) {
|
|
378
|
+
const { tag, condition } = f(v);
|
|
379
|
+
updates.push(() => v.element.classList.toggle(tag, condition));
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
requestAnimationFrame(() => {
|
|
384
|
+
updates.forEach((update) => update());
|
|
385
|
+
});
|
|
386
|
+
});
|
|
387
|
+
__publicField(this, "filterAll", (offset) => {
|
|
388
|
+
const filters = Object.assign(
|
|
389
|
+
{},
|
|
390
|
+
...Object.keys(this.dataFilters).map((f) => ({
|
|
391
|
+
[f]: this.state[f]
|
|
392
|
+
}))
|
|
393
|
+
);
|
|
394
|
+
this.applyFilters(filters, offset);
|
|
395
|
+
});
|
|
396
|
+
__publicField(this, "handleLoadedHTML", (html, container, removeDuplicates = false, shouldLazify = true) => {
|
|
397
|
+
const thumbs = this.rules.GET_THUMBS(html);
|
|
398
|
+
const data_offset = this.data.size;
|
|
399
|
+
for (const thumbElement of thumbs) {
|
|
400
|
+
const url = this.rules.THUMB_URL(thumbElement);
|
|
401
|
+
if (!url || this.data.has(url)) {
|
|
402
|
+
if (removeDuplicates) thumbElement.remove();
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
const { title, duration } = this.rules.THUMB_DATA(thumbElement);
|
|
406
|
+
this.data.set(url, { element: thumbElement, duration, title });
|
|
407
|
+
if (shouldLazify) {
|
|
408
|
+
const { img, imgSrc } = this.rules.THUMB_IMG_DATA(thumbElement);
|
|
409
|
+
this.lazyImgLoader.lazify(thumbElement, img, imgSrc);
|
|
410
|
+
}
|
|
411
|
+
const parent = container || this.rules.CONTAINER;
|
|
412
|
+
if (!parent.contains(thumbElement)) parent.appendChild(thumbElement);
|
|
413
|
+
}
|
|
414
|
+
this.filterAll(data_offset);
|
|
415
|
+
});
|
|
416
|
+
this.rules = rules;
|
|
417
|
+
this.state = state;
|
|
418
|
+
this.data = /* @__PURE__ */ new Map();
|
|
419
|
+
this.lazyImgLoader = new LazyImgLoader(
|
|
420
|
+
(target) => !this.isFiltered(target)
|
|
421
|
+
);
|
|
422
|
+
this.dataFilters = new DataFilter(rules, state).filters;
|
|
423
|
+
}
|
|
424
|
+
static filterDSLToRegex(str) {
|
|
425
|
+
const toFullWord = (w) => `(^|\\ )${w}($|\\ )`;
|
|
426
|
+
const str_ = str.replace(/f\:(\w+)/g, (_, w) => toFullWord(w));
|
|
427
|
+
return stringToWords(str_).map((expr) => new RegExp(expr, "i"));
|
|
428
|
+
}
|
|
429
|
+
isFiltered(el) {
|
|
430
|
+
return el.className.includes("filtered");
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
class InfiniteScroller {
|
|
434
|
+
constructor({
|
|
435
|
+
enabled,
|
|
436
|
+
handleHtmlCallback,
|
|
437
|
+
delay,
|
|
438
|
+
alternativeGenerator,
|
|
439
|
+
paginationOffset,
|
|
440
|
+
paginationLast,
|
|
441
|
+
paginationElement,
|
|
442
|
+
paginationUrlGenerator,
|
|
443
|
+
intersectionObservable
|
|
444
|
+
}) {
|
|
445
|
+
__publicField(this, "paginationGenerator");
|
|
446
|
+
__publicField(this, "enabled");
|
|
447
|
+
__publicField(this, "delay");
|
|
448
|
+
__publicField(this, "paginationOffset");
|
|
449
|
+
__publicField(this, "paginationLast");
|
|
450
|
+
__publicField(this, "handleHtmlCallback");
|
|
451
|
+
// this.stateLocale.pagIndexLast = paginationLast;
|
|
452
|
+
// this.stateLocale.pagIndexCur = paginationOffset;
|
|
453
|
+
// infiniteScrollEnabled: boolean;
|
|
454
|
+
__publicField(this, "onScrollCBs", []);
|
|
455
|
+
__publicField(this, "generatorConsumer", async () => {
|
|
456
|
+
if (!this.enabled) return false;
|
|
457
|
+
const {
|
|
458
|
+
value: { url, offset } = {},
|
|
459
|
+
done
|
|
460
|
+
} = await this.paginationGenerator.next();
|
|
461
|
+
if (!done) {
|
|
462
|
+
const nextPageHTML = await fetchHtml(url);
|
|
463
|
+
const prevScrollPos = document.documentElement.scrollTop;
|
|
464
|
+
this.paginationOffset = offset;
|
|
465
|
+
this.handleHtmlCallback(nextPageHTML);
|
|
466
|
+
this._onScroll();
|
|
467
|
+
window.scrollTo(0, prevScrollPos);
|
|
468
|
+
}
|
|
469
|
+
return !done;
|
|
470
|
+
});
|
|
471
|
+
this.enabled = enabled;
|
|
472
|
+
this.delay = delay;
|
|
473
|
+
this.paginationOffset = paginationOffset;
|
|
474
|
+
this.paginationLast = paginationLast;
|
|
475
|
+
this.handleHtmlCallback = handleHtmlCallback;
|
|
476
|
+
this.paginationGenerator = alternativeGenerator?.() ?? InfiniteScroller.createPaginationGenerator(
|
|
477
|
+
paginationOffset,
|
|
478
|
+
paginationLast,
|
|
479
|
+
paginationUrlGenerator
|
|
480
|
+
);
|
|
481
|
+
const observable = intersectionObservable || paginationElement;
|
|
482
|
+
Observer.observeWhile(observable, this.generatorConsumer, this.delay);
|
|
483
|
+
}
|
|
484
|
+
onScroll(callback) {
|
|
485
|
+
this.onScrollCBs.push(callback);
|
|
486
|
+
return this;
|
|
487
|
+
}
|
|
488
|
+
_onScroll() {
|
|
489
|
+
this.onScrollCBs.forEach((cb) => cb(this));
|
|
490
|
+
}
|
|
491
|
+
static *createPaginationGenerator(currentPage, totalPages, generateURL) {
|
|
492
|
+
for (let offset = currentPage + 1; offset <= totalPages; offset++) {
|
|
493
|
+
const url = generateURL(offset);
|
|
494
|
+
yield { url, offset };
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
292
498
|
export {
|
|
293
499
|
AsyncPool,
|
|
500
|
+
DataManager,
|
|
501
|
+
InfiniteScroller,
|
|
294
502
|
LazyImgLoader,
|
|
295
503
|
MOBILE_UA,
|
|
296
504
|
Observer,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"billy-herrington-utils.es.js","sources":["../src/utils/strings/index.ts","../src/utils/parsers/index.ts","../src/utils/observers/index.ts","../src/utils/math/index.ts","../src/utils/dom/index.ts","../src/utils/fetch/index.ts","../src/utils/events/index.ts","../src/utils/device/index.ts","../src/utils/async/index.ts","../src/utils/arrays/index.ts"],"sourcesContent":["export function stringToWords(s: string): Array<string> {\n return s.split(\",\").map(s => s.trim().toLowerCase()).filter(_ => _);\n}\n\nexport function sanitizeStr(s: string) {\n return s?.replace(/\\n|\\t/, ' ').replace(/ {2,}/, ' ').trim().toLowerCase() || \"\";\n}\n","export function formatTimeToHHMMSS(timeString: string): string {\n const regex: RegExp = /(?:(\\d+)\\s*h\\s*)?(?:(\\d+)\\s*mi?n?\\s*)?(?:(\\d+)\\s*sec)?/;\n const match: RegExpMatchArray | null = timeString.match(regex);\n const h: number = parseInt(match?.[1] || '0');\n const m: number = parseInt(match?.[2] || '0');\n const s: number = parseInt(match?.[3] || '0');\n const pad = (num: number): string => String(num).padStart(2, '0');\n return `${pad(h)}:${pad(m)}:${pad(s)}`;\n}\n\n// \"01:22:03\" -> 4923\nexport function timeToSeconds(t: string): number {\n const r = /sec|min|h|m/.test(t) ? formatTimeToHHMMSS(t) : t;\n return (r?.match(/\\d+/gm) || [0])\n .reverse()\n .map((s, i) => parseInt(s as string) * 60 ** i)\n .reduce((a, b) => a + b);\n}\n\nexport function parseIntegerOr(n: string | number, or: number): number {\n return (num => Number.isNaN(num) ? or : num)(parseInt(n as string));\n}\n\n// \"data:02;body+head:async;void:;zero:;\"\nexport function parseDataParams(str: string): Record<string, string> {\n return str.split(';').reduce((acc, s) => {\n const parsed = s.match(/([\\+\\w]+):(\\w+)?/);\n if (parsed) {\n const [, key, value] = parsed;\n if (value) {\n key.split('+').forEach(p => { acc[p] = value; });\n }\n }\n return acc;\n }, {} as Record<string, string>);\n}\n\nexport function parseCSSUrl(s: string) {\n return s.replace(/url\\(\"|\\\"\\).*/g, '');\n}\n","export class Observer {\n public observer: IntersectionObserver;\n constructor(private callback: (entry: Element) => void) {\n this.observer = new IntersectionObserver(this.handleIntersection.bind(this));\n }\n\n observe(target: Element) {\n this.observer.observe(target);\n }\n\n throttle(target: Element, throttleTime: number) {\n this.observer.unobserve(target);\n setTimeout(() => this.observer.observe(target), throttleTime);\n }\n\n handleIntersection(entries: Iterable<IntersectionObserverEntry>) {\n for (const entry of entries) {\n if (entry.isIntersecting) {\n this.callback(entry.target);\n }\n }\n }\n\n static observeWhile(target: Element, callback: () => Promise<boolean> | boolean, throttleTime: number) {\n const observer_ = new Observer(async (target: Element) => {\n const condition = await callback();\n if (condition) observer_.throttle(target, throttleTime);\n });\n observer_.observe(target);\n return observer_;\n }\n}\n\nexport class LazyImgLoader {\n public lazyImgObserver: Observer;\n private attributeName = 'data-lazy-load';\n\n constructor(shouldDelazify: (target: Element) => boolean) {\n this.lazyImgObserver = new Observer((target: Element) => {\n if (shouldDelazify(target)) {\n this.delazify(target as HTMLImageElement);\n }\n });\n }\n\n lazify(_target: Element, img: HTMLImageElement, imgSrc: string) {\n if (!img || !imgSrc) return;\n img.setAttribute(this.attributeName, imgSrc);\n img.src = '';\n this.lazyImgObserver.observe(img);\n }\n\n delazify = (target: HTMLImageElement) => {\n this.lazyImgObserver.observer.unobserve(target);\n target.src = target.getAttribute(this.attributeName) as string;\n target.removeAttribute(this.attributeName);\n }\n}\n","export function circularShift(n: number, c = 6, s = 1): number {\n return (n + s) % c || c;\n}\n","export function parseDom(html: string): HTMLElement {\n const parsed = new DOMParser().parseFromString(html, 'text/html').body;\n return parsed.children.length > 1 ? parsed : parsed.firstElementChild as HTMLElement;\n}\n\nexport function copyAttributes(target: HTMLElement | Element, source: HTMLElement | Element) {\n for (const attr of source.attributes) {\n attr.nodeValue && target.setAttribute(attr.nodeName, attr.nodeValue);\n }\n}\n\nexport function replaceElementTag(e: HTMLElement | Element, tagName: string) {\n const newTagElement = document.createElement(tagName);\n copyAttributes(newTagElement, e);\n newTagElement.innerHTML = e.innerHTML;\n e.parentNode?.replaceChild(newTagElement, e);\n return newTagElement;\n}\n\nexport function getAllUniqueParents(elements: HTMLCollection): Array<HTMLElement | Element> {\n return Array.from(elements).reduce((acc, v) => {\n if (v.parentElement && !acc.includes(v.parentElement as HTMLElement)) { acc.push(v.parentElement); }\n return acc;\n }, [] as Array<HTMLElement | Element>);\n}\n\nexport function findNextSibling(el: HTMLElement | Element) {\n if (el.nextElementSibling) return el.nextElementSibling;\n if (el.parentElement) return findNextSibling(el.parentElement);\n return null;\n}\n\nexport function waitForElementExists(parent: HTMLElement | Element, selector: string, callback: (el: Element) => void): void {\n const observer = new MutationObserver((_mutations) => {\n const el = parent.querySelector(selector);\n if (el) {\n observer.disconnect();\n callback(el);\n }\n });\n observer.observe(document.body, { childList: true, subtree: true });\n}\n\nexport function watchElementChildrenCount(element: HTMLElement | Element,\n callback: (observer: MutationObserver, count: number) => void): void {\n let count = element.children.length;\n const observer = new MutationObserver((mutationList, observer) => {\n for (const mutation of mutationList) {\n if (mutation.type === \"childList\") {\n if (count !== element.children.length) {\n count = element.children.length;\n callback(observer, count);\n }\n }\n }\n });\n observer.observe(element, { childList: true });\n}\n\nexport function watchDomChangesWithThrottle(element: HTMLElement | Element, callback: () => void,\n throttle = 1000, options: Record<string, boolean> = { childList: true, subtree: true, attributes: true }) {\n let lastMutationTime: number;\n let timeout: number;\n const observer = new MutationObserver((_mutationList, _observer) => {\n const now = Date.now();\n if (lastMutationTime && now - lastMutationTime < throttle) {\n timeout && clearTimeout(timeout);\n }\n timeout = setTimeout(callback, throttle);\n lastMutationTime = now;\n });\n observer.observe(element, options);\n}\n\nexport function downloader(options = { append: \"\", after: \"\", button: \"\", cbBefore: () => { } }) {\n const btn = parseDom(options.button);\n\n if (options.append) document.querySelector(options.append)?.append(btn);\n if (options.after) document.querySelector(options.after)?.after(btn);\n\n btn.addEventListener('click', (e) => {\n e.preventDefault();\n\n if (options.cbBefore) options.cbBefore();\n\n waitForElementExists(document.body, 'video', (video: Element) => {\n window.location.href = video.getAttribute('src') as string;\n });\n });\n}","import { parseDom } from \"../dom\";\n\nexport const MOBILE_UA = [\n 'Mozilla/5.0 (Linux; Android 10; K)',\n 'AppleWebKit/537.36 (KHTML, like Gecko)',\n 'Chrome/114.0.0.0 Mobile Safari/537.36'].join(' ');\n\nexport function fetchWith(url: string, options: Record<string, boolean> = { html: false, mobile: false }) {\n const reqOpts = {};\n if (options.mobile) Object.assign(reqOpts, { headers: new Headers({ \"User-Agent\": MOBILE_UA }) });\n return fetch(url, reqOpts).then((r) => r.text()).then(r => options.html ? parseDom(r) : r);\n}\n\nexport const fetchHtml = (url: string) => fetchWith(url, { html: true });\n\nexport const fetchText = (url: string) => fetchWith(url);\n\nexport function objectToFormData(object: Record<string, number | boolean | string>): FormData {\n const formData = new FormData();\n Object.entries(object).forEach(([k, v]) => formData.append(k, v as string));\n return formData;\n}\n","export function listenEvents(dom: HTMLElement | Element, events: Array<string>, callback: (e: Event) => void): void {\n for (const e of events) {\n dom.addEventListener(e, callback, true);\n }\n}\n\nexport class Tick {\n private tick?: number;\n private callbackFinal?: () => void;\n\n constructor(private delay: number, private startImmediate: boolean = true) {}\n\n public start(callback: () => void, callbackFinal?: () => void): void {\n this.stop();\n this.callbackFinal = callbackFinal;\n if (this.startImmediate) callback();\n this.tick = window.setInterval(callback, this.delay);\n }\n\n public stop(): void {\n if (this.tick !== undefined) {\n clearInterval(this.tick);\n this.tick = undefined;\n }\n if (this.callbackFinal) {\n this.callbackFinal();\n this.callbackFinal = undefined;\n }\n }\n}\n","export function isMob() {\n return /iPhone|Android/i.test(navigator.userAgent);\n}","// https://2ality.com/2016/10/asynchronous-iteration.html\nexport async function computeAsyncOneAtTime(iterable: Iterable<() => Promise<void>>) {\n const res = [];\n for await (const f of iterable) {\n res.push(await f());\n }\n return res;\n}\n\nexport function wait(milliseconds: number) {\n return new Promise((resolve) => setTimeout(resolve, milliseconds));\n}\n\ninterface AsyncPoolTask {\n v: () => Promise<void>;\n p: number;\n}\n\nexport class AsyncPool {\n private cur = 0;\n private finished: Promise<boolean>;\n private _resolve?: (value: boolean | PromiseLike<boolean>) => void;\n\n public static async doNAsyncAtOnce(max = 1, pool: Array<AsyncPoolTask | (() => Promise<void>)> = []) {\n const spool = new AsyncPool(max);\n pool.forEach(f => spool.push(f));\n return spool.run();\n }\n\n constructor(private max = 1, private pool: Array<AsyncPoolTask> = []) {\n this.finished = new Promise((resolve) => {\n this._resolve = resolve;\n });\n }\n\n private getHighPriorityFirst(p = 0): (() => Promise<void>) | undefined {\n if (p > 3 || this.pool.length === 0) return undefined;\n const i = this.pool.findIndex((e) => e.p === p);\n if (i >= 0) {\n const res = this.pool[i].v;\n this.pool.splice(i, 1);\n return res;\n }\n return this.getHighPriorityFirst(p + 1);\n }\n\n private async runTask() {\n this.cur++;\n const f = this.getHighPriorityFirst();\n await f?.();\n this.cur--;\n this.runTasks();\n }\n\n private runTasks() {\n if (!this.pool.length) {\n this._resolve?.(true);\n return;\n }\n if (this.cur < this.max) {\n this.runTask();\n this.runTasks();\n }\n }\n\n public async run() {\n this.runTasks();\n return this.finished;\n }\n\n public push(x: AsyncPoolTask | (() => Promise<void>)) {\n this.pool.push('p' in x ? x : { v: x, p: 0 });\n }\n}\n\n","export function chunks<T>(arr: Array<T>, n: number): Array<Array<T>> {\n return Array.from({ length: Math.ceil(arr.length / n) }, (_, i) => arr.slice(i * n, i * n + n));\n}\n\nexport function range(size: number, startAt: number = 1, step: number = 1): number[] {\n return Array.from({ length: size }, (_, index) => startAt + index * step);\n}\n"],"names":["s","target","observer"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"billy-herrington-utils.es.js","sources":["../src/utils/strings/index.ts","../src/utils/parsers/index.ts","../src/utils/observers/index.ts","../src/utils/math/index.ts","../src/utils/dom/index.ts","../src/utils/fetch/index.ts","../src/utils/events/index.ts","../src/utils/device/index.ts","../src/utils/async/index.ts","../src/utils/arrays/index.ts","../src/data-manager/index.ts","../src/utils/infinite-scroll/index.ts"],"sourcesContent":["export function stringToWords(s: string): Array<string> {\n return s.split(\",\").map(s => s.trim().toLowerCase()).filter(_ => _);\n}\n\nexport function sanitizeStr(s: string) {\n return s?.replace(/\\n|\\t/, ' ').replace(/ {2,}/, ' ').trim().toLowerCase() || \"\";\n}\n","export function formatTimeToHHMMSS(timeString: string): string {\n const regex: RegExp = /(?:(\\d+)\\s*h\\s*)?(?:(\\d+)\\s*mi?n?\\s*)?(?:(\\d+)\\s*sec)?/;\n const match: RegExpMatchArray | null = timeString.match(regex);\n const h: number = parseInt(match?.[1] || '0');\n const m: number = parseInt(match?.[2] || '0');\n const s: number = parseInt(match?.[3] || '0');\n const pad = (num: number): string => String(num).padStart(2, '0');\n return `${pad(h)}:${pad(m)}:${pad(s)}`;\n}\n\n// \"01:22:03\" -> 4923\nexport function timeToSeconds(t: string): number {\n const r = /sec|min|h|m/.test(t) ? formatTimeToHHMMSS(t) : t;\n return (r?.match(/\\d+/gm) || [0])\n .reverse()\n .map((s, i) => parseInt(s as string) * 60 ** i)\n .reduce((a, b) => a + b);\n}\n\nexport function parseIntegerOr(n: string | number, or: number): number {\n return (num => Number.isNaN(num) ? or : num)(parseInt(n as string));\n}\n\n// \"data:02;body+head:async;void:;zero:;\"\nexport function parseDataParams(str: string): Record<string, string> {\n return str.split(';').reduce((acc, s) => {\n const parsed = s.match(/([\\+\\w]+):(\\w+)?/);\n if (parsed) {\n const [, key, value] = parsed;\n if (value) {\n key.split('+').forEach(p => { acc[p] = value; });\n }\n }\n return acc;\n }, {} as Record<string, string>);\n}\n\nexport function parseCSSUrl(s: string) {\n return s.replace(/url\\(\"|\\\"\\).*/g, '');\n}\n","export class Observer {\n public observer: IntersectionObserver;\n constructor(private callback: (entry: Element) => void) {\n this.observer = new IntersectionObserver(this.handleIntersection.bind(this));\n }\n\n observe(target: Element) {\n this.observer.observe(target);\n }\n\n throttle(target: Element, throttleTime: number) {\n this.observer.unobserve(target);\n setTimeout(() => this.observer.observe(target), throttleTime);\n }\n\n handleIntersection(entries: Iterable<IntersectionObserverEntry>) {\n for (const entry of entries) {\n if (entry.isIntersecting) {\n this.callback(entry.target);\n }\n }\n }\n\n static observeWhile(\n target: Element,\n callback: () => Promise<boolean> | boolean,\n throttleTime: number,\n ) {\n const observer_ = new Observer(async (target: Element) => {\n const condition = await callback();\n if (condition) observer_.throttle(target, throttleTime);\n });\n observer_.observe(target);\n return observer_;\n }\n}\n\nexport class LazyImgLoader {\n public lazyImgObserver: Observer;\n private attributeName = 'data-lazy-load';\n\n constructor(shouldDelazify: (target: Element) => boolean) {\n this.lazyImgObserver = new Observer((target: Element) => {\n if (shouldDelazify(target)) {\n this.delazify(target as HTMLImageElement);\n }\n });\n }\n\n lazify(_target: Element, img: HTMLImageElement, imgSrc: string) {\n if (!img || !imgSrc) return;\n img.setAttribute(this.attributeName, imgSrc);\n img.src = '';\n this.lazyImgObserver.observe(img);\n }\n\n delazify = (target: HTMLImageElement) => {\n this.lazyImgObserver.observer.unobserve(target);\n target.src = target.getAttribute(this.attributeName) as string;\n target.removeAttribute(this.attributeName);\n };\n}\n","export function circularShift(n: number, c = 6, s = 1): number {\n return (n + s) % c || c;\n}\n","export function parseDom(html: string): HTMLElement {\n const parsed = new DOMParser().parseFromString(html, 'text/html').body;\n return parsed.children.length > 1 ? parsed : parsed.firstElementChild as HTMLElement;\n}\n\nexport function copyAttributes(target: HTMLElement | Element, source: HTMLElement | Element) {\n for (const attr of source.attributes) {\n attr.nodeValue && target.setAttribute(attr.nodeName, attr.nodeValue);\n }\n}\n\nexport function replaceElementTag(e: HTMLElement | Element, tagName: string) {\n const newTagElement = document.createElement(tagName);\n copyAttributes(newTagElement, e);\n newTagElement.innerHTML = e.innerHTML;\n e.parentNode?.replaceChild(newTagElement, e);\n return newTagElement;\n}\n\nexport function getAllUniqueParents(elements: HTMLCollection): Array<HTMLElement | Element> {\n return Array.from(elements).reduce((acc, v) => {\n if (v.parentElement && !acc.includes(v.parentElement as HTMLElement)) { acc.push(v.parentElement); }\n return acc;\n }, [] as Array<HTMLElement | Element>);\n}\n\nexport function findNextSibling(el: HTMLElement | Element) {\n if (el.nextElementSibling) return el.nextElementSibling;\n if (el.parentElement) return findNextSibling(el.parentElement);\n return null;\n}\n\nexport function waitForElementExists(parent: HTMLElement | Element, selector: string, callback: (el: Element) => void): void {\n const observer = new MutationObserver((_mutations) => {\n const el = parent.querySelector(selector);\n if (el) {\n observer.disconnect();\n callback(el);\n }\n });\n observer.observe(document.body, { childList: true, subtree: true });\n}\n\nexport function watchElementChildrenCount(element: HTMLElement | Element,\n callback: (observer: MutationObserver, count: number) => void): void {\n let count = element.children.length;\n const observer = new MutationObserver((mutationList, observer) => {\n for (const mutation of mutationList) {\n if (mutation.type === \"childList\") {\n if (count !== element.children.length) {\n count = element.children.length;\n callback(observer, count);\n }\n }\n }\n });\n observer.observe(element, { childList: true });\n}\n\nexport function watchDomChangesWithThrottle(\n element: HTMLElement | Element, \n callback: () => void,\n throttle = 1000,\n times = Infinity,\n options: Record<string, boolean> = { childList: true, subtree: true, attributes: true }\n) {\n let lastMutationTime: number;\n let timeout: number;\n let times_ = times;\n const observer = new MutationObserver((_mutationList, _observer) => {\n if (times_ !== Infinity && times_ < 1) {\n observer.disconnect();\n return;\n }\n times_--;\n const now = Date.now();\n if (lastMutationTime && now - lastMutationTime < throttle) {\n timeout && clearTimeout(timeout);\n }\n timeout = setTimeout(callback, throttle);\n lastMutationTime = now;\n });\n observer.observe(element, options);\n return observer;\n}\n\nexport function downloader(options = { append: \"\", after: \"\", button: \"\", cbBefore: () => { } }) {\n const btn = parseDom(options.button);\n\n if (options.append) document.querySelector(options.append)?.append(btn);\n if (options.after) document.querySelector(options.after)?.after(btn);\n\n btn.addEventListener('click', (e) => {\n e.preventDefault();\n\n if (options.cbBefore) options.cbBefore();\n\n waitForElementExists(document.body, 'video', (video: Element) => {\n window.location.href = video.getAttribute('src') as string;\n });\n });\n}","import { parseDom } from '../dom';\n\nexport const MOBILE_UA = [\n 'Mozilla/5.0 (Linux; Android 10; K)',\n 'AppleWebKit/537.36 (KHTML, like Gecko)',\n 'Chrome/114.0.0.0 Mobile Safari/537.36',\n].join(' ');\n\nexport function fetchWith(\n url: string,\n options: Record<string, boolean> = { html: false, mobile: false },\n) {\n const reqOpts = {};\n if (options.mobile) Object.assign(reqOpts, { headers: new Headers({ 'User-Agent': MOBILE_UA }) });\n return fetch(url, reqOpts)\n .then((r) => r.text())\n .then((r) => (options.html ? parseDom(r) : r));\n}\n\nexport const fetchHtml = (url: string) => fetchWith(url, { html: true }) as Promise<HTMLElement>;\n\nexport const fetchText = (url: string) => fetchWith(url) as Promise<string>;\n\nexport function objectToFormData(object: Record<string, number | boolean | string>): FormData {\n const formData = new FormData();\n Object.entries(object).forEach(([k, v]) => formData.append(k, v as string));\n return formData;\n}\n","export function listenEvents(dom: HTMLElement | Element, events: Array<string>, callback: (e: Event) => void): void {\n for (const e of events) {\n dom.addEventListener(e, callback, true);\n }\n}\n\nexport class Tick {\n private tick?: number;\n private callbackFinal?: () => void;\n\n constructor(private delay: number, private startImmediate: boolean = true) {}\n\n public start(callback: () => void, callbackFinal?: () => void): void {\n this.stop();\n this.callbackFinal = callbackFinal;\n if (this.startImmediate) callback();\n this.tick = window.setInterval(callback, this.delay);\n }\n\n public stop(): void {\n if (this.tick !== undefined) {\n clearInterval(this.tick);\n this.tick = undefined;\n }\n if (this.callbackFinal) {\n this.callbackFinal();\n this.callbackFinal = undefined;\n }\n }\n}\n","export function isMob() {\n return /iPhone|Android/i.test(navigator.userAgent);\n}","// https://2ality.com/2016/10/asynchronous-iteration.html\nexport async function computeAsyncOneAtTime(iterable: Iterable<() => Promise<void>>) {\n const res = [];\n for await (const f of iterable) {\n res.push(await f());\n }\n return res;\n}\n\nexport function wait(milliseconds: number) {\n return new Promise((resolve) => setTimeout(resolve, milliseconds));\n}\n\ninterface AsyncPoolTask {\n v: () => Promise<void>;\n p: number;\n}\n\nexport class AsyncPool {\n private cur = 0;\n private finished: Promise<boolean>;\n private _resolve?: (value: boolean | PromiseLike<boolean>) => void;\n\n public static async doNAsyncAtOnce(max = 1, pool: Array<AsyncPoolTask | (() => Promise<void>)> = []) {\n const spool = new AsyncPool(max);\n pool.forEach(f => spool.push(f));\n return spool.run();\n }\n\n constructor(private max = 1, private pool: Array<AsyncPoolTask> = []) {\n this.finished = new Promise((resolve) => {\n this._resolve = resolve;\n });\n }\n\n private getHighPriorityFirst(p = 0): (() => Promise<void>) | undefined {\n if (p > 3 || this.pool.length === 0) return undefined;\n const i = this.pool.findIndex((e) => e.p === p);\n if (i >= 0) {\n const res = this.pool[i].v;\n this.pool.splice(i, 1);\n return res;\n }\n return this.getHighPriorityFirst(p + 1);\n }\n\n private async runTask() {\n this.cur++;\n const f = this.getHighPriorityFirst();\n await f?.();\n this.cur--;\n this.runTasks();\n }\n\n private runTasks() {\n if (!this.pool.length) {\n this._resolve?.(true);\n return;\n }\n if (this.cur < this.max) {\n this.runTask();\n this.runTasks();\n }\n }\n\n public async run() {\n this.runTasks();\n return this.finished;\n }\n\n public push(x: AsyncPoolTask | (() => Promise<void>)) {\n this.pool.push('p' in x ? x : { v: x, p: 0 });\n }\n}\n\n","export function chunks<T>(arr: Array<T>, n: number): Array<Array<T>> {\n return Array.from({ length: Math.ceil(arr.length / n) }, (_, i) => arr.slice(i * n, i * n + n));\n}\n\nexport function range(size: number, startAt: number = 1, step: number = 1): number[] {\n return Array.from({ length: size }, (_, index) => startAt + index * step);\n}\n","import { LazyImgLoader } from '../utils/observers';\nimport { stringToWords } from '../utils/strings';\n\ninterface DataFilterState {\n filterPublic: boolean;\n filterPrivate: boolean;\n filterDuration: boolean;\n filterDurationFrom: number;\n filterDurationTo: number;\n filterExclude: boolean;\n filterExcludeWords: string;\n filterInclude: boolean;\n filterIncludeWords: string;\n}\n\ninterface FilterResult {\n tag: string;\n condition: boolean;\n}\n\ntype FilterInput = Record<string, string | number | boolean | HTMLElement>;\ntype FilterFunction = (v: FilterInput) => FilterResult;\n\nclass DataFilter {\n private state: DataFilterState;\n private rules: IRules;\n public filters: { [key: string]: () => FilterFunction };\n\n constructor(rules: IRules, state: DataFilterState) {\n this.state = state;\n this.rules = rules;\n\n const methods = Object.getOwnPropertyNames(this);\n this.filters = methods.reduce((acc: { [key: string]: () => FilterFunction }, k) => {\n if (k in this.state) {\n acc[k] = this[k as keyof DataFilter] as unknown as () => FilterFunction;\n //@ts-ignore\n GM_addStyle(`.filter-${k.toLowerCase().slice(6)} { display: none !important; }`);\n }\n return acc;\n }, {});\n }\n\n filterPublic = (): FilterFunction => {\n return (v: FilterInput) => {\n const isPublic = !this.rules.IS_PRIVATE(v.element as HTMLElement);\n return {\n tag: 'filter-public',\n condition: this.state.filterPublic && isPublic,\n };\n };\n };\n\n filterPrivate = (): FilterFunction => {\n return (v: FilterInput) => {\n const isPrivate = this.rules.IS_PRIVATE(v.element as HTMLElement);\n return {\n tag: 'filter-private',\n condition: this.state.filterPrivate && isPrivate,\n };\n };\n };\n\n filterDuration = (): FilterFunction => {\n return (v: FilterInput) => {\n const notInRange =\n (v.duration as number) < this.state.filterDurationFrom ||\n (v.duration as number) > this.state.filterDurationTo;\n return {\n tag: 'filter-duration',\n condition: this.state.filterDuration && notInRange,\n };\n };\n };\n\n filterExclude = (): FilterFunction => {\n const tags = DataManager.filterDSLToRegex(this.state.filterExcludeWords);\n return (v: FilterInput) => {\n const containTags = tags.some((tag) => tag.test(v.title as string));\n return {\n tag: 'filter-exclude',\n condition: this.state.filterExclude && containTags,\n };\n };\n };\n\n filterInclude = (): FilterFunction => {\n const tags = DataManager.filterDSLToRegex(this.state.filterIncludeWords);\n return (v: FilterInput) => {\n const containTagsNot = tags.some((tag) => !tag.test(v.title as string));\n return {\n tag: 'filter-include',\n condition: this.state.filterInclude && containTagsNot,\n };\n };\n };\n}\n\ninterface IRules {\n GET_THUMBS: (html: HTMLElement) => HTMLElement[];\n THUMB_URL: (thumbElement: HTMLElement) => string;\n THUMB_DATA: (thumbElement: HTMLElement) => { title: string; duration: number };\n THUMB_IMG_DATA: (thumbElement: HTMLElement) => { img: HTMLElement; imgSrc: string };\n CONTAINER: HTMLElement;\n IS_PRIVATE: (element: HTMLElement) => boolean;\n}\n\nexport class DataManager {\n private rules: IRules;\n private state: DataFilterState;\n private data: Map<string, FilterInput>;\n private lazyImgLoader: LazyImgLoader;\n public dataFilters: { [key: string]: () => FilterFunction };\n\n constructor(rules: IRules, state: DataFilterState) {\n this.rules = rules;\n this.state = state;\n this.data = new Map();\n this.lazyImgLoader = new LazyImgLoader(\n (target: Element) => !this.isFiltered(target as HTMLElement),\n );\n this.dataFilters = new DataFilter(rules, state).filters;\n }\n\n static filterDSLToRegex(str: string): RegExp[] {\n const toFullWord = (w: string) => `(^|\\\\ )${w}($|\\\\ )`;\n const str_ = str.replace(/f\\:(\\w+)/g, (_, w) => toFullWord(w));\n return stringToWords(str_).map((expr: string) => new RegExp(expr, 'i'));\n }\n\n isFiltered(el: HTMLElement): boolean {\n return el.className.includes('filtered');\n }\n\n applyFilters = (filters: { [key: string]: boolean }, offset = 0): void => {\n const filtersToApply = Object.keys(filters)\n .filter((k) => Object.hasOwn(this.dataFilters, k))\n .map((k) => this.dataFilters[k]());\n\n if (filtersToApply.length === 0) return;\n\n const updates: (() => void)[] = [];\n let offset_counter = 1;\n for (const v of this.data.values()) {\n if (++offset_counter > offset) {\n for (const f of filtersToApply) {\n const { tag, condition } = f(v as FilterInput);\n updates.push(() => (v.element as HTMLElement).classList.toggle(tag, condition));\n }\n }\n }\n\n requestAnimationFrame(() => {\n updates.forEach((update) => update());\n });\n };\n\n filterAll = (offset?: number): void => {\n const filters = Object.assign(\n {},\n ...Object.keys(this.dataFilters).map((f) => ({\n [f]: this.state[f as keyof DataFilterState],\n })),\n );\n this.applyFilters(filters, offset);\n };\n\n handleLoadedHTML = (\n html: HTMLElement,\n container?: HTMLElement,\n removeDuplicates = false,\n shouldLazify = true,\n ): void => {\n const thumbs = this.rules.GET_THUMBS(html);\n const data_offset = this.data.size;\n\n for (const thumbElement of thumbs) {\n const url = this.rules.THUMB_URL(thumbElement);\n if (!url || this.data.has(url)) {\n if (removeDuplicates) thumbElement.remove();\n continue;\n }\n\n const { title, duration } = this.rules.THUMB_DATA(thumbElement);\n this.data.set(url, { element: thumbElement, duration, title });\n\n if (shouldLazify) {\n const { img, imgSrc } = this.rules.THUMB_IMG_DATA(thumbElement);\n this.lazyImgLoader.lazify(thumbElement, img as HTMLImageElement, imgSrc);\n }\n\n const parent = container || this.rules.CONTAINER;\n if (!parent.contains(thumbElement)) parent.appendChild(thumbElement);\n }\n\n this.filterAll(data_offset);\n };\n}\n","import { fetchHtml } from '../fetch';\nimport { Observer } from '../observers';\n\ninterface IInfiniteScroller {\n delay: number;\n enabled: boolean;\n paginationOffset: number;\n paginationLast: number;\n paginationElement: HTMLElement;\n paginationUrlGenerator: (offset: number) => string;\n handleHtmlCallback: (document: HTMLElement) => void;\n intersectionObservable?: HTMLElement;\n alternativeGenerator?: () => OffsetGenerator;\n}\n\ninterface GeneratorResult {\n url: string;\n offset: number;\n}\n\ntype OffsetGenerator = Generator<GeneratorResult> | AsyncGenerator<GeneratorResult>;\n\nexport class InfiniteScroller {\n public paginationGenerator: OffsetGenerator;\n public enabled: boolean;\n public delay: number;\n public paginationOffset: number;\n public paginationLast: number;\n private handleHtmlCallback: (document: HTMLElement) => void;\n\n constructor({\n enabled,\n handleHtmlCallback,\n delay,\n alternativeGenerator,\n paginationOffset,\n paginationLast,\n paginationElement,\n paginationUrlGenerator,\n intersectionObservable,\n }: IInfiniteScroller) {\n this.enabled = enabled;\n this.delay = delay;\n this.paginationOffset = paginationOffset;\n this.paginationLast = paginationLast;\n this.handleHtmlCallback = handleHtmlCallback;\n\n this.paginationGenerator =\n alternativeGenerator?.() ??\n InfiniteScroller.createPaginationGenerator(\n paginationOffset,\n paginationLast,\n paginationUrlGenerator,\n );\n\n const observable = intersectionObservable || paginationElement;\n Observer.observeWhile(observable, this.generatorConsumer, this.delay);\n }\n\n // this.stateLocale.pagIndexLast = paginationLast;\n // this.stateLocale.pagIndexCur = paginationOffset;\n // infiniteScrollEnabled: boolean;\n\n private onScrollCBs: Array<(scroller: InfiniteScroller) => void> = [];\n\n public onScroll(callback: (scroller: InfiniteScroller) => void) {\n this.onScrollCBs.push(callback);\n return this;\n }\n\n private _onScroll() {\n this.onScrollCBs.forEach((cb) => cb(this));\n }\n\n generatorConsumer = async () => {\n if (!this.enabled) return false;\n const {\n value: { url, offset } = {},\n done,\n } = await this.paginationGenerator.next();\n if (!done) {\n const nextPageHTML = await fetchHtml(url);\n const prevScrollPos = document.documentElement.scrollTop;\n this.paginationOffset = offset;\n this.handleHtmlCallback(nextPageHTML);\n this._onScroll();\n window.scrollTo(0, prevScrollPos);\n }\n return !done;\n };\n\n static *createPaginationGenerator(\n currentPage: number,\n totalPages: number,\n generateURL: (offset: number) => string,\n ): OffsetGenerator {\n for (let offset = currentPage + 1; offset <= totalPages; offset++) {\n const url = generateURL(offset);\n yield { url, offset };\n }\n }\n}\n"],"names":["s","target","observer"],"mappings":"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"}
|
|
@@ -151,10 +151,16 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
151
151
|
});
|
|
152
152
|
observer.observe(element, { childList: true });
|
|
153
153
|
}
|
|
154
|
-
function watchDomChangesWithThrottle(element, callback, throttle = 1e3, options = { childList: true, subtree: true, attributes: true }) {
|
|
154
|
+
function watchDomChangesWithThrottle(element, callback, throttle = 1e3, times = Infinity, options = { childList: true, subtree: true, attributes: true }) {
|
|
155
155
|
let lastMutationTime;
|
|
156
156
|
let timeout;
|
|
157
|
+
let times_ = times;
|
|
157
158
|
const observer = new MutationObserver((_mutationList, _observer) => {
|
|
159
|
+
if (times_ !== Infinity && times_ < 1) {
|
|
160
|
+
observer.disconnect();
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
times_--;
|
|
158
164
|
const now = Date.now();
|
|
159
165
|
if (lastMutationTime && now - lastMutationTime < throttle) {
|
|
160
166
|
timeout && clearTimeout(timeout);
|
|
@@ -163,6 +169,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
163
169
|
lastMutationTime = now;
|
|
164
170
|
});
|
|
165
171
|
observer.observe(element, options);
|
|
172
|
+
return observer;
|
|
166
173
|
}
|
|
167
174
|
function downloader(options = { append: "", after: "", button: "", cbBefore: () => {
|
|
168
175
|
} }) {
|
|
@@ -293,7 +300,208 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
293
300
|
function range(size, startAt = 1, step = 1) {
|
|
294
301
|
return Array.from({ length: size }, (_, index) => startAt + index * step);
|
|
295
302
|
}
|
|
303
|
+
class DataFilter {
|
|
304
|
+
constructor(rules, state) {
|
|
305
|
+
__publicField(this, "state");
|
|
306
|
+
__publicField(this, "rules");
|
|
307
|
+
__publicField(this, "filters");
|
|
308
|
+
__publicField(this, "filterPublic", () => {
|
|
309
|
+
return (v) => {
|
|
310
|
+
const isPublic = !this.rules.IS_PRIVATE(v.element);
|
|
311
|
+
return {
|
|
312
|
+
tag: "filter-public",
|
|
313
|
+
condition: this.state.filterPublic && isPublic
|
|
314
|
+
};
|
|
315
|
+
};
|
|
316
|
+
});
|
|
317
|
+
__publicField(this, "filterPrivate", () => {
|
|
318
|
+
return (v) => {
|
|
319
|
+
const isPrivate = this.rules.IS_PRIVATE(v.element);
|
|
320
|
+
return {
|
|
321
|
+
tag: "filter-private",
|
|
322
|
+
condition: this.state.filterPrivate && isPrivate
|
|
323
|
+
};
|
|
324
|
+
};
|
|
325
|
+
});
|
|
326
|
+
__publicField(this, "filterDuration", () => {
|
|
327
|
+
return (v) => {
|
|
328
|
+
const notInRange = v.duration < this.state.filterDurationFrom || v.duration > this.state.filterDurationTo;
|
|
329
|
+
return {
|
|
330
|
+
tag: "filter-duration",
|
|
331
|
+
condition: this.state.filterDuration && notInRange
|
|
332
|
+
};
|
|
333
|
+
};
|
|
334
|
+
});
|
|
335
|
+
__publicField(this, "filterExclude", () => {
|
|
336
|
+
const tags = DataManager.filterDSLToRegex(this.state.filterExcludeWords);
|
|
337
|
+
return (v) => {
|
|
338
|
+
const containTags = tags.some((tag) => tag.test(v.title));
|
|
339
|
+
return {
|
|
340
|
+
tag: "filter-exclude",
|
|
341
|
+
condition: this.state.filterExclude && containTags
|
|
342
|
+
};
|
|
343
|
+
};
|
|
344
|
+
});
|
|
345
|
+
__publicField(this, "filterInclude", () => {
|
|
346
|
+
const tags = DataManager.filterDSLToRegex(this.state.filterIncludeWords);
|
|
347
|
+
return (v) => {
|
|
348
|
+
const containTagsNot = tags.some((tag) => !tag.test(v.title));
|
|
349
|
+
return {
|
|
350
|
+
tag: "filter-include",
|
|
351
|
+
condition: this.state.filterInclude && containTagsNot
|
|
352
|
+
};
|
|
353
|
+
};
|
|
354
|
+
});
|
|
355
|
+
this.state = state;
|
|
356
|
+
this.rules = rules;
|
|
357
|
+
const methods = Object.getOwnPropertyNames(this);
|
|
358
|
+
this.filters = methods.reduce((acc, k) => {
|
|
359
|
+
if (k in this.state) {
|
|
360
|
+
acc[k] = this[k];
|
|
361
|
+
GM_addStyle(`.filter-${k.toLowerCase().slice(6)} { display: none !important; }`);
|
|
362
|
+
}
|
|
363
|
+
return acc;
|
|
364
|
+
}, {});
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
class DataManager {
|
|
368
|
+
constructor(rules, state) {
|
|
369
|
+
__publicField(this, "rules");
|
|
370
|
+
__publicField(this, "state");
|
|
371
|
+
__publicField(this, "data");
|
|
372
|
+
__publicField(this, "lazyImgLoader");
|
|
373
|
+
__publicField(this, "dataFilters");
|
|
374
|
+
__publicField(this, "applyFilters", (filters, offset = 0) => {
|
|
375
|
+
const filtersToApply = Object.keys(filters).filter((k) => Object.hasOwn(this.dataFilters, k)).map((k) => this.dataFilters[k]());
|
|
376
|
+
if (filtersToApply.length === 0) return;
|
|
377
|
+
const updates = [];
|
|
378
|
+
let offset_counter = 1;
|
|
379
|
+
for (const v of this.data.values()) {
|
|
380
|
+
if (++offset_counter > offset) {
|
|
381
|
+
for (const f of filtersToApply) {
|
|
382
|
+
const { tag, condition } = f(v);
|
|
383
|
+
updates.push(() => v.element.classList.toggle(tag, condition));
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
requestAnimationFrame(() => {
|
|
388
|
+
updates.forEach((update) => update());
|
|
389
|
+
});
|
|
390
|
+
});
|
|
391
|
+
__publicField(this, "filterAll", (offset) => {
|
|
392
|
+
const filters = Object.assign(
|
|
393
|
+
{},
|
|
394
|
+
...Object.keys(this.dataFilters).map((f) => ({
|
|
395
|
+
[f]: this.state[f]
|
|
396
|
+
}))
|
|
397
|
+
);
|
|
398
|
+
this.applyFilters(filters, offset);
|
|
399
|
+
});
|
|
400
|
+
__publicField(this, "handleLoadedHTML", (html, container, removeDuplicates = false, shouldLazify = true) => {
|
|
401
|
+
const thumbs = this.rules.GET_THUMBS(html);
|
|
402
|
+
const data_offset = this.data.size;
|
|
403
|
+
for (const thumbElement of thumbs) {
|
|
404
|
+
const url = this.rules.THUMB_URL(thumbElement);
|
|
405
|
+
if (!url || this.data.has(url)) {
|
|
406
|
+
if (removeDuplicates) thumbElement.remove();
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
const { title, duration } = this.rules.THUMB_DATA(thumbElement);
|
|
410
|
+
this.data.set(url, { element: thumbElement, duration, title });
|
|
411
|
+
if (shouldLazify) {
|
|
412
|
+
const { img, imgSrc } = this.rules.THUMB_IMG_DATA(thumbElement);
|
|
413
|
+
this.lazyImgLoader.lazify(thumbElement, img, imgSrc);
|
|
414
|
+
}
|
|
415
|
+
const parent = container || this.rules.CONTAINER;
|
|
416
|
+
if (!parent.contains(thumbElement)) parent.appendChild(thumbElement);
|
|
417
|
+
}
|
|
418
|
+
this.filterAll(data_offset);
|
|
419
|
+
});
|
|
420
|
+
this.rules = rules;
|
|
421
|
+
this.state = state;
|
|
422
|
+
this.data = /* @__PURE__ */ new Map();
|
|
423
|
+
this.lazyImgLoader = new LazyImgLoader(
|
|
424
|
+
(target) => !this.isFiltered(target)
|
|
425
|
+
);
|
|
426
|
+
this.dataFilters = new DataFilter(rules, state).filters;
|
|
427
|
+
}
|
|
428
|
+
static filterDSLToRegex(str) {
|
|
429
|
+
const toFullWord = (w) => `(^|\\ )${w}($|\\ )`;
|
|
430
|
+
const str_ = str.replace(/f\:(\w+)/g, (_, w) => toFullWord(w));
|
|
431
|
+
return stringToWords(str_).map((expr) => new RegExp(expr, "i"));
|
|
432
|
+
}
|
|
433
|
+
isFiltered(el) {
|
|
434
|
+
return el.className.includes("filtered");
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
class InfiniteScroller {
|
|
438
|
+
constructor({
|
|
439
|
+
enabled,
|
|
440
|
+
handleHtmlCallback,
|
|
441
|
+
delay,
|
|
442
|
+
alternativeGenerator,
|
|
443
|
+
paginationOffset,
|
|
444
|
+
paginationLast,
|
|
445
|
+
paginationElement,
|
|
446
|
+
paginationUrlGenerator,
|
|
447
|
+
intersectionObservable
|
|
448
|
+
}) {
|
|
449
|
+
__publicField(this, "paginationGenerator");
|
|
450
|
+
__publicField(this, "enabled");
|
|
451
|
+
__publicField(this, "delay");
|
|
452
|
+
__publicField(this, "paginationOffset");
|
|
453
|
+
__publicField(this, "paginationLast");
|
|
454
|
+
__publicField(this, "handleHtmlCallback");
|
|
455
|
+
// this.stateLocale.pagIndexLast = paginationLast;
|
|
456
|
+
// this.stateLocale.pagIndexCur = paginationOffset;
|
|
457
|
+
// infiniteScrollEnabled: boolean;
|
|
458
|
+
__publicField(this, "onScrollCBs", []);
|
|
459
|
+
__publicField(this, "generatorConsumer", async () => {
|
|
460
|
+
if (!this.enabled) return false;
|
|
461
|
+
const {
|
|
462
|
+
value: { url, offset } = {},
|
|
463
|
+
done
|
|
464
|
+
} = await this.paginationGenerator.next();
|
|
465
|
+
if (!done) {
|
|
466
|
+
const nextPageHTML = await fetchHtml(url);
|
|
467
|
+
const prevScrollPos = document.documentElement.scrollTop;
|
|
468
|
+
this.paginationOffset = offset;
|
|
469
|
+
this.handleHtmlCallback(nextPageHTML);
|
|
470
|
+
this._onScroll();
|
|
471
|
+
window.scrollTo(0, prevScrollPos);
|
|
472
|
+
}
|
|
473
|
+
return !done;
|
|
474
|
+
});
|
|
475
|
+
this.enabled = enabled;
|
|
476
|
+
this.delay = delay;
|
|
477
|
+
this.paginationOffset = paginationOffset;
|
|
478
|
+
this.paginationLast = paginationLast;
|
|
479
|
+
this.handleHtmlCallback = handleHtmlCallback;
|
|
480
|
+
this.paginationGenerator = alternativeGenerator?.() ?? InfiniteScroller.createPaginationGenerator(
|
|
481
|
+
paginationOffset,
|
|
482
|
+
paginationLast,
|
|
483
|
+
paginationUrlGenerator
|
|
484
|
+
);
|
|
485
|
+
const observable = intersectionObservable || paginationElement;
|
|
486
|
+
Observer.observeWhile(observable, this.generatorConsumer, this.delay);
|
|
487
|
+
}
|
|
488
|
+
onScroll(callback) {
|
|
489
|
+
this.onScrollCBs.push(callback);
|
|
490
|
+
return this;
|
|
491
|
+
}
|
|
492
|
+
_onScroll() {
|
|
493
|
+
this.onScrollCBs.forEach((cb) => cb(this));
|
|
494
|
+
}
|
|
495
|
+
static *createPaginationGenerator(currentPage, totalPages, generateURL) {
|
|
496
|
+
for (let offset = currentPage + 1; offset <= totalPages; offset++) {
|
|
497
|
+
const url = generateURL(offset);
|
|
498
|
+
yield { url, offset };
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
296
502
|
exports2.AsyncPool = AsyncPool;
|
|
503
|
+
exports2.DataManager = DataManager;
|
|
504
|
+
exports2.InfiniteScroller = InfiniteScroller;
|
|
297
505
|
exports2.LazyImgLoader = LazyImgLoader;
|
|
298
506
|
exports2.MOBILE_UA = MOBILE_UA;
|
|
299
507
|
exports2.Observer = Observer;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"billy-herrington-utils.umd.js","sources":["../src/utils/strings/index.ts","../src/utils/parsers/index.ts","../src/utils/observers/index.ts","../src/utils/math/index.ts","../src/utils/dom/index.ts","../src/utils/fetch/index.ts","../src/utils/events/index.ts","../src/utils/device/index.ts","../src/utils/async/index.ts","../src/utils/arrays/index.ts"],"sourcesContent":["export function stringToWords(s: string): Array<string> {\n return s.split(\",\").map(s => s.trim().toLowerCase()).filter(_ => _);\n}\n\nexport function sanitizeStr(s: string) {\n return s?.replace(/\\n|\\t/, ' ').replace(/ {2,}/, ' ').trim().toLowerCase() || \"\";\n}\n","export function formatTimeToHHMMSS(timeString: string): string {\n const regex: RegExp = /(?:(\\d+)\\s*h\\s*)?(?:(\\d+)\\s*mi?n?\\s*)?(?:(\\d+)\\s*sec)?/;\n const match: RegExpMatchArray | null = timeString.match(regex);\n const h: number = parseInt(match?.[1] || '0');\n const m: number = parseInt(match?.[2] || '0');\n const s: number = parseInt(match?.[3] || '0');\n const pad = (num: number): string => String(num).padStart(2, '0');\n return `${pad(h)}:${pad(m)}:${pad(s)}`;\n}\n\n// \"01:22:03\" -> 4923\nexport function timeToSeconds(t: string): number {\n const r = /sec|min|h|m/.test(t) ? formatTimeToHHMMSS(t) : t;\n return (r?.match(/\\d+/gm) || [0])\n .reverse()\n .map((s, i) => parseInt(s as string) * 60 ** i)\n .reduce((a, b) => a + b);\n}\n\nexport function parseIntegerOr(n: string | number, or: number): number {\n return (num => Number.isNaN(num) ? or : num)(parseInt(n as string));\n}\n\n// \"data:02;body+head:async;void:;zero:;\"\nexport function parseDataParams(str: string): Record<string, string> {\n return str.split(';').reduce((acc, s) => {\n const parsed = s.match(/([\\+\\w]+):(\\w+)?/);\n if (parsed) {\n const [, key, value] = parsed;\n if (value) {\n key.split('+').forEach(p => { acc[p] = value; });\n }\n }\n return acc;\n }, {} as Record<string, string>);\n}\n\nexport function parseCSSUrl(s: string) {\n return s.replace(/url\\(\"|\\\"\\).*/g, '');\n}\n","export class Observer {\n public observer: IntersectionObserver;\n constructor(private callback: (entry: Element) => void) {\n this.observer = new IntersectionObserver(this.handleIntersection.bind(this));\n }\n\n observe(target: Element) {\n this.observer.observe(target);\n }\n\n throttle(target: Element, throttleTime: number) {\n this.observer.unobserve(target);\n setTimeout(() => this.observer.observe(target), throttleTime);\n }\n\n handleIntersection(entries: Iterable<IntersectionObserverEntry>) {\n for (const entry of entries) {\n if (entry.isIntersecting) {\n this.callback(entry.target);\n }\n }\n }\n\n static observeWhile(target: Element, callback: () => Promise<boolean> | boolean, throttleTime: number) {\n const observer_ = new Observer(async (target: Element) => {\n const condition = await callback();\n if (condition) observer_.throttle(target, throttleTime);\n });\n observer_.observe(target);\n return observer_;\n }\n}\n\nexport class LazyImgLoader {\n public lazyImgObserver: Observer;\n private attributeName = 'data-lazy-load';\n\n constructor(shouldDelazify: (target: Element) => boolean) {\n this.lazyImgObserver = new Observer((target: Element) => {\n if (shouldDelazify(target)) {\n this.delazify(target as HTMLImageElement);\n }\n });\n }\n\n lazify(_target: Element, img: HTMLImageElement, imgSrc: string) {\n if (!img || !imgSrc) return;\n img.setAttribute(this.attributeName, imgSrc);\n img.src = '';\n this.lazyImgObserver.observe(img);\n }\n\n delazify = (target: HTMLImageElement) => {\n this.lazyImgObserver.observer.unobserve(target);\n target.src = target.getAttribute(this.attributeName) as string;\n target.removeAttribute(this.attributeName);\n }\n}\n","export function circularShift(n: number, c = 6, s = 1): number {\n return (n + s) % c || c;\n}\n","export function parseDom(html: string): HTMLElement {\n const parsed = new DOMParser().parseFromString(html, 'text/html').body;\n return parsed.children.length > 1 ? parsed : parsed.firstElementChild as HTMLElement;\n}\n\nexport function copyAttributes(target: HTMLElement | Element, source: HTMLElement | Element) {\n for (const attr of source.attributes) {\n attr.nodeValue && target.setAttribute(attr.nodeName, attr.nodeValue);\n }\n}\n\nexport function replaceElementTag(e: HTMLElement | Element, tagName: string) {\n const newTagElement = document.createElement(tagName);\n copyAttributes(newTagElement, e);\n newTagElement.innerHTML = e.innerHTML;\n e.parentNode?.replaceChild(newTagElement, e);\n return newTagElement;\n}\n\nexport function getAllUniqueParents(elements: HTMLCollection): Array<HTMLElement | Element> {\n return Array.from(elements).reduce((acc, v) => {\n if (v.parentElement && !acc.includes(v.parentElement as HTMLElement)) { acc.push(v.parentElement); }\n return acc;\n }, [] as Array<HTMLElement | Element>);\n}\n\nexport function findNextSibling(el: HTMLElement | Element) {\n if (el.nextElementSibling) return el.nextElementSibling;\n if (el.parentElement) return findNextSibling(el.parentElement);\n return null;\n}\n\nexport function waitForElementExists(parent: HTMLElement | Element, selector: string, callback: (el: Element) => void): void {\n const observer = new MutationObserver((_mutations) => {\n const el = parent.querySelector(selector);\n if (el) {\n observer.disconnect();\n callback(el);\n }\n });\n observer.observe(document.body, { childList: true, subtree: true });\n}\n\nexport function watchElementChildrenCount(element: HTMLElement | Element,\n callback: (observer: MutationObserver, count: number) => void): void {\n let count = element.children.length;\n const observer = new MutationObserver((mutationList, observer) => {\n for (const mutation of mutationList) {\n if (mutation.type === \"childList\") {\n if (count !== element.children.length) {\n count = element.children.length;\n callback(observer, count);\n }\n }\n }\n });\n observer.observe(element, { childList: true });\n}\n\nexport function watchDomChangesWithThrottle(element: HTMLElement | Element, callback: () => void,\n throttle = 1000, options: Record<string, boolean> = { childList: true, subtree: true, attributes: true }) {\n let lastMutationTime: number;\n let timeout: number;\n const observer = new MutationObserver((_mutationList, _observer) => {\n const now = Date.now();\n if (lastMutationTime && now - lastMutationTime < throttle) {\n timeout && clearTimeout(timeout);\n }\n timeout = setTimeout(callback, throttle);\n lastMutationTime = now;\n });\n observer.observe(element, options);\n}\n\nexport function downloader(options = { append: \"\", after: \"\", button: \"\", cbBefore: () => { } }) {\n const btn = parseDom(options.button);\n\n if (options.append) document.querySelector(options.append)?.append(btn);\n if (options.after) document.querySelector(options.after)?.after(btn);\n\n btn.addEventListener('click', (e) => {\n e.preventDefault();\n\n if (options.cbBefore) options.cbBefore();\n\n waitForElementExists(document.body, 'video', (video: Element) => {\n window.location.href = video.getAttribute('src') as string;\n });\n });\n}","import { parseDom } from \"../dom\";\n\nexport const MOBILE_UA = [\n 'Mozilla/5.0 (Linux; Android 10; K)',\n 'AppleWebKit/537.36 (KHTML, like Gecko)',\n 'Chrome/114.0.0.0 Mobile Safari/537.36'].join(' ');\n\nexport function fetchWith(url: string, options: Record<string, boolean> = { html: false, mobile: false }) {\n const reqOpts = {};\n if (options.mobile) Object.assign(reqOpts, { headers: new Headers({ \"User-Agent\": MOBILE_UA }) });\n return fetch(url, reqOpts).then((r) => r.text()).then(r => options.html ? parseDom(r) : r);\n}\n\nexport const fetchHtml = (url: string) => fetchWith(url, { html: true });\n\nexport const fetchText = (url: string) => fetchWith(url);\n\nexport function objectToFormData(object: Record<string, number | boolean | string>): FormData {\n const formData = new FormData();\n Object.entries(object).forEach(([k, v]) => formData.append(k, v as string));\n return formData;\n}\n","export function listenEvents(dom: HTMLElement | Element, events: Array<string>, callback: (e: Event) => void): void {\n for (const e of events) {\n dom.addEventListener(e, callback, true);\n }\n}\n\nexport class Tick {\n private tick?: number;\n private callbackFinal?: () => void;\n\n constructor(private delay: number, private startImmediate: boolean = true) {}\n\n public start(callback: () => void, callbackFinal?: () => void): void {\n this.stop();\n this.callbackFinal = callbackFinal;\n if (this.startImmediate) callback();\n this.tick = window.setInterval(callback, this.delay);\n }\n\n public stop(): void {\n if (this.tick !== undefined) {\n clearInterval(this.tick);\n this.tick = undefined;\n }\n if (this.callbackFinal) {\n this.callbackFinal();\n this.callbackFinal = undefined;\n }\n }\n}\n","export function isMob() {\n return /iPhone|Android/i.test(navigator.userAgent);\n}","// https://2ality.com/2016/10/asynchronous-iteration.html\nexport async function computeAsyncOneAtTime(iterable: Iterable<() => Promise<void>>) {\n const res = [];\n for await (const f of iterable) {\n res.push(await f());\n }\n return res;\n}\n\nexport function wait(milliseconds: number) {\n return new Promise((resolve) => setTimeout(resolve, milliseconds));\n}\n\ninterface AsyncPoolTask {\n v: () => Promise<void>;\n p: number;\n}\n\nexport class AsyncPool {\n private cur = 0;\n private finished: Promise<boolean>;\n private _resolve?: (value: boolean | PromiseLike<boolean>) => void;\n\n public static async doNAsyncAtOnce(max = 1, pool: Array<AsyncPoolTask | (() => Promise<void>)> = []) {\n const spool = new AsyncPool(max);\n pool.forEach(f => spool.push(f));\n return spool.run();\n }\n\n constructor(private max = 1, private pool: Array<AsyncPoolTask> = []) {\n this.finished = new Promise((resolve) => {\n this._resolve = resolve;\n });\n }\n\n private getHighPriorityFirst(p = 0): (() => Promise<void>) | undefined {\n if (p > 3 || this.pool.length === 0) return undefined;\n const i = this.pool.findIndex((e) => e.p === p);\n if (i >= 0) {\n const res = this.pool[i].v;\n this.pool.splice(i, 1);\n return res;\n }\n return this.getHighPriorityFirst(p + 1);\n }\n\n private async runTask() {\n this.cur++;\n const f = this.getHighPriorityFirst();\n await f?.();\n this.cur--;\n this.runTasks();\n }\n\n private runTasks() {\n if (!this.pool.length) {\n this._resolve?.(true);\n return;\n }\n if (this.cur < this.max) {\n this.runTask();\n this.runTasks();\n }\n }\n\n public async run() {\n this.runTasks();\n return this.finished;\n }\n\n public push(x: AsyncPoolTask | (() => Promise<void>)) {\n this.pool.push('p' in x ? x : { v: x, p: 0 });\n }\n}\n\n","export function chunks<T>(arr: Array<T>, n: number): Array<Array<T>> {\n return Array.from({ length: Math.ceil(arr.length / n) }, (_, i) => arr.slice(i * n, i * n + n));\n}\n\nexport function range(size: number, startAt: number = 1, step: number = 1): number[] {\n return Array.from({ length: size }, (_, index) => startAt + index * step);\n}\n"],"names":["s","target","observer"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"billy-herrington-utils.umd.js","sources":["../src/utils/strings/index.ts","../src/utils/parsers/index.ts","../src/utils/observers/index.ts","../src/utils/math/index.ts","../src/utils/dom/index.ts","../src/utils/fetch/index.ts","../src/utils/events/index.ts","../src/utils/device/index.ts","../src/utils/async/index.ts","../src/utils/arrays/index.ts","../src/data-manager/index.ts","../src/utils/infinite-scroll/index.ts"],"sourcesContent":["export function stringToWords(s: string): Array<string> {\n return s.split(\",\").map(s => s.trim().toLowerCase()).filter(_ => _);\n}\n\nexport function sanitizeStr(s: string) {\n return s?.replace(/\\n|\\t/, ' ').replace(/ {2,}/, ' ').trim().toLowerCase() || \"\";\n}\n","export function formatTimeToHHMMSS(timeString: string): string {\n const regex: RegExp = /(?:(\\d+)\\s*h\\s*)?(?:(\\d+)\\s*mi?n?\\s*)?(?:(\\d+)\\s*sec)?/;\n const match: RegExpMatchArray | null = timeString.match(regex);\n const h: number = parseInt(match?.[1] || '0');\n const m: number = parseInt(match?.[2] || '0');\n const s: number = parseInt(match?.[3] || '0');\n const pad = (num: number): string => String(num).padStart(2, '0');\n return `${pad(h)}:${pad(m)}:${pad(s)}`;\n}\n\n// \"01:22:03\" -> 4923\nexport function timeToSeconds(t: string): number {\n const r = /sec|min|h|m/.test(t) ? formatTimeToHHMMSS(t) : t;\n return (r?.match(/\\d+/gm) || [0])\n .reverse()\n .map((s, i) => parseInt(s as string) * 60 ** i)\n .reduce((a, b) => a + b);\n}\n\nexport function parseIntegerOr(n: string | number, or: number): number {\n return (num => Number.isNaN(num) ? or : num)(parseInt(n as string));\n}\n\n// \"data:02;body+head:async;void:;zero:;\"\nexport function parseDataParams(str: string): Record<string, string> {\n return str.split(';').reduce((acc, s) => {\n const parsed = s.match(/([\\+\\w]+):(\\w+)?/);\n if (parsed) {\n const [, key, value] = parsed;\n if (value) {\n key.split('+').forEach(p => { acc[p] = value; });\n }\n }\n return acc;\n }, {} as Record<string, string>);\n}\n\nexport function parseCSSUrl(s: string) {\n return s.replace(/url\\(\"|\\\"\\).*/g, '');\n}\n","export class Observer {\n public observer: IntersectionObserver;\n constructor(private callback: (entry: Element) => void) {\n this.observer = new IntersectionObserver(this.handleIntersection.bind(this));\n }\n\n observe(target: Element) {\n this.observer.observe(target);\n }\n\n throttle(target: Element, throttleTime: number) {\n this.observer.unobserve(target);\n setTimeout(() => this.observer.observe(target), throttleTime);\n }\n\n handleIntersection(entries: Iterable<IntersectionObserverEntry>) {\n for (const entry of entries) {\n if (entry.isIntersecting) {\n this.callback(entry.target);\n }\n }\n }\n\n static observeWhile(\n target: Element,\n callback: () => Promise<boolean> | boolean,\n throttleTime: number,\n ) {\n const observer_ = new Observer(async (target: Element) => {\n const condition = await callback();\n if (condition) observer_.throttle(target, throttleTime);\n });\n observer_.observe(target);\n return observer_;\n }\n}\n\nexport class LazyImgLoader {\n public lazyImgObserver: Observer;\n private attributeName = 'data-lazy-load';\n\n constructor(shouldDelazify: (target: Element) => boolean) {\n this.lazyImgObserver = new Observer((target: Element) => {\n if (shouldDelazify(target)) {\n this.delazify(target as HTMLImageElement);\n }\n });\n }\n\n lazify(_target: Element, img: HTMLImageElement, imgSrc: string) {\n if (!img || !imgSrc) return;\n img.setAttribute(this.attributeName, imgSrc);\n img.src = '';\n this.lazyImgObserver.observe(img);\n }\n\n delazify = (target: HTMLImageElement) => {\n this.lazyImgObserver.observer.unobserve(target);\n target.src = target.getAttribute(this.attributeName) as string;\n target.removeAttribute(this.attributeName);\n };\n}\n","export function circularShift(n: number, c = 6, s = 1): number {\n return (n + s) % c || c;\n}\n","export function parseDom(html: string): HTMLElement {\n const parsed = new DOMParser().parseFromString(html, 'text/html').body;\n return parsed.children.length > 1 ? parsed : parsed.firstElementChild as HTMLElement;\n}\n\nexport function copyAttributes(target: HTMLElement | Element, source: HTMLElement | Element) {\n for (const attr of source.attributes) {\n attr.nodeValue && target.setAttribute(attr.nodeName, attr.nodeValue);\n }\n}\n\nexport function replaceElementTag(e: HTMLElement | Element, tagName: string) {\n const newTagElement = document.createElement(tagName);\n copyAttributes(newTagElement, e);\n newTagElement.innerHTML = e.innerHTML;\n e.parentNode?.replaceChild(newTagElement, e);\n return newTagElement;\n}\n\nexport function getAllUniqueParents(elements: HTMLCollection): Array<HTMLElement | Element> {\n return Array.from(elements).reduce((acc, v) => {\n if (v.parentElement && !acc.includes(v.parentElement as HTMLElement)) { acc.push(v.parentElement); }\n return acc;\n }, [] as Array<HTMLElement | Element>);\n}\n\nexport function findNextSibling(el: HTMLElement | Element) {\n if (el.nextElementSibling) return el.nextElementSibling;\n if (el.parentElement) return findNextSibling(el.parentElement);\n return null;\n}\n\nexport function waitForElementExists(parent: HTMLElement | Element, selector: string, callback: (el: Element) => void): void {\n const observer = new MutationObserver((_mutations) => {\n const el = parent.querySelector(selector);\n if (el) {\n observer.disconnect();\n callback(el);\n }\n });\n observer.observe(document.body, { childList: true, subtree: true });\n}\n\nexport function watchElementChildrenCount(element: HTMLElement | Element,\n callback: (observer: MutationObserver, count: number) => void): void {\n let count = element.children.length;\n const observer = new MutationObserver((mutationList, observer) => {\n for (const mutation of mutationList) {\n if (mutation.type === \"childList\") {\n if (count !== element.children.length) {\n count = element.children.length;\n callback(observer, count);\n }\n }\n }\n });\n observer.observe(element, { childList: true });\n}\n\nexport function watchDomChangesWithThrottle(\n element: HTMLElement | Element, \n callback: () => void,\n throttle = 1000,\n times = Infinity,\n options: Record<string, boolean> = { childList: true, subtree: true, attributes: true }\n) {\n let lastMutationTime: number;\n let timeout: number;\n let times_ = times;\n const observer = new MutationObserver((_mutationList, _observer) => {\n if (times_ !== Infinity && times_ < 1) {\n observer.disconnect();\n return;\n }\n times_--;\n const now = Date.now();\n if (lastMutationTime && now - lastMutationTime < throttle) {\n timeout && clearTimeout(timeout);\n }\n timeout = setTimeout(callback, throttle);\n lastMutationTime = now;\n });\n observer.observe(element, options);\n return observer;\n}\n\nexport function downloader(options = { append: \"\", after: \"\", button: \"\", cbBefore: () => { } }) {\n const btn = parseDom(options.button);\n\n if (options.append) document.querySelector(options.append)?.append(btn);\n if (options.after) document.querySelector(options.after)?.after(btn);\n\n btn.addEventListener('click', (e) => {\n e.preventDefault();\n\n if (options.cbBefore) options.cbBefore();\n\n waitForElementExists(document.body, 'video', (video: Element) => {\n window.location.href = video.getAttribute('src') as string;\n });\n });\n}","import { parseDom } from '../dom';\n\nexport const MOBILE_UA = [\n 'Mozilla/5.0 (Linux; Android 10; K)',\n 'AppleWebKit/537.36 (KHTML, like Gecko)',\n 'Chrome/114.0.0.0 Mobile Safari/537.36',\n].join(' ');\n\nexport function fetchWith(\n url: string,\n options: Record<string, boolean> = { html: false, mobile: false },\n) {\n const reqOpts = {};\n if (options.mobile) Object.assign(reqOpts, { headers: new Headers({ 'User-Agent': MOBILE_UA }) });\n return fetch(url, reqOpts)\n .then((r) => r.text())\n .then((r) => (options.html ? parseDom(r) : r));\n}\n\nexport const fetchHtml = (url: string) => fetchWith(url, { html: true }) as Promise<HTMLElement>;\n\nexport const fetchText = (url: string) => fetchWith(url) as Promise<string>;\n\nexport function objectToFormData(object: Record<string, number | boolean | string>): FormData {\n const formData = new FormData();\n Object.entries(object).forEach(([k, v]) => formData.append(k, v as string));\n return formData;\n}\n","export function listenEvents(dom: HTMLElement | Element, events: Array<string>, callback: (e: Event) => void): void {\n for (const e of events) {\n dom.addEventListener(e, callback, true);\n }\n}\n\nexport class Tick {\n private tick?: number;\n private callbackFinal?: () => void;\n\n constructor(private delay: number, private startImmediate: boolean = true) {}\n\n public start(callback: () => void, callbackFinal?: () => void): void {\n this.stop();\n this.callbackFinal = callbackFinal;\n if (this.startImmediate) callback();\n this.tick = window.setInterval(callback, this.delay);\n }\n\n public stop(): void {\n if (this.tick !== undefined) {\n clearInterval(this.tick);\n this.tick = undefined;\n }\n if (this.callbackFinal) {\n this.callbackFinal();\n this.callbackFinal = undefined;\n }\n }\n}\n","export function isMob() {\n return /iPhone|Android/i.test(navigator.userAgent);\n}","// https://2ality.com/2016/10/asynchronous-iteration.html\nexport async function computeAsyncOneAtTime(iterable: Iterable<() => Promise<void>>) {\n const res = [];\n for await (const f of iterable) {\n res.push(await f());\n }\n return res;\n}\n\nexport function wait(milliseconds: number) {\n return new Promise((resolve) => setTimeout(resolve, milliseconds));\n}\n\ninterface AsyncPoolTask {\n v: () => Promise<void>;\n p: number;\n}\n\nexport class AsyncPool {\n private cur = 0;\n private finished: Promise<boolean>;\n private _resolve?: (value: boolean | PromiseLike<boolean>) => void;\n\n public static async doNAsyncAtOnce(max = 1, pool: Array<AsyncPoolTask | (() => Promise<void>)> = []) {\n const spool = new AsyncPool(max);\n pool.forEach(f => spool.push(f));\n return spool.run();\n }\n\n constructor(private max = 1, private pool: Array<AsyncPoolTask> = []) {\n this.finished = new Promise((resolve) => {\n this._resolve = resolve;\n });\n }\n\n private getHighPriorityFirst(p = 0): (() => Promise<void>) | undefined {\n if (p > 3 || this.pool.length === 0) return undefined;\n const i = this.pool.findIndex((e) => e.p === p);\n if (i >= 0) {\n const res = this.pool[i].v;\n this.pool.splice(i, 1);\n return res;\n }\n return this.getHighPriorityFirst(p + 1);\n }\n\n private async runTask() {\n this.cur++;\n const f = this.getHighPriorityFirst();\n await f?.();\n this.cur--;\n this.runTasks();\n }\n\n private runTasks() {\n if (!this.pool.length) {\n this._resolve?.(true);\n return;\n }\n if (this.cur < this.max) {\n this.runTask();\n this.runTasks();\n }\n }\n\n public async run() {\n this.runTasks();\n return this.finished;\n }\n\n public push(x: AsyncPoolTask | (() => Promise<void>)) {\n this.pool.push('p' in x ? x : { v: x, p: 0 });\n }\n}\n\n","export function chunks<T>(arr: Array<T>, n: number): Array<Array<T>> {\n return Array.from({ length: Math.ceil(arr.length / n) }, (_, i) => arr.slice(i * n, i * n + n));\n}\n\nexport function range(size: number, startAt: number = 1, step: number = 1): number[] {\n return Array.from({ length: size }, (_, index) => startAt + index * step);\n}\n","import { LazyImgLoader } from '../utils/observers';\nimport { stringToWords } from '../utils/strings';\n\ninterface DataFilterState {\n filterPublic: boolean;\n filterPrivate: boolean;\n filterDuration: boolean;\n filterDurationFrom: number;\n filterDurationTo: number;\n filterExclude: boolean;\n filterExcludeWords: string;\n filterInclude: boolean;\n filterIncludeWords: string;\n}\n\ninterface FilterResult {\n tag: string;\n condition: boolean;\n}\n\ntype FilterInput = Record<string, string | number | boolean | HTMLElement>;\ntype FilterFunction = (v: FilterInput) => FilterResult;\n\nclass DataFilter {\n private state: DataFilterState;\n private rules: IRules;\n public filters: { [key: string]: () => FilterFunction };\n\n constructor(rules: IRules, state: DataFilterState) {\n this.state = state;\n this.rules = rules;\n\n const methods = Object.getOwnPropertyNames(this);\n this.filters = methods.reduce((acc: { [key: string]: () => FilterFunction }, k) => {\n if (k in this.state) {\n acc[k] = this[k as keyof DataFilter] as unknown as () => FilterFunction;\n //@ts-ignore\n GM_addStyle(`.filter-${k.toLowerCase().slice(6)} { display: none !important; }`);\n }\n return acc;\n }, {});\n }\n\n filterPublic = (): FilterFunction => {\n return (v: FilterInput) => {\n const isPublic = !this.rules.IS_PRIVATE(v.element as HTMLElement);\n return {\n tag: 'filter-public',\n condition: this.state.filterPublic && isPublic,\n };\n };\n };\n\n filterPrivate = (): FilterFunction => {\n return (v: FilterInput) => {\n const isPrivate = this.rules.IS_PRIVATE(v.element as HTMLElement);\n return {\n tag: 'filter-private',\n condition: this.state.filterPrivate && isPrivate,\n };\n };\n };\n\n filterDuration = (): FilterFunction => {\n return (v: FilterInput) => {\n const notInRange =\n (v.duration as number) < this.state.filterDurationFrom ||\n (v.duration as number) > this.state.filterDurationTo;\n return {\n tag: 'filter-duration',\n condition: this.state.filterDuration && notInRange,\n };\n };\n };\n\n filterExclude = (): FilterFunction => {\n const tags = DataManager.filterDSLToRegex(this.state.filterExcludeWords);\n return (v: FilterInput) => {\n const containTags = tags.some((tag) => tag.test(v.title as string));\n return {\n tag: 'filter-exclude',\n condition: this.state.filterExclude && containTags,\n };\n };\n };\n\n filterInclude = (): FilterFunction => {\n const tags = DataManager.filterDSLToRegex(this.state.filterIncludeWords);\n return (v: FilterInput) => {\n const containTagsNot = tags.some((tag) => !tag.test(v.title as string));\n return {\n tag: 'filter-include',\n condition: this.state.filterInclude && containTagsNot,\n };\n };\n };\n}\n\ninterface IRules {\n GET_THUMBS: (html: HTMLElement) => HTMLElement[];\n THUMB_URL: (thumbElement: HTMLElement) => string;\n THUMB_DATA: (thumbElement: HTMLElement) => { title: string; duration: number };\n THUMB_IMG_DATA: (thumbElement: HTMLElement) => { img: HTMLElement; imgSrc: string };\n CONTAINER: HTMLElement;\n IS_PRIVATE: (element: HTMLElement) => boolean;\n}\n\nexport class DataManager {\n private rules: IRules;\n private state: DataFilterState;\n private data: Map<string, FilterInput>;\n private lazyImgLoader: LazyImgLoader;\n public dataFilters: { [key: string]: () => FilterFunction };\n\n constructor(rules: IRules, state: DataFilterState) {\n this.rules = rules;\n this.state = state;\n this.data = new Map();\n this.lazyImgLoader = new LazyImgLoader(\n (target: Element) => !this.isFiltered(target as HTMLElement),\n );\n this.dataFilters = new DataFilter(rules, state).filters;\n }\n\n static filterDSLToRegex(str: string): RegExp[] {\n const toFullWord = (w: string) => `(^|\\\\ )${w}($|\\\\ )`;\n const str_ = str.replace(/f\\:(\\w+)/g, (_, w) => toFullWord(w));\n return stringToWords(str_).map((expr: string) => new RegExp(expr, 'i'));\n }\n\n isFiltered(el: HTMLElement): boolean {\n return el.className.includes('filtered');\n }\n\n applyFilters = (filters: { [key: string]: boolean }, offset = 0): void => {\n const filtersToApply = Object.keys(filters)\n .filter((k) => Object.hasOwn(this.dataFilters, k))\n .map((k) => this.dataFilters[k]());\n\n if (filtersToApply.length === 0) return;\n\n const updates: (() => void)[] = [];\n let offset_counter = 1;\n for (const v of this.data.values()) {\n if (++offset_counter > offset) {\n for (const f of filtersToApply) {\n const { tag, condition } = f(v as FilterInput);\n updates.push(() => (v.element as HTMLElement).classList.toggle(tag, condition));\n }\n }\n }\n\n requestAnimationFrame(() => {\n updates.forEach((update) => update());\n });\n };\n\n filterAll = (offset?: number): void => {\n const filters = Object.assign(\n {},\n ...Object.keys(this.dataFilters).map((f) => ({\n [f]: this.state[f as keyof DataFilterState],\n })),\n );\n this.applyFilters(filters, offset);\n };\n\n handleLoadedHTML = (\n html: HTMLElement,\n container?: HTMLElement,\n removeDuplicates = false,\n shouldLazify = true,\n ): void => {\n const thumbs = this.rules.GET_THUMBS(html);\n const data_offset = this.data.size;\n\n for (const thumbElement of thumbs) {\n const url = this.rules.THUMB_URL(thumbElement);\n if (!url || this.data.has(url)) {\n if (removeDuplicates) thumbElement.remove();\n continue;\n }\n\n const { title, duration } = this.rules.THUMB_DATA(thumbElement);\n this.data.set(url, { element: thumbElement, duration, title });\n\n if (shouldLazify) {\n const { img, imgSrc } = this.rules.THUMB_IMG_DATA(thumbElement);\n this.lazyImgLoader.lazify(thumbElement, img as HTMLImageElement, imgSrc);\n }\n\n const parent = container || this.rules.CONTAINER;\n if (!parent.contains(thumbElement)) parent.appendChild(thumbElement);\n }\n\n this.filterAll(data_offset);\n };\n}\n","import { fetchHtml } from '../fetch';\nimport { Observer } from '../observers';\n\ninterface IInfiniteScroller {\n delay: number;\n enabled: boolean;\n paginationOffset: number;\n paginationLast: number;\n paginationElement: HTMLElement;\n paginationUrlGenerator: (offset: number) => string;\n handleHtmlCallback: (document: HTMLElement) => void;\n intersectionObservable?: HTMLElement;\n alternativeGenerator?: () => OffsetGenerator;\n}\n\ninterface GeneratorResult {\n url: string;\n offset: number;\n}\n\ntype OffsetGenerator = Generator<GeneratorResult> | AsyncGenerator<GeneratorResult>;\n\nexport class InfiniteScroller {\n public paginationGenerator: OffsetGenerator;\n public enabled: boolean;\n public delay: number;\n public paginationOffset: number;\n public paginationLast: number;\n private handleHtmlCallback: (document: HTMLElement) => void;\n\n constructor({\n enabled,\n handleHtmlCallback,\n delay,\n alternativeGenerator,\n paginationOffset,\n paginationLast,\n paginationElement,\n paginationUrlGenerator,\n intersectionObservable,\n }: IInfiniteScroller) {\n this.enabled = enabled;\n this.delay = delay;\n this.paginationOffset = paginationOffset;\n this.paginationLast = paginationLast;\n this.handleHtmlCallback = handleHtmlCallback;\n\n this.paginationGenerator =\n alternativeGenerator?.() ??\n InfiniteScroller.createPaginationGenerator(\n paginationOffset,\n paginationLast,\n paginationUrlGenerator,\n );\n\n const observable = intersectionObservable || paginationElement;\n Observer.observeWhile(observable, this.generatorConsumer, this.delay);\n }\n\n // this.stateLocale.pagIndexLast = paginationLast;\n // this.stateLocale.pagIndexCur = paginationOffset;\n // infiniteScrollEnabled: boolean;\n\n private onScrollCBs: Array<(scroller: InfiniteScroller) => void> = [];\n\n public onScroll(callback: (scroller: InfiniteScroller) => void) {\n this.onScrollCBs.push(callback);\n return this;\n }\n\n private _onScroll() {\n this.onScrollCBs.forEach((cb) => cb(this));\n }\n\n generatorConsumer = async () => {\n if (!this.enabled) return false;\n const {\n value: { url, offset } = {},\n done,\n } = await this.paginationGenerator.next();\n if (!done) {\n const nextPageHTML = await fetchHtml(url);\n const prevScrollPos = document.documentElement.scrollTop;\n this.paginationOffset = offset;\n this.handleHtmlCallback(nextPageHTML);\n this._onScroll();\n window.scrollTo(0, prevScrollPos);\n }\n return !done;\n };\n\n static *createPaginationGenerator(\n currentPage: number,\n totalPages: number,\n generateURL: (offset: number) => string,\n ): OffsetGenerator {\n for (let offset = currentPage + 1; offset <= totalPages; offset++) {\n const url = generateURL(offset);\n yield { url, offset };\n }\n }\n}\n"],"names":["s","target","observer"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -26,6 +26,36 @@ export declare function computeAsyncOneAtTime(iterable: Iterable<() => Promise<v
|
|
|
26
26
|
|
|
27
27
|
export declare function copyAttributes(target: HTMLElement | Element, source: HTMLElement | Element): void;
|
|
28
28
|
|
|
29
|
+
declare interface DataFilterState {
|
|
30
|
+
filterPublic: boolean;
|
|
31
|
+
filterPrivate: boolean;
|
|
32
|
+
filterDuration: boolean;
|
|
33
|
+
filterDurationFrom: number;
|
|
34
|
+
filterDurationTo: number;
|
|
35
|
+
filterExclude: boolean;
|
|
36
|
+
filterExcludeWords: string;
|
|
37
|
+
filterInclude: boolean;
|
|
38
|
+
filterIncludeWords: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export declare class DataManager {
|
|
42
|
+
private rules;
|
|
43
|
+
private state;
|
|
44
|
+
private data;
|
|
45
|
+
private lazyImgLoader;
|
|
46
|
+
dataFilters: {
|
|
47
|
+
[key: string]: () => FilterFunction;
|
|
48
|
+
};
|
|
49
|
+
constructor(rules: IRules, state: DataFilterState);
|
|
50
|
+
static filterDSLToRegex(str: string): RegExp[];
|
|
51
|
+
isFiltered(el: HTMLElement): boolean;
|
|
52
|
+
applyFilters: (filters: {
|
|
53
|
+
[key: string]: boolean;
|
|
54
|
+
}, offset?: number) => void;
|
|
55
|
+
filterAll: (offset?: number) => void;
|
|
56
|
+
handleLoadedHTML: (html: HTMLElement, container?: HTMLElement, removeDuplicates?: boolean, shouldLazify?: boolean) => void;
|
|
57
|
+
}
|
|
58
|
+
|
|
29
59
|
export declare function downloader(options?: {
|
|
30
60
|
append: string;
|
|
31
61
|
after: string;
|
|
@@ -33,16 +63,72 @@ export declare function downloader(options?: {
|
|
|
33
63
|
cbBefore: () => void;
|
|
34
64
|
}): void;
|
|
35
65
|
|
|
36
|
-
export declare const fetchHtml: (url: string) => Promise<
|
|
66
|
+
export declare const fetchHtml: (url: string) => Promise<HTMLElement>;
|
|
37
67
|
|
|
38
|
-
export declare const fetchText: (url: string) => Promise<string
|
|
68
|
+
export declare const fetchText: (url: string) => Promise<string>;
|
|
39
69
|
|
|
40
70
|
export declare function fetchWith(url: string, options?: Record<string, boolean>): Promise<string | HTMLElement>;
|
|
41
71
|
|
|
72
|
+
declare type FilterFunction = (v: FilterInput) => FilterResult;
|
|
73
|
+
|
|
74
|
+
declare type FilterInput = Record<string, string | number | boolean | HTMLElement>;
|
|
75
|
+
|
|
76
|
+
declare interface FilterResult {
|
|
77
|
+
tag: string;
|
|
78
|
+
condition: boolean;
|
|
79
|
+
}
|
|
80
|
+
|
|
42
81
|
export declare function findNextSibling(el: HTMLElement | Element): Element | null;
|
|
43
82
|
|
|
83
|
+
declare interface GeneratorResult {
|
|
84
|
+
url: string;
|
|
85
|
+
offset: number;
|
|
86
|
+
}
|
|
87
|
+
|
|
44
88
|
export declare function getAllUniqueParents(elements: HTMLCollection): Array<HTMLElement | Element>;
|
|
45
89
|
|
|
90
|
+
declare interface IInfiniteScroller {
|
|
91
|
+
delay: number;
|
|
92
|
+
enabled: boolean;
|
|
93
|
+
paginationOffset: number;
|
|
94
|
+
paginationLast: number;
|
|
95
|
+
paginationElement: HTMLElement;
|
|
96
|
+
paginationUrlGenerator: (offset: number) => string;
|
|
97
|
+
handleHtmlCallback: (document: HTMLElement) => void;
|
|
98
|
+
intersectionObservable?: HTMLElement;
|
|
99
|
+
alternativeGenerator?: () => OffsetGenerator;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export declare class InfiniteScroller {
|
|
103
|
+
paginationGenerator: OffsetGenerator;
|
|
104
|
+
enabled: boolean;
|
|
105
|
+
delay: number;
|
|
106
|
+
paginationOffset: number;
|
|
107
|
+
paginationLast: number;
|
|
108
|
+
private handleHtmlCallback;
|
|
109
|
+
constructor({ enabled, handleHtmlCallback, delay, alternativeGenerator, paginationOffset, paginationLast, paginationElement, paginationUrlGenerator, intersectionObservable, }: IInfiniteScroller);
|
|
110
|
+
private onScrollCBs;
|
|
111
|
+
onScroll(callback: (scroller: InfiniteScroller) => void): this;
|
|
112
|
+
private _onScroll;
|
|
113
|
+
generatorConsumer: () => Promise<boolean>;
|
|
114
|
+
static createPaginationGenerator(currentPage: number, totalPages: number, generateURL: (offset: number) => string): OffsetGenerator;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
declare interface IRules {
|
|
118
|
+
GET_THUMBS: (html: HTMLElement) => HTMLElement[];
|
|
119
|
+
THUMB_URL: (thumbElement: HTMLElement) => string;
|
|
120
|
+
THUMB_DATA: (thumbElement: HTMLElement) => {
|
|
121
|
+
title: string;
|
|
122
|
+
duration: number;
|
|
123
|
+
};
|
|
124
|
+
THUMB_IMG_DATA: (thumbElement: HTMLElement) => {
|
|
125
|
+
img: HTMLElement;
|
|
126
|
+
imgSrc: string;
|
|
127
|
+
};
|
|
128
|
+
CONTAINER: HTMLElement;
|
|
129
|
+
IS_PRIVATE: (element: HTMLElement) => boolean;
|
|
130
|
+
}
|
|
131
|
+
|
|
46
132
|
export declare function isMob(): boolean;
|
|
47
133
|
|
|
48
134
|
export declare class LazyImgLoader {
|
|
@@ -69,6 +155,8 @@ export declare class Observer {
|
|
|
69
155
|
static observeWhile(target: Element, callback: () => Promise<boolean> | boolean, throttleTime: number): Observer;
|
|
70
156
|
}
|
|
71
157
|
|
|
158
|
+
declare type OffsetGenerator = Generator<GeneratorResult> | AsyncGenerator<GeneratorResult>;
|
|
159
|
+
|
|
72
160
|
export declare function parseCSSUrl(s: string): string;
|
|
73
161
|
|
|
74
162
|
export declare function parseDataParams(str: string): Record<string, string>;
|
|
@@ -101,7 +189,7 @@ export declare function wait(milliseconds: number): Promise<unknown>;
|
|
|
101
189
|
|
|
102
190
|
export declare function waitForElementExists(parent: HTMLElement | Element, selector: string, callback: (el: Element) => void): void;
|
|
103
191
|
|
|
104
|
-
export declare function watchDomChangesWithThrottle(element: HTMLElement | Element, callback: () => void, throttle?: number, options?: Record<string, boolean>):
|
|
192
|
+
export declare function watchDomChangesWithThrottle(element: HTMLElement | Element, callback: () => void, throttle?: number, times?: number, options?: Record<string, boolean>): MutationObserver;
|
|
105
193
|
|
|
106
194
|
export declare function watchElementChildrenCount(element: HTMLElement | Element, callback: (observer: MutationObserver, count: number) => void): void;
|
|
107
195
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "billy-herrington-utils",
|
|
3
3
|
"description": "daddy told us not to be ashamed of our utils",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.3.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": ["utils", "observer", "dom", "fetch", "arrays", "typescript"],
|
|
7
7
|
"author": "smartacephale atm.mormon@protonmail.com (https://github.com/smartacephale)",
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { LazyImgLoader } from '../utils/observers';
|
|
2
|
+
import { stringToWords } from '../utils/strings';
|
|
3
|
+
|
|
4
|
+
interface DataFilterState {
|
|
5
|
+
filterPublic: boolean;
|
|
6
|
+
filterPrivate: boolean;
|
|
7
|
+
filterDuration: boolean;
|
|
8
|
+
filterDurationFrom: number;
|
|
9
|
+
filterDurationTo: number;
|
|
10
|
+
filterExclude: boolean;
|
|
11
|
+
filterExcludeWords: string;
|
|
12
|
+
filterInclude: boolean;
|
|
13
|
+
filterIncludeWords: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface FilterResult {
|
|
17
|
+
tag: string;
|
|
18
|
+
condition: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type FilterInput = Record<string, string | number | boolean | HTMLElement>;
|
|
22
|
+
type FilterFunction = (v: FilterInput) => FilterResult;
|
|
23
|
+
|
|
24
|
+
class DataFilter {
|
|
25
|
+
private state: DataFilterState;
|
|
26
|
+
private rules: IRules;
|
|
27
|
+
public filters: { [key: string]: () => FilterFunction };
|
|
28
|
+
|
|
29
|
+
constructor(rules: IRules, state: DataFilterState) {
|
|
30
|
+
this.state = state;
|
|
31
|
+
this.rules = rules;
|
|
32
|
+
|
|
33
|
+
const methods = Object.getOwnPropertyNames(this);
|
|
34
|
+
this.filters = methods.reduce((acc: { [key: string]: () => FilterFunction }, k) => {
|
|
35
|
+
if (k in this.state) {
|
|
36
|
+
acc[k] = this[k as keyof DataFilter] as unknown as () => FilterFunction;
|
|
37
|
+
//@ts-ignore
|
|
38
|
+
GM_addStyle(`.filter-${k.toLowerCase().slice(6)} { display: none !important; }`);
|
|
39
|
+
}
|
|
40
|
+
return acc;
|
|
41
|
+
}, {});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
filterPublic = (): FilterFunction => {
|
|
45
|
+
return (v: FilterInput) => {
|
|
46
|
+
const isPublic = !this.rules.IS_PRIVATE(v.element as HTMLElement);
|
|
47
|
+
return {
|
|
48
|
+
tag: 'filter-public',
|
|
49
|
+
condition: this.state.filterPublic && isPublic,
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
filterPrivate = (): FilterFunction => {
|
|
55
|
+
return (v: FilterInput) => {
|
|
56
|
+
const isPrivate = this.rules.IS_PRIVATE(v.element as HTMLElement);
|
|
57
|
+
return {
|
|
58
|
+
tag: 'filter-private',
|
|
59
|
+
condition: this.state.filterPrivate && isPrivate,
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
filterDuration = (): FilterFunction => {
|
|
65
|
+
return (v: FilterInput) => {
|
|
66
|
+
const notInRange =
|
|
67
|
+
(v.duration as number) < this.state.filterDurationFrom ||
|
|
68
|
+
(v.duration as number) > this.state.filterDurationTo;
|
|
69
|
+
return {
|
|
70
|
+
tag: 'filter-duration',
|
|
71
|
+
condition: this.state.filterDuration && notInRange,
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
filterExclude = (): FilterFunction => {
|
|
77
|
+
const tags = DataManager.filterDSLToRegex(this.state.filterExcludeWords);
|
|
78
|
+
return (v: FilterInput) => {
|
|
79
|
+
const containTags = tags.some((tag) => tag.test(v.title as string));
|
|
80
|
+
return {
|
|
81
|
+
tag: 'filter-exclude',
|
|
82
|
+
condition: this.state.filterExclude && containTags,
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
filterInclude = (): FilterFunction => {
|
|
88
|
+
const tags = DataManager.filterDSLToRegex(this.state.filterIncludeWords);
|
|
89
|
+
return (v: FilterInput) => {
|
|
90
|
+
const containTagsNot = tags.some((tag) => !tag.test(v.title as string));
|
|
91
|
+
return {
|
|
92
|
+
tag: 'filter-include',
|
|
93
|
+
condition: this.state.filterInclude && containTagsNot,
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
interface IRules {
|
|
100
|
+
GET_THUMBS: (html: HTMLElement) => HTMLElement[];
|
|
101
|
+
THUMB_URL: (thumbElement: HTMLElement) => string;
|
|
102
|
+
THUMB_DATA: (thumbElement: HTMLElement) => { title: string; duration: number };
|
|
103
|
+
THUMB_IMG_DATA: (thumbElement: HTMLElement) => { img: HTMLElement; imgSrc: string };
|
|
104
|
+
CONTAINER: HTMLElement;
|
|
105
|
+
IS_PRIVATE: (element: HTMLElement) => boolean;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export class DataManager {
|
|
109
|
+
private rules: IRules;
|
|
110
|
+
private state: DataFilterState;
|
|
111
|
+
private data: Map<string, FilterInput>;
|
|
112
|
+
private lazyImgLoader: LazyImgLoader;
|
|
113
|
+
public dataFilters: { [key: string]: () => FilterFunction };
|
|
114
|
+
|
|
115
|
+
constructor(rules: IRules, state: DataFilterState) {
|
|
116
|
+
this.rules = rules;
|
|
117
|
+
this.state = state;
|
|
118
|
+
this.data = new Map();
|
|
119
|
+
this.lazyImgLoader = new LazyImgLoader(
|
|
120
|
+
(target: Element) => !this.isFiltered(target as HTMLElement),
|
|
121
|
+
);
|
|
122
|
+
this.dataFilters = new DataFilter(rules, state).filters;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
static filterDSLToRegex(str: string): RegExp[] {
|
|
126
|
+
const toFullWord = (w: string) => `(^|\\ )${w}($|\\ )`;
|
|
127
|
+
const str_ = str.replace(/f\:(\w+)/g, (_, w) => toFullWord(w));
|
|
128
|
+
return stringToWords(str_).map((expr: string) => new RegExp(expr, 'i'));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
isFiltered(el: HTMLElement): boolean {
|
|
132
|
+
return el.className.includes('filtered');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
applyFilters = (filters: { [key: string]: boolean }, offset = 0): void => {
|
|
136
|
+
const filtersToApply = Object.keys(filters)
|
|
137
|
+
.filter((k) => Object.hasOwn(this.dataFilters, k))
|
|
138
|
+
.map((k) => this.dataFilters[k]());
|
|
139
|
+
|
|
140
|
+
if (filtersToApply.length === 0) return;
|
|
141
|
+
|
|
142
|
+
const updates: (() => void)[] = [];
|
|
143
|
+
let offset_counter = 1;
|
|
144
|
+
for (const v of this.data.values()) {
|
|
145
|
+
if (++offset_counter > offset) {
|
|
146
|
+
for (const f of filtersToApply) {
|
|
147
|
+
const { tag, condition } = f(v as FilterInput);
|
|
148
|
+
updates.push(() => (v.element as HTMLElement).classList.toggle(tag, condition));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
requestAnimationFrame(() => {
|
|
154
|
+
updates.forEach((update) => update());
|
|
155
|
+
});
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
filterAll = (offset?: number): void => {
|
|
159
|
+
const filters = Object.assign(
|
|
160
|
+
{},
|
|
161
|
+
...Object.keys(this.dataFilters).map((f) => ({
|
|
162
|
+
[f]: this.state[f as keyof DataFilterState],
|
|
163
|
+
})),
|
|
164
|
+
);
|
|
165
|
+
this.applyFilters(filters, offset);
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
handleLoadedHTML = (
|
|
169
|
+
html: HTMLElement,
|
|
170
|
+
container?: HTMLElement,
|
|
171
|
+
removeDuplicates = false,
|
|
172
|
+
shouldLazify = true,
|
|
173
|
+
): void => {
|
|
174
|
+
const thumbs = this.rules.GET_THUMBS(html);
|
|
175
|
+
const data_offset = this.data.size;
|
|
176
|
+
|
|
177
|
+
for (const thumbElement of thumbs) {
|
|
178
|
+
const url = this.rules.THUMB_URL(thumbElement);
|
|
179
|
+
if (!url || this.data.has(url)) {
|
|
180
|
+
if (removeDuplicates) thumbElement.remove();
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const { title, duration } = this.rules.THUMB_DATA(thumbElement);
|
|
185
|
+
this.data.set(url, { element: thumbElement, duration, title });
|
|
186
|
+
|
|
187
|
+
if (shouldLazify) {
|
|
188
|
+
const { img, imgSrc } = this.rules.THUMB_IMG_DATA(thumbElement);
|
|
189
|
+
this.lazyImgLoader.lazify(thumbElement, img as HTMLImageElement, imgSrc);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const parent = container || this.rules.CONTAINER;
|
|
193
|
+
if (!parent.contains(thumbElement)) parent.appendChild(thumbElement);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
this.filterAll(data_offset);
|
|
197
|
+
};
|
|
198
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export { stringToWords, sanitizeStr } from
|
|
2
|
-
export { timeToSeconds, parseCSSUrl, parseDataParams, parseIntegerOr } from
|
|
3
|
-
export { Observer, LazyImgLoader } from
|
|
4
|
-
export { circularShift } from
|
|
5
|
-
export { MOBILE_UA, fetchHtml, fetchText, fetchWith, objectToFormData } from
|
|
6
|
-
export { Tick, listenEvents } from
|
|
1
|
+
export { stringToWords, sanitizeStr } from './utils/strings';
|
|
2
|
+
export { timeToSeconds, parseCSSUrl, parseDataParams, parseIntegerOr } from './utils/parsers';
|
|
3
|
+
export { Observer, LazyImgLoader } from './utils/observers';
|
|
4
|
+
export { circularShift } from './utils/math';
|
|
5
|
+
export { MOBILE_UA, fetchHtml, fetchText, fetchWith, objectToFormData } from './utils/fetch';
|
|
6
|
+
export { Tick, listenEvents } from './utils/events';
|
|
7
7
|
export {
|
|
8
8
|
parseDom,
|
|
9
9
|
copyAttributes,
|
|
@@ -13,8 +13,10 @@ export {
|
|
|
13
13
|
replaceElementTag,
|
|
14
14
|
waitForElementExists,
|
|
15
15
|
watchDomChangesWithThrottle,
|
|
16
|
-
watchElementChildrenCount
|
|
17
|
-
} from
|
|
18
|
-
export { isMob } from
|
|
19
|
-
export { computeAsyncOneAtTime, AsyncPool, wait } from
|
|
20
|
-
export { chunks, range } from
|
|
16
|
+
watchElementChildrenCount,
|
|
17
|
+
} from './utils/dom';
|
|
18
|
+
export { isMob } from './utils/device';
|
|
19
|
+
export { computeAsyncOneAtTime, AsyncPool, wait } from './utils/async';
|
|
20
|
+
export { chunks, range } from './utils/arrays';
|
|
21
|
+
export { DataManager } from './data-manager';
|
|
22
|
+
export { InfiniteScroller } from './utils/infinite-scroll';
|
package/src/utils/fetch/index.ts
CHANGED
|
@@ -1,19 +1,25 @@
|
|
|
1
|
-
import { parseDom } from
|
|
1
|
+
import { parseDom } from '../dom';
|
|
2
2
|
|
|
3
3
|
export const MOBILE_UA = [
|
|
4
4
|
'Mozilla/5.0 (Linux; Android 10; K)',
|
|
5
5
|
'AppleWebKit/537.36 (KHTML, like Gecko)',
|
|
6
|
-
'Chrome/114.0.0.0 Mobile Safari/537.36'
|
|
6
|
+
'Chrome/114.0.0.0 Mobile Safari/537.36',
|
|
7
|
+
].join(' ');
|
|
7
8
|
|
|
8
|
-
export function fetchWith(
|
|
9
|
+
export function fetchWith(
|
|
10
|
+
url: string,
|
|
11
|
+
options: Record<string, boolean> = { html: false, mobile: false },
|
|
12
|
+
) {
|
|
9
13
|
const reqOpts = {};
|
|
10
|
-
if (options.mobile) Object.assign(reqOpts, { headers: new Headers({
|
|
11
|
-
return fetch(url, reqOpts)
|
|
14
|
+
if (options.mobile) Object.assign(reqOpts, { headers: new Headers({ 'User-Agent': MOBILE_UA }) });
|
|
15
|
+
return fetch(url, reqOpts)
|
|
16
|
+
.then((r) => r.text())
|
|
17
|
+
.then((r) => (options.html ? parseDom(r) : r));
|
|
12
18
|
}
|
|
13
19
|
|
|
14
|
-
export const fetchHtml = (url: string) => fetchWith(url, { html: true })
|
|
20
|
+
export const fetchHtml = (url: string) => fetchWith(url, { html: true }) as Promise<HTMLElement>;
|
|
15
21
|
|
|
16
|
-
export const fetchText = (url: string) => fetchWith(url)
|
|
22
|
+
export const fetchText = (url: string) => fetchWith(url) as Promise<string>;
|
|
17
23
|
|
|
18
24
|
export function objectToFormData(object: Record<string, number | boolean | string>): FormData {
|
|
19
25
|
const formData = new FormData();
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { fetchHtml } from '../fetch';
|
|
2
|
+
import { Observer } from '../observers';
|
|
3
|
+
|
|
4
|
+
interface IInfiniteScroller {
|
|
5
|
+
delay: number;
|
|
6
|
+
enabled: boolean;
|
|
7
|
+
paginationOffset: number;
|
|
8
|
+
paginationLast: number;
|
|
9
|
+
paginationElement: HTMLElement;
|
|
10
|
+
paginationUrlGenerator: (offset: number) => string;
|
|
11
|
+
handleHtmlCallback: (document: HTMLElement) => void;
|
|
12
|
+
intersectionObservable?: HTMLElement;
|
|
13
|
+
alternativeGenerator?: () => OffsetGenerator;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface GeneratorResult {
|
|
17
|
+
url: string;
|
|
18
|
+
offset: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type OffsetGenerator = Generator<GeneratorResult> | AsyncGenerator<GeneratorResult>;
|
|
22
|
+
|
|
23
|
+
export class InfiniteScroller {
|
|
24
|
+
public paginationGenerator: OffsetGenerator;
|
|
25
|
+
public enabled: boolean;
|
|
26
|
+
public delay: number;
|
|
27
|
+
public paginationOffset: number;
|
|
28
|
+
public paginationLast: number;
|
|
29
|
+
private handleHtmlCallback: (document: HTMLElement) => void;
|
|
30
|
+
|
|
31
|
+
constructor({
|
|
32
|
+
enabled,
|
|
33
|
+
handleHtmlCallback,
|
|
34
|
+
delay,
|
|
35
|
+
alternativeGenerator,
|
|
36
|
+
paginationOffset,
|
|
37
|
+
paginationLast,
|
|
38
|
+
paginationElement,
|
|
39
|
+
paginationUrlGenerator,
|
|
40
|
+
intersectionObservable,
|
|
41
|
+
}: IInfiniteScroller) {
|
|
42
|
+
this.enabled = enabled;
|
|
43
|
+
this.delay = delay;
|
|
44
|
+
this.paginationOffset = paginationOffset;
|
|
45
|
+
this.paginationLast = paginationLast;
|
|
46
|
+
this.handleHtmlCallback = handleHtmlCallback;
|
|
47
|
+
|
|
48
|
+
this.paginationGenerator =
|
|
49
|
+
alternativeGenerator?.() ??
|
|
50
|
+
InfiniteScroller.createPaginationGenerator(
|
|
51
|
+
paginationOffset,
|
|
52
|
+
paginationLast,
|
|
53
|
+
paginationUrlGenerator,
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const observable = intersectionObservable || paginationElement;
|
|
57
|
+
Observer.observeWhile(observable, this.generatorConsumer, this.delay);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// this.stateLocale.pagIndexLast = paginationLast;
|
|
61
|
+
// this.stateLocale.pagIndexCur = paginationOffset;
|
|
62
|
+
// infiniteScrollEnabled: boolean;
|
|
63
|
+
|
|
64
|
+
private onScrollCBs: Array<(scroller: InfiniteScroller) => void> = [];
|
|
65
|
+
|
|
66
|
+
public onScroll(callback: (scroller: InfiniteScroller) => void) {
|
|
67
|
+
this.onScrollCBs.push(callback);
|
|
68
|
+
return this;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private _onScroll() {
|
|
72
|
+
this.onScrollCBs.forEach((cb) => cb(this));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
generatorConsumer = async () => {
|
|
76
|
+
if (!this.enabled) return false;
|
|
77
|
+
const {
|
|
78
|
+
value: { url, offset } = {},
|
|
79
|
+
done,
|
|
80
|
+
} = await this.paginationGenerator.next();
|
|
81
|
+
if (!done) {
|
|
82
|
+
const nextPageHTML = await fetchHtml(url);
|
|
83
|
+
const prevScrollPos = document.documentElement.scrollTop;
|
|
84
|
+
this.paginationOffset = offset;
|
|
85
|
+
this.handleHtmlCallback(nextPageHTML);
|
|
86
|
+
this._onScroll();
|
|
87
|
+
window.scrollTo(0, prevScrollPos);
|
|
88
|
+
}
|
|
89
|
+
return !done;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
static *createPaginationGenerator(
|
|
93
|
+
currentPage: number,
|
|
94
|
+
totalPages: number,
|
|
95
|
+
generateURL: (offset: number) => string,
|
|
96
|
+
): OffsetGenerator {
|
|
97
|
+
for (let offset = currentPage + 1; offset <= totalPages; offset++) {
|
|
98
|
+
const url = generateURL(offset);
|
|
99
|
+
yield { url, offset };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -21,7 +21,11 @@ export class Observer {
|
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
static observeWhile(
|
|
24
|
+
static observeWhile(
|
|
25
|
+
target: Element,
|
|
26
|
+
callback: () => Promise<boolean> | boolean,
|
|
27
|
+
throttleTime: number,
|
|
28
|
+
) {
|
|
25
29
|
const observer_ = new Observer(async (target: Element) => {
|
|
26
30
|
const condition = await callback();
|
|
27
31
|
if (condition) observer_.throttle(target, throttleTime);
|
|
@@ -54,5 +58,5 @@ export class LazyImgLoader {
|
|
|
54
58
|
this.lazyImgObserver.observer.unobserve(target);
|
|
55
59
|
target.src = target.getAttribute(this.attributeName) as string;
|
|
56
60
|
target.removeAttribute(this.attributeName);
|
|
57
|
-
}
|
|
61
|
+
};
|
|
58
62
|
}
|