pervert-monkey 1.0.25 → 1.0.27

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 (62) hide show
  1. package/README.md +5 -2
  2. package/dist/core/pervertmonkey.core.es.d.ts +2 -541
  3. package/dist/core/pervertmonkey.core.es.js +8005 -9281
  4. package/dist/core/pervertmonkey.core.es.js.map +1 -1
  5. package/dist/core/pervertmonkey.core.umd.js +8833 -10051
  6. package/dist/core/pervertmonkey.core.umd.js.map +1 -1
  7. package/dist/userscripts/3hentai.user.js +40 -46
  8. package/dist/userscripts/camgirlfinder.user.js +56 -49
  9. package/dist/userscripts/camwhores.user.js +286 -343
  10. package/dist/userscripts/e-hentai.user.js +54 -57
  11. package/dist/userscripts/ebalka.user.js +52 -55
  12. package/dist/userscripts/eporner.user.js +76 -68
  13. package/dist/userscripts/erome.user.js +79 -84
  14. package/dist/userscripts/eroprofile.user.js +28 -29
  15. package/dist/userscripts/javhdporn.user.js +28 -22
  16. package/dist/userscripts/missav.user.js +22 -23
  17. package/dist/userscripts/motherless.user.js +141 -152
  18. package/dist/userscripts/namethatporn.user.js +49 -58
  19. package/dist/userscripts/nhentai.user.js +104 -99
  20. package/dist/userscripts/obmenvsem.user.js +61 -69
  21. package/dist/userscripts/pornhub.user.js +50 -47
  22. package/dist/userscripts/simpcity.user.js +82 -24
  23. package/dist/userscripts/socialmediagirls.user.js +26 -22
  24. package/dist/userscripts/spankbang.user.js +62 -44
  25. package/dist/userscripts/thisvid.user.js +1269 -1366
  26. package/dist/userscripts/xhamster.user.js +119 -132
  27. package/dist/userscripts/xmegadrive.user.js +82 -0
  28. package/dist/userscripts/xvideos.user.js +115 -91
  29. package/package.json +10 -6
  30. package/src/core/data-handler/data-filter.ts +3 -3
  31. package/src/core/data-handler/data-manager.ts +11 -3
  32. package/src/core/parsers/pagination-parser/index.ts +0 -4
  33. package/src/core/parsers/pagination-parser/pagination-strategies/PaginationStrategyPathnameParams.ts +36 -1
  34. package/src/core/rules/index.ts +3 -3
  35. package/src/userscripts/index.ts +1 -1
  36. package/src/userscripts/meta.json +1 -1
  37. package/src/userscripts/scripts/3hentai.ts +1 -1
  38. package/src/userscripts/scripts/camgirlfinder.ts +1 -1
  39. package/src/userscripts/scripts/camwhores.ts +2 -2
  40. package/src/userscripts/scripts/e-hentai.ts +1 -1
  41. package/src/userscripts/scripts/ebalka.ts +2 -2
  42. package/src/userscripts/scripts/eporner.ts +41 -15
  43. package/src/userscripts/scripts/erome.ts +1 -1
  44. package/src/userscripts/scripts/eroprofile.ts +6 -6
  45. package/src/userscripts/scripts/javhdporn.ts +1 -1
  46. package/src/userscripts/scripts/missav.ts +1 -1
  47. package/src/userscripts/scripts/motherless.ts +28 -19
  48. package/src/userscripts/scripts/namethatporn.ts +1 -1
  49. package/src/userscripts/scripts/nhentai.ts +1 -1
  50. package/src/userscripts/scripts/obmenvsem.ts +1 -1
  51. package/src/userscripts/scripts/pornhub.ts +4 -2
  52. package/src/userscripts/scripts/simpcity.ts +72 -5
  53. package/src/userscripts/scripts/{socialmediagirls copy.ts → socialmediagirls.ts} +1 -1
  54. package/src/userscripts/scripts/spankbang.ts +20 -4
  55. package/src/userscripts/scripts/thisvid.ts +8 -21
  56. package/src/userscripts/scripts/xhamster.ts +12 -4
  57. package/src/userscripts/scripts/xmegadrive.ts +78 -0
  58. package/src/userscripts/scripts/xvideos.ts +26 -7
  59. package/src/utils/fetch/index.ts +2 -0
  60. package/src/utils/objects/memoize.ts +1 -9
  61. package/dist/test/test.user.js +0 -10301
  62. package/dist/userscripts/socialmediagirls copy.user.js +0 -41
@@ -21,7 +21,7 @@ import {
21
21
 
22
22
  export const meta: MonkeyUserScript = {
23
23
  name: 'ThisVid.com PervertMonkey',
24
- version: '8.0.20',
24
+ version: '8.0.23',
25
25
  description:
26
26
  'Infinite scroll [optional]. Preview for private videos. Filter by Title, Duration, Quality and Public/Private. Sort by Duration and Views. Private/Public feed of friends uploads. Check access to private vids. Mass friend request button. Sorts messages. Download button 📼',
27
27
  match: ['https://*.thisvid.com/*'],
@@ -138,8 +138,6 @@ GM_addStyle(`
138
138
  .friendProfile { background: radial-gradient(circle, rgb(28, 42, 50) 48%, rgb(0, 0, 0) 100%) !important; }
139
139
  `);
140
140
 
141
- //====================================================================================================
142
-
143
141
  function friend(id: string, message = '') {
144
142
  return fetch(
145
143
  `https://thisvid.com/members/${id}/?action=add_to_friends_complete&function=get_block&block_id=member_profile_view_view_profile&format=json&mode=async&message=${message}`,
@@ -209,7 +207,7 @@ async function friendMemberFriends(orientationFilter?: string) {
209
207
  await friend(fid);
210
208
  }
211
209
  }
212
- }, 60),
210
+ }, 5),
213
211
  )
214
212
  .forEach(() => {});
215
213
  }
@@ -247,8 +245,6 @@ function initFriendship() {
247
245
  }
248
246
  }
249
247
 
250
- //====================================================================================================
251
-
252
248
  type MemberData = {
253
249
  uploadedPublic: number;
254
250
  uploadedPrivate: number;
@@ -284,8 +280,6 @@ async function getMemberData(id: string) {
284
280
  return data as MemberData;
285
281
  }
286
282
 
287
- //====================================================================================================
288
-
289
283
  function requestAccessVideoPage() {
290
284
  const holder = document.querySelector('.video-holder > p');
291
285
  if (holder) {
@@ -308,6 +302,8 @@ const requestPrivateAccess = (e: PointerEvent, memberid: string) => {
308
302
  );
309
303
  };
310
304
 
305
+ Object.assign(unsafeWindow, { requestPrivateAccess });
306
+
311
307
  async function checkPrivateVideoAccess(url: string) {
312
308
  const html = await fetchHtml(url);
313
309
  const holder = html.querySelector('.video-holder > p');
@@ -317,6 +313,9 @@ async function checkPrivateVideoAccess(url: string) {
317
313
  const uploaderEl = (
318
314
  holder ? holder.querySelector('a') : html.querySelector('a.author')
319
315
  ) as HTMLAnchorElement;
316
+
317
+ if (!uploaderEl) return { access: false, uploaderURL: '' };
318
+
320
319
  const uploaderURL = uploaderEl.href.match(/\d+/)?.at(-1) as string;
321
320
  const uploaderName = uploaderEl.innerText;
322
321
 
@@ -344,7 +343,7 @@ async function requestAccess() {
344
343
  const { access, uploaderURL } = await checkPrivateVideoAccess(url);
345
344
 
346
345
  thumb.classList.add(access ? 'haveAccess' : 'haveNoAccess');
347
- if (access) return;
346
+ if (access || uploaderURL === '') return;
348
347
 
349
348
  if (rules.store.state.autoRequestAccess && !uploadersChecked.has(uploaderURL)) {
350
349
  acceptFriendship(uploaderURL);
@@ -357,8 +356,6 @@ async function requestAccess() {
357
356
  }
358
357
  }
359
358
 
360
- //====================================================================================================
361
-
362
359
  const createDownloadButton = () =>
363
360
  downloader({
364
361
  after: '.share_btn',
@@ -367,8 +364,6 @@ const createDownloadButton = () =>
367
364
  doBefore: () => $('.fp-ui').click(),
368
365
  });
369
366
 
370
- //====================================================================================================
371
-
372
367
  function animatePreview(_: HTMLElement) {
373
368
  const tick = new Tick(750);
374
369
  $('img[alt!="Private"]').off();
@@ -402,8 +397,6 @@ function animatePreview(_: HTMLElement) {
402
397
  );
403
398
  }
404
399
 
405
- //====================================================================================================
406
-
407
400
  async function getMemberVideos(id: string, type = 'private') {
408
401
  const { uploadedPrivate, uploadedPublic, name } = await getMemberData(id);
409
402
  const videosCount = type === 'private' ? uploadedPrivate : uploadedPublic;
@@ -625,8 +618,6 @@ async function createPrivateFeed() {
625
618
  return rulesConfig;
626
619
  }
627
620
 
628
- //====================================================================================================
629
-
630
621
  function deleteMsg(id: string) {
631
622
  fetch(
632
623
  `https://thisvid.com/my_messages/inbox/?mode=async&format=json&action=delete&function=get_block&block_id=list_messages_my_conversation_messages&delete[]=${id}`,
@@ -673,8 +664,6 @@ function highlightMessages() {
673
664
  });
674
665
  }
675
666
 
676
- //====================================================================================================
677
-
678
667
  if (LOGGED_IN) {
679
668
  rules.store.eventSubject.subscribe((x) => {
680
669
  if (x.includes('check access')) {
@@ -697,8 +686,6 @@ if (IS_OTHER_MEMBER_PAGE) {
697
686
  initFriendship();
698
687
  }
699
688
 
700
- Object.assign(unsafeWindow, { requestPrivateAccess });
701
-
702
689
  if (IS_MEMBER_FRIEND) {
703
690
  document.querySelector('.profile')?.classList.add('friendProfile');
704
691
  }
@@ -14,7 +14,7 @@ import {
14
14
 
15
15
  export const meta: MonkeyUserScript = {
16
16
  name: 'Xhamster PervertMonkey',
17
- version: '5.0.21',
17
+ version: '5.0.23',
18
18
  description:
19
19
  'Infinite scroll [optional], Filter by Title, Duration and Watched/Unwatched. Sort by Duration and Views',
20
20
  match: ['https://*.xhamster.com/*', 'https://*.xhamster.*/*'],
@@ -88,7 +88,15 @@ const rules = new Rules({
88
88
  paginationStrategyOptions,
89
89
  getPaginationData,
90
90
  containerSelectorLast: '.thumb-list',
91
- thumbs: { selector: '.video-thumb' },
91
+ thumbs: {
92
+ selector: '.video-thumb',
93
+ transform: (thumb: HTMLElement) => {
94
+ if (thumb.querySelector('[class*=placeholder]')) {
95
+ console.log('has placeholder', thumb);
96
+ }
97
+ return thumb;
98
+ },
99
+ },
92
100
  thumb: {
93
101
  selectors: {
94
102
  title: '.video-thumb-info__name,.video-thumb-info>a',
@@ -99,7 +107,7 @@ const rules = new Rules({
99
107
  },
100
108
  thumbImg: {
101
109
  strategy: 'auto',
102
- remove: '[loading]',
110
+ // remove: '[loading]',
103
111
  },
104
112
  gropeStrategy: 'all-in-all',
105
113
  customDataFilterFns: [
@@ -168,4 +176,4 @@ function expandMoreVideoPage() {
168
176
 
169
177
  if (IS_VIDEO_PAGE) {
170
178
  expandMoreVideoPage();
171
- }
179
+ }
@@ -0,0 +1,78 @@
1
+ import type { MonkeyUserScript } from 'vite-plugin-monkey';
2
+ import { unsafeWindow } from '$';
3
+ import { Rules } from '../../core';
4
+ import { circularShift, OnHover, Tick } from '../../utils';
5
+
6
+ export const meta: MonkeyUserScript = {
7
+ name: 'xmegadrive PervertMonkey',
8
+ version: '1.0.0',
9
+ description:
10
+ 'Infinite scroll [optional]. Filter by Title and Duration. Sort by Duration and Views.',
11
+ match: ['https://*.xmegadrive.com/*'],
12
+ exclude: 'https://*.xmegadrive.com/*mode=async*',
13
+ };
14
+
15
+ const $ = (unsafeWindow as any).$;
16
+
17
+ const rules = new Rules({
18
+ containerSelector:
19
+ '[id*="playlist"]:has(> .item .title),[id*="videos"]:has(> .item .title),form:has(>.item .title)',
20
+ paginationStrategyOptions: {
21
+ paginationSelector: '.pagination:not([id *= member])',
22
+ },
23
+ thumbs: {
24
+ selector:
25
+ '.list-videos .item, .playlist .item, .list-playlists > div > .item, .item:has(.title)',
26
+ },
27
+ thumb: {
28
+ strategy: 'auto-select',
29
+ selectors: {
30
+ private: { type: 'boolean', selector: '[class*=private]' },
31
+ views: { selector: '.views', type: 'float' },
32
+ },
33
+ },
34
+ dataManagerOptions: { removeDuplicates: true },
35
+ thumbImg: {
36
+ selector: 'data-original',
37
+ },
38
+ gropeStrategy: 'all-in-all',
39
+ schemeOptions: ['Title Filter', 'Duration Filter', 'Sort By', 'Badge', 'Advanced'],
40
+ animatePreview,
41
+ });
42
+
43
+ function animatePreview(container: HTMLElement) {
44
+ const tick = new Tick(500);
45
+
46
+ function killjquery(n = 10) {
47
+ if (n > 0) {
48
+ n--;
49
+ $('img[data-cnt]').off();
50
+ setTimeout(() => killjquery(n), 250);
51
+ }
52
+ }
53
+
54
+ killjquery();
55
+
56
+ function rotateImg(src: string, count: number) {
57
+ return src.replace(/(\d)(?=\.jpg$)/, (_, n) => `${circularShift(parseInt(n), count)}`);
58
+ }
59
+
60
+ OnHover.create(
61
+ container,
62
+ '.list-videos .item, .playlist .item, .list-playlists > div > .item, .item:has(.title)',
63
+ (e) => {
64
+ const img = e.querySelector('img') as HTMLImageElement;
65
+ const origin = img.src;
66
+ const count = parseInt(img.getAttribute('data-cnt') as string) || 5;
67
+ tick.start(
68
+ () => {
69
+ img.src = rotateImg(img.src, count);
70
+ },
71
+ () => {
72
+ img.src = origin;
73
+ },
74
+ );
75
+ return () => tick.stop();
76
+ },
77
+ );
78
+ }
@@ -5,7 +5,7 @@ import { exterminateVideo, OnHover, parseHtml } from '../../utils';
5
5
 
6
6
  export const meta: MonkeyUserScript = {
7
7
  name: 'XVideos PervertMonkey',
8
- version: '4.0.21',
8
+ version: '4.1.0',
9
9
  description:
10
10
  'Infinite scroll [optional], Filter by Title, Uploader and Duration. Sort by Duration and Views.',
11
11
  match: 'https://*.xvideos.com/*',
@@ -36,12 +36,31 @@ const rules = new Rules({
36
36
  },
37
37
  },
38
38
  customDataFilterFns: [
39
- { qualityLow: (e, state) => !!state.qualityLow && e.quality !== '' },
40
- { quality360: (e, state) => !!state.quality360 && e.quality !== '360p' },
41
- { quality720: (e, state) => !!state.quality720 && e.quality !== '720p' },
42
- { quality1080: (e, state) => !!state.quality1080 && e.quality !== '1080p' },
43
- { quality1440: (e, state) => !!state.quality1440 && e.quality !== '1440p' },
44
- { quality4k: (e, state) => !!state.quality4k && e.quality !== '4k' },
39
+ {
40
+ qualityFilter: {
41
+ handle(el, state) {
42
+ const hasAnyQualitySelected =
43
+ state.qualityLow ||
44
+ state.quality360 ||
45
+ state.quality720 ||
46
+ state.quality1080 ||
47
+ state.quality1440 ||
48
+ state.quality4k;
49
+
50
+ if (!hasAnyQualitySelected) return false;
51
+
52
+ return !(
53
+ (state.qualityLow && el.quality === '') ||
54
+ (state.quality360 && el.quality === '360p') ||
55
+ (state.quality720 && el.quality === '720p') ||
56
+ (state.quality1080 && el.quality === '1080p') ||
57
+ (state.quality1440 && el.quality === '1440p') ||
58
+ (state.quality4k && el.quality === '4k')
59
+ );
60
+ },
61
+ deps: ['qualityLow', 'quality360', 'quality720', 'quality1080', 'quality1440', 'quality4k'],
62
+ },
63
+ },
45
64
  ],
46
65
  schemeOptions: [
47
66
  'Title Filter',
@@ -31,7 +31,9 @@ export async function fetchWith<T extends JSON | string | HTMLElement>(
31
31
 
32
32
  export const fetchJson = (input: RequestInfo | URL) =>
33
33
  fetchWith<JSON>(input, { type: 'json' });
34
+
34
35
  export const fetchHtml = (input: RequestInfo | URL) =>
35
36
  fetchWith<HTMLElement>(input, { type: 'html' });
37
+
36
38
  export const fetchText = (input: RequestInfo | URL) =>
37
39
  fetchWith<string>(input, { type: 'text' });
@@ -10,15 +10,7 @@ export function memoize<T extends AnyFunction>(fn: T): MemoizedFunction<T> {
10
10
 
11
11
  const memoizedFunction = ((...args: Parameters<T>): ReturnType<T> => {
12
12
  const key = JSON.stringify(args);
13
-
14
- if (cache.has(key)) {
15
- return cache.get(key) as ReturnType<T>;
16
- }
17
-
18
- const result = fn(...args);
19
- cache.set(key, result);
20
-
21
- return result;
13
+ return cache.getOrInsertComputed(key, () => fn(...args));
22
14
  }) as MemoizedFunction<T>;
23
15
 
24
16
  return memoizedFunction;