billy-herrington-utils 1.2.1 → 1.3.1
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 +205 -0
- package/dist/billy-herrington-utils.es.js.map +1 -1
- package/dist/billy-herrington-utils.umd.js +205 -0
- package/dist/billy-herrington-utils.umd.js.map +1 -1
- package/dist/index.d.ts +92 -2
- 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 +106 -0
- package/src/utils/observers/index.ts +6 -2
|
@@ -296,8 +296,213 @@ function chunks(arr, n) {
|
|
|
296
296
|
function range(size, startAt = 1, step = 1) {
|
|
297
297
|
return Array.from({ length: size }, (_, index) => startAt + index * step);
|
|
298
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 = true,
|
|
436
|
+
delay = 350,
|
|
437
|
+
writeHistory = false,
|
|
438
|
+
paginationOffset,
|
|
439
|
+
paginationLast,
|
|
440
|
+
paginationElement,
|
|
441
|
+
paginationUrlGenerator,
|
|
442
|
+
handleHtmlCallback,
|
|
443
|
+
alternativeGenerator,
|
|
444
|
+
intersectionObservable
|
|
445
|
+
}) {
|
|
446
|
+
__publicField(this, "paginationGenerator");
|
|
447
|
+
__publicField(this, "enabled");
|
|
448
|
+
__publicField(this, "delay");
|
|
449
|
+
__publicField(this, "paginationOffset");
|
|
450
|
+
__publicField(this, "paginationLast");
|
|
451
|
+
__publicField(this, "writeHistory");
|
|
452
|
+
__publicField(this, "handleHtmlCallback");
|
|
453
|
+
__publicField(this, "onScrollCBs", []);
|
|
454
|
+
__publicField(this, "generatorConsumer", async () => {
|
|
455
|
+
if (!this.enabled) return false;
|
|
456
|
+
const {
|
|
457
|
+
value: { url, offset } = {},
|
|
458
|
+
done
|
|
459
|
+
} = await this.paginationGenerator.next();
|
|
460
|
+
if (!done) {
|
|
461
|
+
const nextPageHTML = await fetchHtml(url);
|
|
462
|
+
const prevScrollPos = document.documentElement.scrollTop;
|
|
463
|
+
this.paginationOffset = offset;
|
|
464
|
+
this.handleHtmlCallback(nextPageHTML);
|
|
465
|
+
this._onScroll();
|
|
466
|
+
window.scrollTo(0, prevScrollPos);
|
|
467
|
+
if (this.writeHistory) {
|
|
468
|
+
history.replaceState({}, "", url);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
return !done;
|
|
472
|
+
});
|
|
473
|
+
this.enabled = enabled;
|
|
474
|
+
this.delay = delay;
|
|
475
|
+
this.writeHistory = writeHistory;
|
|
476
|
+
this.paginationOffset = paginationOffset;
|
|
477
|
+
this.paginationLast = paginationLast;
|
|
478
|
+
this.handleHtmlCallback = handleHtmlCallback;
|
|
479
|
+
this.paginationGenerator = alternativeGenerator?.() ?? InfiniteScroller.createPaginationGenerator(
|
|
480
|
+
paginationOffset,
|
|
481
|
+
paginationLast,
|
|
482
|
+
paginationUrlGenerator
|
|
483
|
+
);
|
|
484
|
+
const observable = intersectionObservable || paginationElement;
|
|
485
|
+
Observer.observeWhile(observable, this.generatorConsumer, this.delay);
|
|
486
|
+
}
|
|
487
|
+
onScroll(callback, initCall) {
|
|
488
|
+
if (initCall) callback(this);
|
|
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
|
+
}
|
|
299
502
|
export {
|
|
300
503
|
AsyncPool,
|
|
504
|
+
DataManager,
|
|
505
|
+
InfiniteScroller,
|
|
301
506
|
LazyImgLoader,
|
|
302
507
|
MOBILE_UA,
|
|
303
508
|
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(\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'].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 writeHistory: 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 public writeHistory: boolean;\n private handleHtmlCallback: (document: HTMLElement) => void;\n\n constructor({\n enabled = true,\n delay = 350,\n writeHistory = false,\n paginationOffset,\n paginationLast,\n paginationElement,\n paginationUrlGenerator,\n handleHtmlCallback,\n alternativeGenerator,\n intersectionObservable,\n }: IInfiniteScroller) {\n this.enabled = enabled;\n this.delay = delay;\n this.writeHistory = writeHistory;\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 private onScrollCBs: Array<(scroller: InfiniteScroller) => void> = [];\n\n public onScroll(callback: (scroller: InfiniteScroller) => void, initCall: false) {\n if (initCall) callback(this);\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 if (this.writeHistory) {\n history.replaceState({}, '', url);\n }\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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"}
|
|
@@ -300,7 +300,212 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
300
300
|
function range(size, startAt = 1, step = 1) {
|
|
301
301
|
return Array.from({ length: size }, (_, index) => startAt + index * step);
|
|
302
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 = true,
|
|
440
|
+
delay = 350,
|
|
441
|
+
writeHistory = false,
|
|
442
|
+
paginationOffset,
|
|
443
|
+
paginationLast,
|
|
444
|
+
paginationElement,
|
|
445
|
+
paginationUrlGenerator,
|
|
446
|
+
handleHtmlCallback,
|
|
447
|
+
alternativeGenerator,
|
|
448
|
+
intersectionObservable
|
|
449
|
+
}) {
|
|
450
|
+
__publicField(this, "paginationGenerator");
|
|
451
|
+
__publicField(this, "enabled");
|
|
452
|
+
__publicField(this, "delay");
|
|
453
|
+
__publicField(this, "paginationOffset");
|
|
454
|
+
__publicField(this, "paginationLast");
|
|
455
|
+
__publicField(this, "writeHistory");
|
|
456
|
+
__publicField(this, "handleHtmlCallback");
|
|
457
|
+
__publicField(this, "onScrollCBs", []);
|
|
458
|
+
__publicField(this, "generatorConsumer", async () => {
|
|
459
|
+
if (!this.enabled) return false;
|
|
460
|
+
const {
|
|
461
|
+
value: { url, offset } = {},
|
|
462
|
+
done
|
|
463
|
+
} = await this.paginationGenerator.next();
|
|
464
|
+
if (!done) {
|
|
465
|
+
const nextPageHTML = await fetchHtml(url);
|
|
466
|
+
const prevScrollPos = document.documentElement.scrollTop;
|
|
467
|
+
this.paginationOffset = offset;
|
|
468
|
+
this.handleHtmlCallback(nextPageHTML);
|
|
469
|
+
this._onScroll();
|
|
470
|
+
window.scrollTo(0, prevScrollPos);
|
|
471
|
+
if (this.writeHistory) {
|
|
472
|
+
history.replaceState({}, "", url);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
return !done;
|
|
476
|
+
});
|
|
477
|
+
this.enabled = enabled;
|
|
478
|
+
this.delay = delay;
|
|
479
|
+
this.writeHistory = writeHistory;
|
|
480
|
+
this.paginationOffset = paginationOffset;
|
|
481
|
+
this.paginationLast = paginationLast;
|
|
482
|
+
this.handleHtmlCallback = handleHtmlCallback;
|
|
483
|
+
this.paginationGenerator = alternativeGenerator?.() ?? InfiniteScroller.createPaginationGenerator(
|
|
484
|
+
paginationOffset,
|
|
485
|
+
paginationLast,
|
|
486
|
+
paginationUrlGenerator
|
|
487
|
+
);
|
|
488
|
+
const observable = intersectionObservable || paginationElement;
|
|
489
|
+
Observer.observeWhile(observable, this.generatorConsumer, this.delay);
|
|
490
|
+
}
|
|
491
|
+
onScroll(callback, initCall) {
|
|
492
|
+
if (initCall) callback(this);
|
|
493
|
+
this.onScrollCBs.push(callback);
|
|
494
|
+
return this;
|
|
495
|
+
}
|
|
496
|
+
_onScroll() {
|
|
497
|
+
this.onScrollCBs.forEach((cb) => cb(this));
|
|
498
|
+
}
|
|
499
|
+
static *createPaginationGenerator(currentPage, totalPages, generateURL) {
|
|
500
|
+
for (let offset = currentPage + 1; offset <= totalPages; offset++) {
|
|
501
|
+
const url = generateURL(offset);
|
|
502
|
+
yield { url, offset };
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
}
|
|
303
506
|
exports2.AsyncPool = AsyncPool;
|
|
507
|
+
exports2.DataManager = DataManager;
|
|
508
|
+
exports2.InfiniteScroller = InfiniteScroller;
|
|
304
509
|
exports2.LazyImgLoader = LazyImgLoader;
|
|
305
510
|
exports2.MOBILE_UA = MOBILE_UA;
|
|
306
511
|
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(\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'].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 writeHistory: 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 public writeHistory: boolean;\n private handleHtmlCallback: (document: HTMLElement) => void;\n\n constructor({\n enabled = true,\n delay = 350,\n writeHistory = false,\n paginationOffset,\n paginationLast,\n paginationElement,\n paginationUrlGenerator,\n handleHtmlCallback,\n alternativeGenerator,\n intersectionObservable,\n }: IInfiniteScroller) {\n this.enabled = enabled;\n this.delay = delay;\n this.writeHistory = writeHistory;\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 private onScrollCBs: Array<(scroller: InfiniteScroller) => void> = [];\n\n public onScroll(callback: (scroller: InfiniteScroller) => void, initCall: false) {\n if (initCall) callback(this);\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 if (this.writeHistory) {\n history.replaceState({}, '', url);\n }\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,74 @@ 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
|
+
writeHistory: boolean;
|
|
94
|
+
paginationOffset: number;
|
|
95
|
+
paginationLast: number;
|
|
96
|
+
paginationElement: HTMLElement;
|
|
97
|
+
paginationUrlGenerator: (offset: number) => string;
|
|
98
|
+
handleHtmlCallback: (document: HTMLElement) => void;
|
|
99
|
+
intersectionObservable?: HTMLElement;
|
|
100
|
+
alternativeGenerator?: () => OffsetGenerator;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export declare class InfiniteScroller {
|
|
104
|
+
paginationGenerator: OffsetGenerator;
|
|
105
|
+
enabled: boolean;
|
|
106
|
+
delay: number;
|
|
107
|
+
paginationOffset: number;
|
|
108
|
+
paginationLast: number;
|
|
109
|
+
writeHistory: boolean;
|
|
110
|
+
private handleHtmlCallback;
|
|
111
|
+
constructor({ enabled, delay, writeHistory, paginationOffset, paginationLast, paginationElement, paginationUrlGenerator, handleHtmlCallback, alternativeGenerator, intersectionObservable, }: IInfiniteScroller);
|
|
112
|
+
private onScrollCBs;
|
|
113
|
+
onScroll(callback: (scroller: InfiniteScroller) => void, initCall: false): this;
|
|
114
|
+
private _onScroll;
|
|
115
|
+
generatorConsumer: () => Promise<boolean>;
|
|
116
|
+
static createPaginationGenerator(currentPage: number, totalPages: number, generateURL: (offset: number) => string): OffsetGenerator;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
declare interface IRules {
|
|
120
|
+
GET_THUMBS: (html: HTMLElement) => HTMLElement[];
|
|
121
|
+
THUMB_URL: (thumbElement: HTMLElement) => string;
|
|
122
|
+
THUMB_DATA: (thumbElement: HTMLElement) => {
|
|
123
|
+
title: string;
|
|
124
|
+
duration: number;
|
|
125
|
+
};
|
|
126
|
+
THUMB_IMG_DATA: (thumbElement: HTMLElement) => {
|
|
127
|
+
img: HTMLElement;
|
|
128
|
+
imgSrc: string;
|
|
129
|
+
};
|
|
130
|
+
CONTAINER: HTMLElement;
|
|
131
|
+
IS_PRIVATE: (element: HTMLElement) => boolean;
|
|
132
|
+
}
|
|
133
|
+
|
|
46
134
|
export declare function isMob(): boolean;
|
|
47
135
|
|
|
48
136
|
export declare class LazyImgLoader {
|
|
@@ -69,6 +157,8 @@ export declare class Observer {
|
|
|
69
157
|
static observeWhile(target: Element, callback: () => Promise<boolean> | boolean, throttleTime: number): Observer;
|
|
70
158
|
}
|
|
71
159
|
|
|
160
|
+
declare type OffsetGenerator = Generator<GeneratorResult> | AsyncGenerator<GeneratorResult>;
|
|
161
|
+
|
|
72
162
|
export declare function parseCSSUrl(s: string): string;
|
|
73
163
|
|
|
74
164
|
export declare function parseDataParams(str: string): Record<string, string>;
|
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.1",
|
|
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,106 @@
|
|
|
1
|
+
import { fetchHtml } from '../fetch';
|
|
2
|
+
import { Observer } from '../observers';
|
|
3
|
+
|
|
4
|
+
interface IInfiniteScroller {
|
|
5
|
+
delay: number;
|
|
6
|
+
enabled: boolean;
|
|
7
|
+
writeHistory: boolean;
|
|
8
|
+
paginationOffset: number;
|
|
9
|
+
paginationLast: number;
|
|
10
|
+
paginationElement: HTMLElement;
|
|
11
|
+
paginationUrlGenerator: (offset: number) => string;
|
|
12
|
+
handleHtmlCallback: (document: HTMLElement) => void;
|
|
13
|
+
intersectionObservable?: HTMLElement;
|
|
14
|
+
alternativeGenerator?: () => OffsetGenerator;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface GeneratorResult {
|
|
18
|
+
url: string;
|
|
19
|
+
offset: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
type OffsetGenerator = Generator<GeneratorResult> | AsyncGenerator<GeneratorResult>;
|
|
23
|
+
|
|
24
|
+
export class InfiniteScroller {
|
|
25
|
+
public paginationGenerator: OffsetGenerator;
|
|
26
|
+
public enabled: boolean;
|
|
27
|
+
public delay: number;
|
|
28
|
+
public paginationOffset: number;
|
|
29
|
+
public paginationLast: number;
|
|
30
|
+
public writeHistory: boolean;
|
|
31
|
+
private handleHtmlCallback: (document: HTMLElement) => void;
|
|
32
|
+
|
|
33
|
+
constructor({
|
|
34
|
+
enabled = true,
|
|
35
|
+
delay = 350,
|
|
36
|
+
writeHistory = false,
|
|
37
|
+
paginationOffset,
|
|
38
|
+
paginationLast,
|
|
39
|
+
paginationElement,
|
|
40
|
+
paginationUrlGenerator,
|
|
41
|
+
handleHtmlCallback,
|
|
42
|
+
alternativeGenerator,
|
|
43
|
+
intersectionObservable,
|
|
44
|
+
}: IInfiniteScroller) {
|
|
45
|
+
this.enabled = enabled;
|
|
46
|
+
this.delay = delay;
|
|
47
|
+
this.writeHistory = writeHistory;
|
|
48
|
+
this.paginationOffset = paginationOffset;
|
|
49
|
+
this.paginationLast = paginationLast;
|
|
50
|
+
this.handleHtmlCallback = handleHtmlCallback;
|
|
51
|
+
|
|
52
|
+
this.paginationGenerator =
|
|
53
|
+
alternativeGenerator?.() ??
|
|
54
|
+
InfiniteScroller.createPaginationGenerator(
|
|
55
|
+
paginationOffset,
|
|
56
|
+
paginationLast,
|
|
57
|
+
paginationUrlGenerator,
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const observable = intersectionObservable || paginationElement;
|
|
61
|
+
Observer.observeWhile(observable, this.generatorConsumer, this.delay);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private onScrollCBs: Array<(scroller: InfiniteScroller) => void> = [];
|
|
65
|
+
|
|
66
|
+
public onScroll(callback: (scroller: InfiniteScroller) => void, initCall: false) {
|
|
67
|
+
if (initCall) callback(this);
|
|
68
|
+
this.onScrollCBs.push(callback);
|
|
69
|
+
return this;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private _onScroll() {
|
|
73
|
+
this.onScrollCBs.forEach((cb) => cb(this));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
generatorConsumer = async () => {
|
|
77
|
+
if (!this.enabled) return false;
|
|
78
|
+
const {
|
|
79
|
+
value: { url, offset } = {},
|
|
80
|
+
done,
|
|
81
|
+
} = await this.paginationGenerator.next();
|
|
82
|
+
if (!done) {
|
|
83
|
+
const nextPageHTML = await fetchHtml(url);
|
|
84
|
+
const prevScrollPos = document.documentElement.scrollTop;
|
|
85
|
+
this.paginationOffset = offset;
|
|
86
|
+
this.handleHtmlCallback(nextPageHTML);
|
|
87
|
+
this._onScroll();
|
|
88
|
+
window.scrollTo(0, prevScrollPos);
|
|
89
|
+
if (this.writeHistory) {
|
|
90
|
+
history.replaceState({}, '', url);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return !done;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
static *createPaginationGenerator(
|
|
97
|
+
currentPage: number,
|
|
98
|
+
totalPages: number,
|
|
99
|
+
generateURL: (offset: number) => string,
|
|
100
|
+
): OffsetGenerator {
|
|
101
|
+
for (let offset = currentPage + 1; offset <= totalPages; offset++) {
|
|
102
|
+
const url = generateURL(offset);
|
|
103
|
+
yield { url, offset };
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -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
|
}
|