pervert-monkey 1.0.17 → 1.0.18

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.
Files changed (50) hide show
  1. package/dist/core/pervertmonkey.core.es.d.ts +16 -10
  2. package/dist/core/pervertmonkey.core.es.js +120 -127
  3. package/dist/core/pervertmonkey.core.es.js.map +1 -1
  4. package/dist/core/pervertmonkey.core.umd.js +120 -127
  5. package/dist/core/pervertmonkey.core.umd.js.map +1 -1
  6. package/dist/userscripts/3hentai.user.js +2 -2
  7. package/dist/userscripts/camgirlfinder.user.js +2 -2
  8. package/dist/userscripts/camwhores.user.js +4 -5
  9. package/dist/userscripts/e-hentai.user.js +2 -2
  10. package/dist/userscripts/ebalka.user.js +7 -3
  11. package/dist/userscripts/eporner.user.js +2 -2
  12. package/dist/userscripts/erome.user.js +2 -2
  13. package/dist/userscripts/eroprofile.user.js +2 -2
  14. package/dist/userscripts/javhdporn.user.js +2 -2
  15. package/dist/userscripts/missav.user.js +2 -7
  16. package/dist/userscripts/motherless.user.js +2 -2
  17. package/dist/userscripts/namethatporn.user.js +2 -2
  18. package/dist/userscripts/nhentai.user.js +2 -2
  19. package/dist/userscripts/obmenvsem.user.js +2 -2
  20. package/dist/userscripts/pornhub.user.js +2 -2
  21. package/dist/userscripts/spankbang.user.js +3 -4
  22. package/dist/userscripts/thisvid.user.js +4 -5
  23. package/dist/userscripts/xhamster.user.js +2 -2
  24. package/dist/userscripts/xvideos.user.js +2 -2
  25. package/package.json +1 -1
  26. package/src/core/data-handler/data-manager.ts +47 -115
  27. package/src/core/infinite-scroll/index.ts +6 -4
  28. package/src/userscripts/index.ts +1 -1
  29. package/src/userscripts/scripts/3hentai.ts +1 -1
  30. package/src/userscripts/scripts/camgirlfinder.ts +1 -1
  31. package/src/userscripts/scripts/camwhores.ts +3 -4
  32. package/src/userscripts/scripts/e-hentai.ts +1 -1
  33. package/src/userscripts/scripts/ebalka.ts +10 -3
  34. package/src/userscripts/scripts/eporner.ts +1 -1
  35. package/src/userscripts/scripts/erome.ts +1 -1
  36. package/src/userscripts/scripts/eroprofile.ts +1 -1
  37. package/src/userscripts/scripts/javhdporn.ts +1 -1
  38. package/src/userscripts/scripts/missav.ts +1 -6
  39. package/src/userscripts/scripts/motherless.ts +1 -1
  40. package/src/userscripts/scripts/namethatporn.ts +1 -1
  41. package/src/userscripts/scripts/nhentai.ts +1 -1
  42. package/src/userscripts/scripts/obmenvsem.ts +1 -1
  43. package/src/userscripts/scripts/pornhub.ts +1 -1
  44. package/src/userscripts/scripts/spankbang.ts +1 -3
  45. package/src/userscripts/scripts/thisvid.ts +4 -4
  46. package/src/userscripts/scripts/xhamster.ts +1 -1
  47. package/src/userscripts/scripts/xvideos.ts +1 -1
  48. package/src/utils/dom/index.ts +9 -6
  49. package/src/utils/index.ts +4 -22
  50. package/src/utils/performance/index.ts +44 -0
@@ -16,6 +16,8 @@ export declare function chunks<T>(arr: T[], size: number): T[][];
16
16
 
17
17
  export declare function circularShift(n: number, c?: number, s?: number): number;
18
18
 
19
+ export declare function containMutation(container: HTMLElement, callback: () => void): void;
20
+
19
21
  export declare function copyAttributes<T extends Element = HTMLElement>(target: T, source: T): void;
20
22
 
21
23
  export declare type DataElement = {
@@ -68,11 +70,9 @@ export declare class DataManager {
68
70
  private lazyImgLoader;
69
71
  dataFilter: DataFilter;
70
72
  constructor(rules: Rules, containerHomogenity?: Parameters<typeof checkHomogenity>[2] | undefined);
71
- applyFilters: (filters?: Record<string, boolean>, offset?: number) => Promise<void>;
72
- layoutStylePaintEnabled: boolean;
73
- private layoutStylePaint;
74
- filterAll: (offset?: number) => Promise<void>;
75
- parseData: (html: HTMLElement, container?: HTMLElement, removeDuplicates?: boolean, shouldLazify?: boolean) => void;
73
+ applyFilters(filters?: Record<string, boolean>, offset?: number): Promise<void>;
74
+ filterAll(offset?: number): Promise<void>;
75
+ parseData(html: HTMLElement, container?: HTMLElement, removeDuplicates?: boolean, shouldLazify?: boolean): Promise<void>;
76
76
  sortBy<K extends keyof DataElement>(key: K, direction?: boolean): void;
77
77
  }
78
78
 
@@ -200,11 +200,11 @@ declare const DefaultScheme: [{
200
200
  }];
201
201
  }];
202
202
 
203
- export declare function downloader(options?: {
204
- append: string;
205
- after: string;
206
- button: string;
207
- cbBefore: () => void;
203
+ export declare function downloader(options: {
204
+ append?: string;
205
+ after?: string;
206
+ buttonHtml: string;
207
+ doBefore?: () => void;
208
208
  }): void;
209
209
 
210
210
  export declare function exterminateVideo(video: HTMLVideoElement): void;
@@ -223,6 +223,8 @@ export declare function fetchWith<T extends JSON | string | HTMLElement>(input:
223
223
 
224
224
  export declare function findNextSibling<T extends Element = HTMLElement>(e: T): Element | null;
225
225
 
226
+ export declare function findSelfOrChild<T extends HTMLElement>(element: T, selector: string): T | null;
227
+
226
228
  /**
227
229
  * Converts a duration string (e.g., "1h 22min 3sec") to HH:MM:SS format.
228
230
  * @param timeStr - The duration string to format.
@@ -261,6 +263,8 @@ declare type InfiniteScrollerOptions = Pick<InfiniteScroller, 'rules'> & Partial
261
263
 
262
264
  export declare function instantiateTemplate(sourceSelector: string, attributeUpdates: Record<string, string>, contentUpdates: Record<string, string>): string;
263
265
 
266
+ export declare function irange(start?: number, step?: number): Generator<number, void, unknown>;
267
+
264
268
  declare type IScrollerSubject = {
265
269
  type: 'scroll';
266
270
  scroller: InfiniteScroller;
@@ -445,6 +449,8 @@ export declare class Rules {
445
449
  constructor(options: Partial<Rules>);
446
450
  }
447
451
 
452
+ export declare function runIdleJob<T>(iterator: Iterator<T>, job: (v: T) => void): Promise<unknown>;
453
+
448
454
  export declare function sanitizeStr(s: string): string;
449
455
 
450
456
  declare type SchemeKeys = JabroniTypes.ExtractValuesByKey<typeof DefaultScheme, 'title'>;
@@ -172,6 +172,12 @@ function watchDomChangesWithThrottle(element, callback, throttle = 1e3, times =
172
172
  observer.observe(element, options);
173
173
  return observer;
174
174
  }
175
+ function findSelfOrChild(element, selector) {
176
+ if (element.matches(selector)) {
177
+ return element;
178
+ }
179
+ return element.querySelector(selector);
180
+ }
175
181
  function querySelectorLast(root = document, selector) {
176
182
  const nodes = root.querySelectorAll(selector);
177
183
  return nodes.length > 0 ? nodes[nodes.length - 1] : void 0;
@@ -264,15 +270,15 @@ function exterminateVideo(video) {
264
270
  video.load();
265
271
  video.remove();
266
272
  }
267
- function downloader(options = { append: "", after: "", button: "", cbBefore: () => {
268
- } }) {
273
+ function downloader(options) {
269
274
  var _a3, _b2;
270
- const btn = parseHtml(options.button);
275
+ const btn = parseHtml(options.buttonHtml);
271
276
  if (options.append) (_a3 = document.querySelector(options.append)) == null ? void 0 : _a3.append(btn);
272
277
  if (options.after) (_b2 = document.querySelector(options.after)) == null ? void 0 : _b2.after(btn);
273
- btn.addEventListener("click", (e) => {
278
+ btn == null ? void 0 : btn.addEventListener("click", (e) => {
279
+ var _a4;
274
280
  e.preventDefault();
275
- if (options.cbBefore) options.cbBefore();
281
+ (_a4 = options.doBefore) == null ? void 0 : _a4.call(options);
276
282
  waitForElementToAppear(document.body, "video", (video) => {
277
283
  window.location.href = video.getAttribute("src");
278
284
  });
@@ -466,6 +472,42 @@ function parseDataParams(str) {
466
472
  function parseCssUrl(s) {
467
473
  return s.replace(/url\("|"\).*/g, "");
468
474
  }
475
+ function runIdleJob(iterator2, job) {
476
+ return new Promise((resolve) => {
477
+ const scheduler = window.requestIdleCallback || ((cb) => {
478
+ return setTimeout(() => {
479
+ cb({
480
+ didTimeout: true,
481
+ timeRemaining: () => 50
482
+ });
483
+ }, 1);
484
+ });
485
+ function runBatch(deadline) {
486
+ while (deadline.timeRemaining() > 0) {
487
+ const { value, done } = iterator2.next();
488
+ if (done) {
489
+ resolve(true);
490
+ return;
491
+ }
492
+ job(value);
493
+ }
494
+ scheduler(runBatch);
495
+ }
496
+ scheduler(runBatch);
497
+ });
498
+ }
499
+ function containMutation(container, callback) {
500
+ container.style.contain = "content";
501
+ try {
502
+ callback();
503
+ } finally {
504
+ requestAnimationFrame(() => {
505
+ requestAnimationFrame(() => {
506
+ container.style.contain = "none";
507
+ });
508
+ });
509
+ }
510
+ }
469
511
  function createTextFilter(filterName, dataPropName, positive) {
470
512
  const filterNameValue = `${filterName}Words`;
471
513
  return {
@@ -557,136 +599,82 @@ class DataManager {
557
599
  (target) => !DataFilter.isFiltered(target)
558
600
  ));
559
601
  __publicField(this, "dataFilter");
560
- __publicField(this, "applyFilters", async (filters = {}, offset = 0) => {
561
- const filtersToApply = this.dataFilter.selectFilters(filters);
562
- if (filtersToApply.length === 0) return;
563
- const iterator2 = this.data.values().drop(offset);
564
- let finished = false;
565
- const updates = [];
566
- await new Promise((resolve) => {
567
- function runBatch(deadline) {
568
- while (deadline.timeRemaining() > 0) {
569
- const { value, done } = iterator2.next();
570
- finished = !!done;
571
- if (done) break;
572
- for (const f of filtersToApply) {
573
- const { name, condition } = f()(value);
574
- updates.push({ e: value.element, name, condition });
575
- }
576
- }
577
- if (!finished) {
578
- requestIdleCallback(runBatch);
579
- } else {
580
- resolve(true);
581
- }
582
- }
583
- requestIdleCallback(runBatch);
584
- });
585
- const parents = [...new Set(updates.map((u) => u.e.parentElement))].filter(
586
- (_2) => _2 !== null
587
- );
588
- requestAnimationFrame(() => {
589
- const revertDisplayStyle = parents.map((p) => {
590
- const display = p.style.display;
591
- p.style.display = "none";
592
- this.layoutStylePaint(p);
593
- p.style.willChange = "contents";
594
- return () => {
595
- p.style.display = display;
596
- requestAnimationFrame(() => {
597
- p.style.willChange = "auto";
598
- });
599
- };
600
- });
601
- updates.forEach((u) => {
602
+ this.rules = rules;
603
+ this.containerHomogenity = containerHomogenity;
604
+ this.dataFilter = new DataFilter(this.rules);
605
+ }
606
+ async applyFilters(filters = {}, offset = 0) {
607
+ const filtersToApply = this.dataFilter.selectFilters(filters);
608
+ if (filtersToApply.length === 0) return;
609
+ const iterator2 = this.data.values().drop(offset);
610
+ const updates = [];
611
+ await runIdleJob(iterator2, (v2) => {
612
+ for (const f of filtersToApply) {
613
+ const { name, condition } = f()(v2);
614
+ updates.push({ e: v2.element, name, condition });
615
+ }
616
+ });
617
+ const parents = Map.groupBy(updates, (u) => u.e.parentElement);
618
+ parents.forEach((v2, parent) => {
619
+ const f = () => {
620
+ v2.forEach((u) => {
602
621
  u.e.classList.toggle(u.name, u.condition);
603
622
  });
604
- revertDisplayStyle.forEach((f) => {
605
- f == null ? void 0 : f();
606
- });
607
- });
608
- });
609
- __publicField(this, "layoutStylePaintEnabled", false);
610
- __publicField(this, "filterAll", async (offset) => {
611
- const keys = Array.from(this.dataFilter.filters.keys());
612
- const filters = Object.fromEntries(
613
- keys.map((k2) => [k2, this.rules.store.state[k2]])
614
- );
615
- await this.applyFilters(filters, offset);
616
- });
617
- __publicField(this, "parseData", (html, container, removeDuplicates = false, shouldLazify = true) => {
618
- const thumbs = this.rules.thumbsParser.getThumbs(html);
619
- const dataOffset = this.data.size;
620
- const fragment = document.createDocumentFragment();
621
- const parent = container || this.rules.container;
622
- const homogenity = !!this.containerHomogenity;
623
- for (const thumbElement of thumbs) {
624
- const url = this.rules.thumbDataParser.getUrl(thumbElement);
625
- if (!url || this.data.has(url) || parent !== container && (parent == null ? void 0 : parent.contains(thumbElement)) || homogenity && !checkHomogenity(
626
- parent,
627
- thumbElement.parentElement,
628
- this.containerHomogenity
629
- )) {
630
- if (removeDuplicates) thumbElement.remove();
631
- continue;
632
- }
633
- const data = this.rules.thumbDataParser.getThumbData(thumbElement);
634
- this.data.set(url, { element: thumbElement, ...data });
635
- if (shouldLazify) {
636
- const { img, imgSrc } = this.rules.thumbImgParser.getImgData(thumbElement);
637
- this.lazyImgLoader.lazify(thumbElement, img, imgSrc);
638
- }
639
- fragment.append(thumbElement);
640
- }
641
- this.filterAll(dataOffset).then(() => {
642
- if (!parent) return;
643
- parent.style.willChange = "contents";
623
+ };
624
+ if (!parent) {
625
+ f();
626
+ } else {
644
627
  requestAnimationFrame(() => {
645
- parent == null ? void 0 : parent.appendChild(fragment);
646
- requestAnimationFrame(() => {
647
- parent.style.willChange = "auto";
648
- });
628
+ containMutation(parent, f);
649
629
  });
650
- });
630
+ }
651
631
  });
652
- this.rules = rules;
653
- this.containerHomogenity = containerHomogenity;
654
- this.dataFilter = new DataFilter(this.rules);
655
632
  }
656
- layoutStylePaint(e) {
657
- if (!this.layoutStylePaintEnabled) return;
658
- e.style.contain = "layout style paint";
633
+ async filterAll(offset) {
634
+ const keys = Array.from(this.dataFilter.filters.keys());
635
+ const filters = Object.fromEntries(
636
+ keys.map((k2) => [k2, this.rules.store.state[k2]])
637
+ );
638
+ await this.applyFilters(filters, offset);
639
+ }
640
+ async parseData(html, container, removeDuplicates = false, shouldLazify = true) {
641
+ const thumbs = this.rules.thumbsParser.getThumbs(html);
642
+ const dataOffset = this.data.size;
643
+ const fragment = document.createDocumentFragment();
644
+ const parent = container || this.rules.container;
645
+ const homogenity = !!this.containerHomogenity;
646
+ for (const thumbElement of thumbs) {
647
+ const url = this.rules.thumbDataParser.getUrl(thumbElement);
648
+ const isHomogenic = homogenity && !checkHomogenity(
649
+ parent,
650
+ thumbElement.parentElement,
651
+ this.containerHomogenity
652
+ );
653
+ if (!url || this.data.has(url) || parent !== container && (parent == null ? void 0 : parent.contains(thumbElement)) || isHomogenic) {
654
+ if (removeDuplicates) thumbElement.remove();
655
+ continue;
656
+ }
657
+ const data = this.rules.thumbDataParser.getThumbData(thumbElement);
658
+ this.data.set(url, { element: thumbElement, ...data });
659
+ if (shouldLazify) {
660
+ const { img, imgSrc } = this.rules.thumbImgParser.getImgData(thumbElement);
661
+ this.lazyImgLoader.lazify(thumbElement, img, imgSrc);
662
+ }
663
+ fragment.append(thumbElement);
664
+ }
665
+ await this.filterAll(dataOffset);
666
+ if (!parent) return;
667
+ containMutation(parent, () => parent == null ? void 0 : parent.appendChild(fragment));
659
668
  }
660
669
  sortBy(key, direction = true) {
661
670
  if (this.data.size < 2) return;
662
- const elements = this.data.values().toArray().filter((e) => e.element.parentElement !== null).map((e) => e);
663
- const containers = new Set(elements.map((e) => e.element.parentElement));
664
- containers.forEach((c) => {
665
- this.layoutStylePaint(c);
666
- c.style.willChange = "contents";
667
- });
668
- const elementsByContainers = /* @__PURE__ */ new Map();
669
- containers.forEach((c) => {
670
- elementsByContainers.set(c, []);
671
- });
672
- elements.forEach((e) => {
673
- const parent = e.element.parentElement;
674
- const container = elementsByContainers.get(parent);
675
- container == null ? void 0 : container.push(e);
676
- });
671
+ const ds2 = this.data.values().toArray().filter((e) => e.element.parentElement !== null);
672
+ const byContainers = Map.groupBy(ds2, (e) => e.element.parentElement);
677
673
  const dir = direction ? -1 : 1;
678
- for (const [container, items] of elementsByContainers) {
674
+ for (const [container, items] of byContainers) {
679
675
  items.sort((a2, b2) => (a2[key] - b2[key]) * dir);
680
- const domNodes = items.map((e) => e.element);
681
- const display = container.style.display;
682
- container.style.display = "none";
683
- container.replaceChildren(...domNodes);
684
- requestAnimationFrame(() => {
685
- container.style.display = display;
686
- requestAnimationFrame(() => {
687
- container.style.willChange = "auto";
688
- });
689
- });
676
+ const children = items.map((e) => e.element);
677
+ containMutation(container, () => container.replaceChildren(...children));
690
678
  }
691
679
  }
692
680
  }
@@ -2023,10 +2011,8 @@ class InfiniteScroller {
2023
2011
  }
2024
2012
  async doScroll(url, offset) {
2025
2013
  const page = await this.getPaginationData(url);
2026
- const prevScrollPos = document.documentElement.scrollTop;
2027
2014
  this.paginationOffset = Math.max(this.paginationOffset, offset);
2028
2015
  this.subject.next({ type: "scroll", scroller: this, page });
2029
- window.scrollTo(0, prevScrollPos);
2030
2016
  if (this.rules.store.state.writeHistory) {
2031
2017
  history.replaceState({}, "", url);
2032
2018
  }
@@ -2048,7 +2034,10 @@ class InfiniteScroller {
2048
2034
  infiniteScroller.subject.subscribe((x2) => {
2049
2035
  if (x2.type === "scroll") {
2050
2036
  rules.store.state.$paginationOffset = x2.scroller.paginationOffset;
2051
- rules.dataManager.parseData(x2.page);
2037
+ const prevScrollPos = document.documentElement.scrollTop;
2038
+ rules.dataManager.parseData(x2.page).then(() => {
2039
+ window.scrollTo(0, prevScrollPos);
2040
+ });
2052
2041
  }
2053
2042
  });
2054
2043
  rules.store.stateSubject.subscribe(() => {
@@ -10024,6 +10013,7 @@ export {
10024
10013
  checkHomogenity,
10025
10014
  chunks,
10026
10015
  circularShift,
10016
+ containMutation,
10027
10017
  copyAttributes,
10028
10018
  downloader,
10029
10019
  exterminateVideo,
@@ -10032,10 +10022,12 @@ export {
10032
10022
  fetchText,
10033
10023
  fetchWith,
10034
10024
  findNextSibling,
10025
+ findSelfOrChild,
10035
10026
  formatTimeToHHMMSS,
10036
10027
  getCommonParents,
10037
10028
  getPaginationStrategy,
10038
10029
  instantiateTemplate,
10030
+ irange,
10039
10031
  memoize,
10040
10032
  objectToFormData,
10041
10033
  parseCssUrl,
@@ -10050,6 +10042,7 @@ export {
10050
10042
  range,
10051
10043
  removeClassesAndDataAttributes,
10052
10044
  replaceElementTag,
10045
+ runIdleJob,
10053
10046
  sanitizeStr,
10054
10047
  splitWith,
10055
10048
  timeToSeconds,