pervert-monkey 1.0.11 → 1.0.13

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 (55) hide show
  1. package/README.md +22 -11
  2. package/dist/core/pervertmonkey.core.es.d.ts +25 -16
  3. package/dist/core/pervertmonkey.core.es.js +712 -61
  4. package/dist/core/pervertmonkey.core.es.js.map +1 -1
  5. package/dist/core/pervertmonkey.core.umd.js +712 -61
  6. package/dist/core/pervertmonkey.core.umd.js.map +1 -1
  7. package/dist/userscripts/3hentai.user.js +19 -26
  8. package/dist/userscripts/camgirlfinder.user.js +2 -2
  9. package/dist/userscripts/camwhores.user.js +12 -16
  10. package/dist/userscripts/e-hentai.user.js +3 -4
  11. package/dist/userscripts/ebalka.user.js +6 -11
  12. package/dist/userscripts/eporner.user.js +11 -16
  13. package/dist/userscripts/erome.user.js +2 -2
  14. package/dist/userscripts/eroprofile.user.js +2 -2
  15. package/dist/userscripts/javhdporn.user.js +2 -2
  16. package/dist/userscripts/missav.user.js +2 -2
  17. package/dist/userscripts/motherless.user.js +22 -42
  18. package/dist/userscripts/namethatporn.user.js +5 -4
  19. package/dist/userscripts/nhentai.user.js +3 -3
  20. package/dist/userscripts/obmenvsem.user.js +18 -4
  21. package/dist/userscripts/pornhub.user.js +9 -12
  22. package/dist/userscripts/spankbang.user.js +6 -38
  23. package/dist/userscripts/thisvid.user.js +20 -22
  24. package/dist/userscripts/xhamster.user.js +13 -16
  25. package/dist/userscripts/xvideos.user.js +7 -12
  26. package/package.json +1 -1
  27. package/src/core/data-handler/data-manager.ts +4 -4
  28. package/src/core/jabroni-config/index.ts +3 -2
  29. package/src/core/jabroni-config/jabroni-gui-controller.ts +61 -0
  30. package/src/core/parsers/thumb-data-parser.ts +10 -1
  31. package/src/core/rules/index.ts +12 -39
  32. package/src/userscripts/index.ts +1 -1
  33. package/src/userscripts/scripts/3hentai.ts +20 -24
  34. package/src/userscripts/scripts/camgirlfinder.ts +1 -1
  35. package/src/userscripts/scripts/camwhores.ts +10 -17
  36. package/src/userscripts/scripts/e-hentai.ts +1 -1
  37. package/src/userscripts/scripts/ebalka.ts +7 -12
  38. package/src/userscripts/scripts/eporner.ts +8 -14
  39. package/src/userscripts/scripts/erome.ts +1 -1
  40. package/src/userscripts/scripts/eroprofile.ts +3 -3
  41. package/src/userscripts/scripts/javhdporn.ts +1 -1
  42. package/src/userscripts/scripts/missav.ts +1 -1
  43. package/src/userscripts/scripts/motherless.ts +19 -48
  44. package/src/userscripts/scripts/namethatporn.ts +1 -1
  45. package/src/userscripts/scripts/nhentai.ts +1 -1
  46. package/src/userscripts/scripts/obmenvsem.ts +1 -1
  47. package/src/userscripts/scripts/pornhub.ts +1 -1
  48. package/src/userscripts/scripts/spankbang.ts +1 -1
  49. package/src/userscripts/scripts/thisvid.ts +18 -19
  50. package/src/userscripts/scripts/xhamster.ts +10 -11
  51. package/src/userscripts/scripts/xvideos.ts +6 -11
  52. package/src/utils/dom/index.ts +10 -0
  53. package/src/utils/events/on-hover.ts +17 -25
  54. package/src/utils/events/tick.ts +1 -3
  55. package/src/utils/parsers/index.ts +16 -0
@@ -1,7 +1,7 @@
1
1
  // ==UserScript==
2
2
  // @name SpankBang.com PervertMonkey
3
3
  // @namespace pervertmonkey
4
- // @version 4.0.1
4
+ // @version 4.0.3
5
5
  // @author violent-orangutan
6
6
  // @description Infinite scroll [optional]. Filter by Title and Duration
7
7
  // @license MIT
@@ -12,14 +12,14 @@
12
12
  // @supportURL https://github.com/smartacephale/sleazy-fork/issues
13
13
  // @match https://*.spankbang.com/*
14
14
  // @match https://*.spankbang.*/*
15
- // @require https://cdn.jsdelivr.net/npm/pervert-monkey@1.0.10/dist/core/pervertmonkey.core.umd.js
15
+ // @require https://cdn.jsdelivr.net/npm/pervert-monkey@1.0.13/dist/core/pervertmonkey.core.umd.js
16
16
  // @require data:application/javascript,var core = window.pervertmonkey.core || pervertmonkey.core; var utils = core;
17
17
  // @grant GM_addStyle
18
18
  // @grant unsafeWindow
19
19
  // @run-at document-idle
20
20
  // ==/UserScript==
21
21
 
22
- (function (core, utils) {
22
+ (function (core) {
23
23
  'use strict';
24
24
 
25
25
  new core.Rules({
@@ -31,45 +31,13 @@
31
31
  thumb: {
32
32
  selectors: {
33
33
  title: "[title]",
34
+ tags: { selector: '[data-testid="title"]', type: "string" },
34
35
  duration: '[data-testid="video-item-length"]'
35
36
  }
36
37
  },
37
38
  thumbImg: { strategy: "auto" },
38
39
  gropeStrategy: "all-in-all",
39
- schemeOptions: ["Text Filter", "Duration Filter", "Badge", "Advanced"],
40
- animatePreview
40
+ schemeOptions: ["Text Filter", "Duration Filter", "Badge", "Advanced"]
41
41
  });
42
- function animatePreview(container) {
43
- function createPreviewElement(src) {
44
- return utils.parseHtml(`
45
- <div class="video-js vjs-controls-disabled vjs-workinghover vjs-v7 vjs-playing vjs-has-started mp4t_video-dimensions vjs-user-inactive"
46
- id="mp4t_video" tabindex="-1" lang="en" translate="no" role="region" aria-label="Video Player"
47
- style="opacity: 1;">
48
- <video id="mp4t_video_html5_api" class="vjs-tech" tabindex="-1" autoplay="autoplay" muted="muted" playsinline="playsinline"
49
- src="${src}">
50
- </video>
51
- </div>`);
52
- }
53
- function animateThumb(e) {
54
- const src = e.querySelector("[data-preview]")?.getAttribute("data-preview");
55
- const vid = createPreviewElement(src);
56
- e.append(vid);
57
- return () => {
58
- const v = vid.querySelector("video");
59
- utils.exterminateVideo(v);
60
- vid.remove();
61
- };
62
- }
63
- utils.OnHover.create(
64
- container,
65
- (e) => e.tagName === "IMG",
66
- (e) => {
67
- const target = e;
68
- const leaveTarget = target.closest(".thumb");
69
- const onOverCallback = animateThumb(leaveTarget);
70
- return { leaveTarget, onOverCallback };
71
- }
72
- );
73
- }
74
42
 
75
- })(core, utils);
43
+ })(core);
@@ -1,7 +1,7 @@
1
1
  // ==UserScript==
2
2
  // @name ThisVid.com Improved
3
3
  // @namespace pervertmonkey
4
- // @version 8.0.1
4
+ // @version 8.0.3
5
5
  // @author violent-orangutan
6
6
  // @description Infinite scroll [optional]. Preview for private videos. Filter: title, duration, public/private. Check access to private vids. Mass friend request button. Sorts messages. Download button 📼
7
7
  // @license MIT
@@ -11,7 +11,7 @@
11
11
  // @source github:smartacephale/sleazy-fork
12
12
  // @supportURL https://github.com/smartacephale/sleazy-fork/issues
13
13
  // @match https://*.thisvid.com/*
14
- // @require https://cdn.jsdelivr.net/npm/pervert-monkey@1.0.10/dist/core/pervertmonkey.core.umd.js
14
+ // @require https://cdn.jsdelivr.net/npm/pervert-monkey@1.0.13/dist/core/pervertmonkey.core.umd.js
15
15
  // @require data:application/javascript,var core = window.pervertmonkey.core || pervertmonkey.core; var utils = core;
16
16
  // @grant GM_addStyle
17
17
  // @grant unsafeWindow
@@ -907,8 +907,8 @@ function takeWhile(predicate) {
907
907
  },
908
908
  thumb: {
909
909
  selectors: {
910
- titleSelector: ".title",
911
- durationSelector: ".duration",
910
+ title: ".title",
911
+ duration: ".duration",
912
912
  private: { selector: ".private", type: "boolean" },
913
913
  hd: { selector: ".quality", type: "boolean" },
914
914
  views: { selector: ".view", type: "number" }
@@ -1157,24 +1157,22 @@ function takeWhile(predicate) {
1157
1157
  (_2, n) => `${utils.circularShift(parseInt(n), 6)}`
1158
1158
  );
1159
1159
  }
1160
- function animate(container) {
1161
- utils.OnHover.create(
1162
- container,
1163
- (target) => !!target.getAttribute("src"),
1164
- (target) => {
1165
- const e = target;
1166
- const orig = target.getAttribute("src");
1167
- tick.start(
1168
- () => iteratePreviewFrames(e),
1169
- () => {
1170
- e.src = orig;
1171
- }
1172
- );
1173
- },
1174
- () => tick.stop()
1175
- );
1176
- }
1177
- animate(document.querySelector(".content") || document.body);
1160
+ const container = document.querySelector(".content") || document.body;
1161
+ utils.OnHover.create(
1162
+ container,
1163
+ "div:has(> .tumbpu[title]):not(.thumbs-photo) > .tumbpu[title], .thumb-holder",
1164
+ (target) => {
1165
+ const img = target.querySelector("img");
1166
+ const orig = img.getAttribute("src");
1167
+ tick.start(
1168
+ () => iteratePreviewFrames(img),
1169
+ () => {
1170
+ img.src = orig;
1171
+ }
1172
+ );
1173
+ return () => tick.stop();
1174
+ }
1175
+ );
1178
1176
  }
1179
1177
  async function getMemberVideos(id, type = "private") {
1180
1178
  const { uploadedPrivate, uploadedPublic, name } = await getMemberData(id);
@@ -1,7 +1,7 @@
1
1
  // ==UserScript==
2
2
  // @name Xhamster Improved
3
3
  // @namespace pervertmonkey
4
- // @version 5.0.2
4
+ // @version 5.0.4
5
5
  // @author violent-orangutan
6
6
  // @description Infinite scroll [optional], Filter by Title and Duration
7
7
  // @license MIT
@@ -13,7 +13,7 @@
13
13
  // @match https://*.xhamster.com/*
14
14
  // @match https://*.xhamster.*/*
15
15
  // @exclude https://*.xhamster.com/embed*
16
- // @require https://cdn.jsdelivr.net/npm/pervert-monkey@1.0.10/dist/core/pervertmonkey.core.umd.js
16
+ // @require https://cdn.jsdelivr.net/npm/pervert-monkey@1.0.13/dist/core/pervertmonkey.core.umd.js
17
17
  // @require data:application/javascript,var core = window.pervertmonkey.core || pervertmonkey.core; var utils = core;
18
18
  // @grant GM_addElement
19
19
  // @grant GM_addStyle
@@ -24,6 +24,7 @@
24
24
  (function (core, utils) {
25
25
  'use strict';
26
26
 
27
+ var _GM_addElement = (() => typeof GM_addElement != "undefined" ? GM_addElement : undefined)();
27
28
  var _unsafeWindow = (() => typeof unsafeWindow != "undefined" ? unsafeWindow : undefined)();
28
29
 
29
30
  const IS_VIDEO_PAGE = /^\/videos|moments\//.test(location.pathname);
@@ -74,8 +75,8 @@
74
75
  paginationStrategyOptions,
75
76
  getPaginationData,
76
77
  containerSelectorLast: ".thumb-list",
77
- thumbs: { selector: "video-thumb" },
78
- thumb: {
78
+ thumbs: { selector: ".video-thumb" },
79
+ thumb: {
79
80
  selectors: {
80
81
  title: ".video-thumb-info__name,.video-thumb-info>a",
81
82
  duration: ".thumb-image-container__duration",
@@ -87,7 +88,7 @@ thumb: {
87
88
  },
88
89
  thumbImg: {
89
90
  strategy: "auto",
90
- shouldDelete: "[loading]"
91
+ remove: "[loading]"
91
92
  },
92
93
  gropeStrategy: "all-in-all",
93
94
  customDataSelectorFns: [
@@ -118,7 +119,7 @@ thumb: {
118
119
  });
119
120
  function animatePreview() {
120
121
  function createPreviewVideoElement(src, mount) {
121
- const video = GM_addElement("video", {
122
+ const video = _GM_addElement("video", {
122
123
  playsInline: true,
123
124
  autoplay: true,
124
125
  loop: true,
@@ -134,16 +135,12 @@ thumb: {
134
135
  );
135
136
  return () => utils.exterminateVideo(video);
136
137
  }
137
- utils.OnHover.create(
138
- document.body,
139
- (e) => e.classList.contains("thumb-image-container__image"),
140
- (e) => {
141
- const videoSrc = e.parentElement?.getAttribute("data-previewvideo");
142
- const onOverCallback = createPreviewVideoElement(videoSrc, e);
143
- const leaveTarget = e.parentElement?.parentElement;
144
- return { leaveTarget, onOverCallback };
145
- }
146
- );
138
+ utils.OnHover.create(document.body, ".video-thumb", (e) => {
139
+ const container = e.querySelector(".thumb-image-container__image");
140
+ const videoSrc = e.querySelector("[data-previewvideo]")?.getAttribute("data-previewvideo");
141
+ console.log(container, videoSrc);
142
+ return createPreviewVideoElement(videoSrc, container);
143
+ });
147
144
  }
148
145
  function expandMoreVideoPage() {
149
146
  utils.watchElementChildrenCount(rules.container, () => setTimeout(rules.gropeInit, 1800));
@@ -1,7 +1,7 @@
1
1
  // ==UserScript==
2
2
  // @name XVideos Improved
3
3
  // @namespace pervertmonkey
4
- // @version 4.0.2
4
+ // @version 4.0.4
5
5
  // @author violent-orangutan
6
6
  // @description Infinite scroll [optional], Filter by Title and Duration
7
7
  // @license MIT
@@ -11,7 +11,7 @@
11
11
  // @source github:smartacephale/sleazy-fork
12
12
  // @supportURL https://github.com/smartacephale/sleazy-fork/issues
13
13
  // @match https://*.xvideos.com/*
14
- // @require https://cdn.jsdelivr.net/npm/pervert-monkey@1.0.10/dist/core/pervertmonkey.core.umd.js
14
+ // @require https://cdn.jsdelivr.net/npm/pervert-monkey@1.0.13/dist/core/pervertmonkey.core.umd.js
15
15
  // @require data:application/javascript,var core = window.pervertmonkey.core || pervertmonkey.core; var utils = core;
16
16
  // @grant GM_addStyle
17
17
  // @grant unsafeWindow
@@ -74,16 +74,11 @@
74
74
  function getVideoURL(src) {
75
75
  return src.replace(/\w+\.\w+$/, () => "preview.mp4");
76
76
  }
77
- utils.OnHover.create(
78
- container,
79
- (target) => target.tagName === "IMG" && target.id.includes("pic_"),
80
- (target) => {
81
- const videoSrc = getVideoURL(target.src);
82
- const onOverCallback = createPreviewElement(videoSrc, target);
83
- const leaveTarget = target.closest(".thumb-inside");
84
- return { leaveTarget, onOverCallback };
85
- }
86
- );
77
+ utils.OnHover.create(container, "div.thumb-block[id^=video_]:not(.thumb-ad)", (target) => {
78
+ const img = target.querySelector("img");
79
+ const videoSrc = getVideoURL(img.src);
80
+ return createPreviewElement(videoSrc, img);
81
+ });
87
82
  }
88
83
 
89
84
  })(core, utils);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pervert-monkey",
3
3
  "description": "daddy told us not to be ashamed of our userscripts",
4
- "version": "1.0.11",
4
+ "version": "1.0.13",
5
5
  "license": "MIT",
6
6
  "keywords": [
7
7
  "userscript",
@@ -14,7 +14,7 @@ export class DataManager {
14
14
 
15
15
  constructor(
16
16
  private rules: Rules,
17
- private parseDataParentHomogenity?: Parameters<typeof checkHomogenity>[2]
17
+ private parentHomogenity?: Parameters<typeof checkHomogenity>[2],
18
18
  ) {
19
19
  this.dataFilter = new DataFilter(this.rules);
20
20
  }
@@ -82,10 +82,10 @@ export class DataManager {
82
82
  const dataOffset = this.data.size;
83
83
  const fragment = document.createDocumentFragment();
84
84
  const parent = container || this.rules.container;
85
- const homogenity = !!this.parseDataParentHomogenity;
85
+ const homogenity = !!this.parentHomogenity;
86
86
 
87
87
  for (const thumbElement of thumbs) {
88
- const url = this.rules.getThumbUrl(thumbElement);
88
+ const url = this.rules.thumbDataParser.getUrl(thumbElement);
89
89
  if (
90
90
  !url ||
91
91
  this.data.has(url) ||
@@ -94,7 +94,7 @@ export class DataManager {
94
94
  !checkHomogenity(
95
95
  parent,
96
96
  thumbElement.parentElement as HTMLElement,
97
- this.parseDataParentHomogenity as object,
97
+ this.parentHomogenity as object,
98
98
  ))
99
99
  ) {
100
100
  if (removeDuplicates) thumbElement.remove();
@@ -1,2 +1,3 @@
1
- export * from './default-scheme'
2
- export * from './default-store'
1
+ export * from './default-scheme';
2
+ export * from './default-store';
3
+ export * from './jabroni-gui-controller';
@@ -0,0 +1,61 @@
1
+ import type { JabronioStore } from 'jabroni-outfit';
2
+ import { map, Subject, scan, shareReplay, takeUntil } from 'rxjs';
3
+ import type { DataManager } from '../data-handler';
4
+
5
+ interface DirectionalEventState {
6
+ type?: string;
7
+ direction: boolean;
8
+ }
9
+
10
+ export class JabronioGuiController {
11
+ constructor(
12
+ private store: JabronioStore,
13
+ private dataManager: DataManager,
14
+ ) {
15
+ this.directionalEventObservable$ = this.directionalEvent();
16
+ this.setupStoreListeners();
17
+ }
18
+
19
+ private readonly destroy$ = new Subject<void>();
20
+
21
+ public dispose() {
22
+ this.destroy$.next();
23
+ this.destroy$.complete();
24
+ }
25
+
26
+ private directionalEventObservable$?: ReturnType<typeof this.directionalEvent>;
27
+
28
+ private directionalEvent() {
29
+ return this.store.eventSubject.pipe(
30
+ scan(
31
+ (acc: DirectionalEventState, value: string) => ({
32
+ type: value,
33
+ direction: acc.type === value ? !acc.direction : true,
34
+ }),
35
+ { type: undefined, direction: true },
36
+ ),
37
+ map(({ type, direction }) => ({
38
+ type: type as keyof typeof this.eventsMap,
39
+ direction,
40
+ })),
41
+ shareReplay(1),
42
+ takeUntil(this.destroy$),
43
+ );
44
+ }
45
+
46
+ private readonly eventsMap = {
47
+ 'sort by duration': (direction: boolean) =>
48
+ this.dataManager.sortBy('duration', direction),
49
+ 'sort by views': (direction: boolean) => this.dataManager.sortBy('views', direction),
50
+ } as const;
51
+
52
+ private setupStoreListeners() {
53
+ this.directionalEventObservable$?.subscribe((e) => {
54
+ this.eventsMap[e.type](e.direction);
55
+ });
56
+
57
+ this.store.stateSubject.pipe(takeUntil(this.destroy$)).subscribe((a) => {
58
+ this.dataManager.applyFilters(a as { [key: string]: boolean });
59
+ });
60
+ }
61
+ }
@@ -1,4 +1,5 @@
1
1
  import {
2
+ parseNumberWithLetter,
2
3
  querySelectorLast,
3
4
  querySelectorText,
4
5
  sanitizeStr,
@@ -6,7 +7,7 @@ import {
6
7
  } from '../../utils';
7
8
 
8
9
  type Primitive = string | number | boolean;
9
- type PrimitiveString = 'boolean' | 'string' | 'number' | 'duration';
10
+ type PrimitiveString = 'boolean' | 'string' | 'number' | 'float' | 'duration';
10
11
  type ThumbData = Record<string, Primitive>;
11
12
  type ThumbDataSelector = {
12
13
  name: string;
@@ -25,6 +26,10 @@ export class ThumbDataParser {
25
26
  return { title, duration };
26
27
  }
27
28
 
29
+ public getUrl(thumb: HTMLElement | HTMLAnchorElement) {
30
+ return ((thumb.querySelector('a[href]') || thumb) as HTMLAnchorElement).href;
31
+ }
32
+
28
33
  private preprocessCustomThumbDataSelectors() {
29
34
  if (!this.selectors) return;
30
35
  Object.entries(this.selectors).forEach(([key, value]) => {
@@ -66,6 +71,10 @@ export class ThumbDataParser {
66
71
  if (type === 'duration') {
67
72
  return timeToSeconds(querySelectorText(thumb, selector));
68
73
  }
74
+ if (type === 'float') {
75
+ const value = querySelectorText(thumb, selector);
76
+ return parseNumberWithLetter(value);
77
+ }
69
78
  return Number.parseInt(querySelectorText(thumb, selector));
70
79
  }
71
80
 
@@ -6,20 +6,21 @@ import {
6
6
  } from '../../utils';
7
7
  import { DataManager, type DataSelectorFn } from '../data-handler';
8
8
  import { InfiniteScroller, type OffsetGenerator } from '../infinite-scroll';
9
- import { DefaultScheme, type SchemeOptions, StoreStateDefault } from '../jabroni-config';
9
+ import {
10
+ DefaultScheme,
11
+ JabronioGuiController,
12
+ type SchemeOptions,
13
+ StoreStateDefault,
14
+ } from '../jabroni-config';
10
15
  import {
11
16
  getPaginationStrategy,
12
17
  type PaginationStrategy,
13
18
  ThumbDataParser,
14
19
  ThumbImgParser,
15
- ThumbsParser
20
+ ThumbsParser,
16
21
  } from '../parsers';
17
22
 
18
23
  export class Rules {
19
- public getThumbUrl(thumb: HTMLElement | HTMLAnchorElement) {
20
- return ((thumb.querySelector('a[href]') || thumb) as HTMLAnchorElement).href;
21
- }
22
-
23
24
  public thumb: Parameters<typeof ThumbDataParser.create>[0] = {};
24
25
  public thumbDataParser: ThumbDataParser;
25
26
 
@@ -73,6 +74,7 @@ export class Rules {
73
74
  public schemeOptions: SchemeOptions = [];
74
75
  public store: JabronioStore;
75
76
  public gui: JabronioGUI;
77
+ public inputController: JabronioGuiController;
76
78
 
77
79
  private createStore() {
78
80
  const config = { ...StoreStateDefault, ...this.storeOptions };
@@ -117,35 +119,6 @@ export class Rules {
117
119
  return window.self !== window.top;
118
120
  }
119
121
 
120
- private setupStoreListeners() {
121
- const eventsMap = {
122
- 'sort by duration': {
123
- action: (direction: boolean) => this.dataManager.sortBy('duration', direction),
124
- },
125
- };
126
-
127
- let lastEvent: undefined | string;
128
- let direction = true;
129
-
130
- this.store.eventSubject.subscribe((event) => {
131
- if (event === lastEvent) {
132
- direction = !direction;
133
- } else {
134
- lastEvent = event;
135
- direction = true;
136
- }
137
-
138
- if (event in eventsMap) {
139
- const ev = eventsMap[event as keyof typeof eventsMap];
140
- ev?.action(direction);
141
- }
142
- });
143
-
144
- this.store.stateSubject.subscribe((a) => {
145
- this.dataManager.applyFilters(a as { [key: string]: boolean });
146
- });
147
- }
148
-
149
122
  private mutationObservers: MutationObserver[] = [];
150
123
 
151
124
  public resetOnPaginationOrContainerDeath = true;
@@ -171,8 +144,6 @@ export class Rules {
171
144
  public onResetCallback?: () => void;
172
145
 
173
146
  private reset() {
174
- // console.log('\nRESET\n');
175
-
176
147
  this.mutationObservers.forEach((o) => {
177
148
  o.disconnect();
178
149
  });
@@ -181,7 +152,9 @@ export class Rules {
181
152
  this.paginationStrategy = getPaginationStrategy(this.paginationStrategyOptions);
182
153
 
183
154
  this.dataManager = new DataManager(this, this.dataHomogenity);
184
- this.setupStoreListeners();
155
+
156
+ this.inputController.dispose();
157
+ this.inputController = new JabronioGuiController(this.store, this.dataManager);
185
158
 
186
159
  this.resetInfiniteScroller();
187
160
 
@@ -209,8 +182,8 @@ export class Rules {
209
182
  this.gui = this.createGui();
210
183
 
211
184
  this.dataManager = new DataManager(this, this.dataHomogenity);
185
+ this.inputController = new JabronioGuiController(this.store, this.dataManager);
212
186
 
213
187
  this.reset();
214
- // console.log('data', this.dataManager.data.values().toArray());
215
188
  }
216
189
  }
@@ -1 +1 @@
1
- import './scripts/eporner'
1
+ import './scripts/motherless'
@@ -4,7 +4,7 @@ import { circularShift, OnHover, Tick } from '../../utils';
4
4
 
5
5
  export const meta: MonkeyUserScript = {
6
6
  name: '3Hentai PervertMonkey',
7
- version: '1.0.2',
7
+ version: '1.0.4',
8
8
  description: 'Infinite scroll [optional], Filter by Title',
9
9
  match: 'https://*.3hentai.net/*',
10
10
  };
@@ -12,12 +12,12 @@ export const meta: MonkeyUserScript = {
12
12
  const rules = new Rules({
13
13
  containerSelectorLast: '.listing-container',
14
14
  thumbs: {
15
- selector: '.doujin-col'
15
+ selector: '.doujin-col',
16
16
  },
17
17
  thumb: {
18
18
  selectors: {
19
19
  title: '.title',
20
- }
20
+ },
21
21
  },
22
22
  thumbImg: {
23
23
  strategy: 'auto',
@@ -33,27 +33,23 @@ function animatePreview() {
33
33
  const end = 9999;
34
34
 
35
35
  function rotate(src: string) {
36
- return src.replace(/(\d+)(?=t\.jpg$)/,
37
- (_, n) => `${circularShift(parseInt(n), end)}`);
36
+ return src.replace(/(\d+)(?=t\.jpg$)/, (_, n) => `${circularShift(parseInt(n), end)}`);
38
37
  }
39
38
 
40
- OnHover.create(
41
- document.body,
42
- (e) => e instanceof HTMLImageElement && e.src.endsWith('.jpg'),
43
- (e) => {
44
- const t = e as HTMLImageElement;
45
- const origin = t.src;
46
- t.src = t.src.replace(/\w+\.\w+$/, '1t.jpg');
47
- t.onerror = (_) => tick.stop();
48
- tick.start(
49
- () => {
50
- t.src = rotate(t.src);
51
- },
52
- () => {
53
- t.src = origin;
54
- },
55
- );
56
- },
57
- (_) => tick.stop()
58
- );
39
+ OnHover.create(document.body, '.doujin-col', (e) => {
40
+ const img = e.querySelector('img') as HTMLImageElement;
41
+ const origin = img.src;
42
+ img.src = img.src.replace(/\w+\.\w+$/, '1t.jpg');
43
+ img.onerror = (_) => tick.stop();
44
+ tick.start(
45
+ () => {
46
+ img.src = rotate(img.src);
47
+ },
48
+ () => {
49
+ img.src = origin;
50
+ },
51
+ );
52
+
53
+ return () => tick.stop();
54
+ });
59
55
  }
@@ -2,7 +2,7 @@ import type { MonkeyUserScript } from 'vite-plugin-monkey';
2
2
 
3
3
  export const meta: MonkeyUserScript = {
4
4
  name: 'CamGirlFinder PervertMonkey',
5
- version: '1.6.0',
5
+ version: '1.6.2',
6
6
  description:
7
7
  'Adds model links for CamWhores, webcamrecordings, recu.me, camvideos, privat-zapisi',
8
8
  match: ['https://camgirlfinder.net/*'],
@@ -17,7 +17,7 @@ import {
17
17
 
18
18
  export const meta: MonkeyUserScript = {
19
19
  name: 'CamWhores PervertMonkey',
20
- version: '3.0.4',
20
+ version: '3.0.6',
21
21
  description:
22
22
  'Infinite scroll [optional]. Filter by Title, Duration and Private/Public. Mass friend request button. Download button',
23
23
  match: ['https://*.camwhores.tv', 'https://*.camwhores.*/*'],
@@ -48,7 +48,7 @@ const rules = new Rules({
48
48
  },
49
49
  thumbs: {
50
50
  selector:
51
- '.list-videos .item, .playlist .item, .list-playlists > div > .item, .item:has(.title)'
51
+ '.list-videos .item, .playlist .item, .list-playlists > div > .item, .item:has(.title)',
52
52
  },
53
53
  thumb: {
54
54
  strategy: 'auto-select',
@@ -108,28 +108,21 @@ function animatePreview(container: HTMLElement) {
108
108
 
109
109
  OnHover.create(
110
110
  container,
111
- (target) =>
112
- target.tagName === 'IMG' &&
113
- target.classList.contains('thumb') &&
114
- !!target.getAttribute('src') &&
115
- !/data:image|avatar/.test(target.getAttribute('src') as string),
116
- (_target) => {
117
- const target = _target as HTMLImageElement;
118
- const origin = target.src;
119
- const count = parseInt(target.getAttribute('data-cnt') as string) || 5;
111
+ '.list-videos .item, .playlist .item, .list-playlists > div > .item, .item:has(.title)',
112
+ (e) => {
113
+ const img = e.querySelector('img') as HTMLImageElement;
114
+ const origin = img.src;
115
+ const count = parseInt(img.getAttribute('data-cnt') as string) || 5;
120
116
  tick.start(
121
117
  () => {
122
- target.src = rotateImg(target.src, count);
118
+ img.src = rotateImg(img.src, count);
123
119
  },
124
120
  () => {
125
- target.src = origin;
121
+ img.src = origin;
126
122
  },
127
123
  );
128
- return {
129
- leaveTarget: target.closest('.item') as HTMLElement,
130
- };
124
+ return () => tick.stop();
131
125
  },
132
- () => tick.stop(),
133
126
  );
134
127
  }
135
128
 
@@ -4,7 +4,7 @@ import { fetchHtml } from '../../utils';
4
4
 
5
5
  export const meta: MonkeyUserScript = {
6
6
  name: 'E-Hentai PervertMonkey',
7
- version: '1.0.0',
7
+ version: '1.0.2',
8
8
  description: 'Infinite scroll [optional], Filter by Title',
9
9
  match: ['https://*.e-hentai.org/*'],
10
10
  };