pervert-monkey 1.0.13 → 1.0.17

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 (58) hide show
  1. package/dist/core/pervertmonkey.core.es.d.ts +90 -36
  2. package/dist/core/pervertmonkey.core.es.js +258 -129
  3. package/dist/core/pervertmonkey.core.es.js.map +1 -1
  4. package/dist/core/pervertmonkey.core.umd.js +258 -129
  5. package/dist/core/pervertmonkey.core.umd.js.map +1 -1
  6. package/dist/userscripts/3hentai.user.js +4 -5
  7. package/dist/userscripts/camgirlfinder.user.js +2 -2
  8. package/dist/userscripts/camwhores.user.js +7 -16
  9. package/dist/userscripts/e-hentai.user.js +8 -8
  10. package/dist/userscripts/ebalka.user.js +18 -10
  11. package/dist/userscripts/eporner.user.js +24 -41
  12. package/dist/userscripts/erome.user.js +13 -16
  13. package/dist/userscripts/eroprofile.user.js +5 -14
  14. package/dist/userscripts/javhdporn.user.js +6 -5
  15. package/dist/userscripts/missav.user.js +10 -4
  16. package/dist/userscripts/motherless.user.js +13 -6
  17. package/dist/userscripts/namethatporn.user.js +10 -16
  18. package/dist/userscripts/nhentai.user.js +5 -13
  19. package/dist/userscripts/obmenvsem.user.js +11 -4
  20. package/dist/userscripts/pornhub.user.js +14 -6
  21. package/dist/userscripts/spankbang.user.js +28 -7
  22. package/dist/userscripts/thisvid.user.js +15 -33
  23. package/dist/userscripts/xhamster.user.js +13 -18
  24. package/dist/userscripts/xvideos.user.js +33 -5
  25. package/package.json +1 -1
  26. package/src/core/data-handler/data-filter-fn-defaults.ts +52 -0
  27. package/src/core/data-handler/data-filter-fn.ts +62 -0
  28. package/src/core/data-handler/data-filter.ts +31 -103
  29. package/src/core/data-handler/data-manager.ts +91 -28
  30. package/src/core/jabroni-config/default-scheme.ts +54 -5
  31. package/src/core/jabroni-config/index.ts +1 -0
  32. package/src/core/jabroni-config/jabroni-gui-controller.ts +1 -1
  33. package/src/core/jabroni-config/scheme-selectors-mapping.ts +12 -0
  34. package/src/core/parsers/thumb-data-parser.ts +15 -19
  35. package/src/core/rules/index.ts +15 -9
  36. package/src/userscripts/index.ts +1 -1
  37. package/src/userscripts/scripts/3hentai.ts +3 -4
  38. package/src/userscripts/scripts/camgirlfinder.ts +1 -1
  39. package/src/userscripts/scripts/camwhores.ts +5 -14
  40. package/src/userscripts/scripts/e-hentai.ts +12 -12
  41. package/src/userscripts/scripts/ebalka.ts +16 -8
  42. package/src/userscripts/scripts/eporner.ts +23 -39
  43. package/src/userscripts/scripts/erome.ts +13 -17
  44. package/src/userscripts/scripts/eroprofile.ts +4 -12
  45. package/src/userscripts/scripts/javhdporn.ts +7 -8
  46. package/src/userscripts/scripts/missav.ts +10 -4
  47. package/src/userscripts/scripts/motherless.ts +13 -7
  48. package/src/userscripts/scripts/namethatporn.ts +10 -17
  49. package/src/userscripts/scripts/nhentai.ts +6 -13
  50. package/src/userscripts/scripts/obmenvsem.ts +14 -4
  51. package/src/userscripts/scripts/pornhub.ts +13 -4
  52. package/src/userscripts/scripts/spankbang.ts +29 -5
  53. package/src/userscripts/scripts/thisvid.ts +16 -31
  54. package/src/userscripts/scripts/xhamster.ts +13 -18
  55. package/src/userscripts/scripts/xvideos.ts +32 -3
  56. package/src/utils/dom/dom-observers.ts +3 -3
  57. package/src/utils/dom/index.ts +1 -1
  58. package/src/utils/parsers/index.ts +5 -2
@@ -17,9 +17,9 @@ import {
17
17
 
18
18
  export const meta: MonkeyUserScript = {
19
19
  name: 'CamWhores PervertMonkey',
20
- version: '3.0.6',
20
+ version: '3.0.10',
21
21
  description:
22
- 'Infinite scroll [optional]. Filter by Title, Duration and Private/Public. Mass friend request button. Download button',
22
+ 'Infinite scroll [optional]. Filter by Title, Duration and Private/Public. Sort by Duration and Views. Mass friend request button. Download button',
23
23
  match: ['https://*.camwhores.tv', 'https://*.camwhores.*/*'],
24
24
  exclude: 'https://*.camwhores.tv/*mode=async*',
25
25
  };
@@ -54,27 +54,18 @@ const rules = new Rules({
54
54
  strategy: 'auto-select',
55
55
  selectors: {
56
56
  private: { type: 'boolean', selector: '[class*=private]' },
57
+ views: { selector: '.views', type: 'float' },
57
58
  },
58
59
  },
59
60
  thumbImg: {
60
61
  selector: 'data-original',
61
62
  },
62
63
  gropeStrategy: 'all-in-all',
63
- customDataSelectorFns: [
64
- 'filterInclude',
65
- 'filterExclude',
66
- 'filterDuration',
67
- {
68
- filterPrivate: (e, state) => (state.filterPrivate && e.private) as boolean,
69
- },
70
- {
71
- filterPublic: (e, state) => (state.filterPublic && !e.private) as boolean,
72
- },
73
- ],
74
64
  schemeOptions: [
75
- 'Text Filter',
65
+ 'Title Filter',
76
66
  'Duration Filter',
77
67
  'Privacy Filter',
68
+ 'Sort By',
78
69
  'Badge',
79
70
  {
80
71
  title: 'Advanced',
@@ -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.2',
7
+ version: '1.0.7',
8
8
  description: 'Infinite scroll [optional], Filter by Title',
9
9
  match: ['https://*.e-hentai.org/*'],
10
10
  };
@@ -13,33 +13,31 @@ const rules = new Rules({
13
13
  thumbs: { selector: '.gl1t' },
14
14
  thumb: {
15
15
  selectors: {
16
- title: '.glname'
17
- }
16
+ title: '.glname',
17
+ },
18
18
  },
19
19
  thumbImg: {
20
20
  selector: 'data-lazy-load',
21
21
  },
22
22
  containerSelectorLast: '.itg.gld',
23
23
  paginationStrategyOptions: createPaginationStrategyOptions(),
24
- customDataSelectorFns: ['filterInclude', 'filterExclude'],
25
- schemeOptions: ['Text Filter', 'Badge', 'Advanced'],
24
+ schemeOptions: ['Title Filter', 'Badge', 'Advanced'],
26
25
  });
27
26
 
28
27
  function createPaginationStrategyOptions(): Rules['paginationStrategyOptions'] {
29
28
  let nextLink: string;
30
29
 
31
- function getPaginationUrlGenerator() {
32
- function getNextLink(doc: Document | HTMLElement = document) {
33
- return [...doc.querySelectorAll<HTMLAnchorElement>('a#dnext[href]')].pop()
34
- ?.href as string;
35
- }
30
+ function getNextLink(doc: Document | HTMLElement = document) {
31
+ return [...doc.querySelectorAll<HTMLAnchorElement>('a#dnext[href]')].pop()
32
+ ?.href as string;
33
+ }
36
34
 
35
+ function getPaginationUrlGenerator() {
37
36
  const paginationUrlGenerator = async (_: number) => {
38
37
  if (!nextLink) {
39
38
  nextLink = getNextLink();
40
39
  return nextLink;
41
40
  }
42
- // need cache or reuse infinite scroller request
43
41
  const doc = await fetchHtml(nextLink);
44
42
  nextLink = getNextLink(doc);
45
43
  return nextLink;
@@ -48,9 +46,11 @@ function createPaginationStrategyOptions(): Rules['paginationStrategyOptions'] {
48
46
  return paginationUrlGenerator;
49
47
  }
50
48
 
49
+ const totalTitles = Number.parseInt(getNextLink()?.match(/\d+$/)?.[0] || '0');
50
+
51
51
  return {
52
52
  paginationSelector: '.searchnav + div + .searchnav',
53
- overwritePaginationLast: () => 9999999,
53
+ overwritePaginationLast: () => totalTitles,
54
54
  getPaginationUrlGenerator,
55
55
  };
56
56
  }
@@ -4,8 +4,8 @@ import { exterminateVideo, OnHover, parseHtml } from '../../utils';
4
4
 
5
5
  export const meta: MonkeyUserScript = {
6
6
  name: 'Ebalka PervertMonkey',
7
- version: '3.0.3',
8
- description: 'Infinite scroll [optional], Filter by Title and Duration',
7
+ version: '3.0.7',
8
+ description: 'Infinite scroll [optional], Filter by Title and Duration, Sort by Duration',
9
9
  match: [
10
10
  'https://b.ebalka.zip/*',
11
11
  'https://a.ebalka.love/*',
@@ -27,25 +27,33 @@ const rules = new Rules({
27
27
  selectors: {
28
28
  title: '.card__title',
29
29
  duration: '.card__spot > span:last-child',
30
+ hd: { selector: '.card__icons > .card__icon', type: 'boolean' },
30
31
  },
31
32
  },
32
33
  animatePreview,
33
- schemeOptions: ['Text Filter', 'Badge', 'Duration Filter', 'Advanced'],
34
+ schemeOptions: [
35
+ 'Title Filter',
36
+ 'Duration Filter',
37
+ 'HD Filter',
38
+ 'Sort By Duration',
39
+ 'Badge',
40
+ 'Advanced',
41
+ ],
34
42
  });
35
43
 
36
44
  function animatePreview(container: HTMLElement) {
37
45
  function animateThumb(thumb: HTMLElement) {
38
- const el = thumb.querySelector('.card__thumb_video') as HTMLElement;
39
- el.classList.toggle('video-on');
40
- const src = el.querySelector('.card__image')?.getAttribute('data-preview') as string;
46
+ const e = thumb.querySelector('.card__thumb_video') as HTMLElement;
47
+ e.classList.toggle('video-on');
48
+ const src = e.querySelector('.card__image')?.getAttribute('data-preview') as string;
41
49
 
42
50
  const videoElem =
43
51
  parseHtml(`<video style="position: absolute; left: 0px; top: 0px; visibility: visible; margin-top: -1px;"
44
52
  autoplay="" loop="" playsinline="true" webkit-playsinline="true" src="${src}"></video>`) as HTMLVideoElement;
45
- el.appendChild(videoElem);
53
+ e.appendChild(videoElem);
46
54
 
47
55
  return () => {
48
- el.classList.toggle('video-on');
56
+ e.classList.toggle('video-on');
49
57
  exterminateVideo(videoElem);
50
58
  };
51
59
  }
@@ -5,8 +5,9 @@ import { OnHover } from '../../utils';
5
5
 
6
6
  export const meta: MonkeyUserScript = {
7
7
  name: 'Eporner PervertMonkey',
8
- version: '2.0.4',
9
- description: 'Infinite scroll [optional], Filter by Title, Duration and HD',
8
+ version: '2.0.9',
9
+ description:
10
+ 'Infinite scroll [optional], Filter by Title, Uploader, Duration and HD, Sort by Views and Duration',
10
11
  match: ['https://*.eporner.com/*', 'https://*.eporner.*/*'],
11
12
  };
12
13
 
@@ -19,10 +20,11 @@ const rules = new Rules({
19
20
  thumbs: { selector: 'div[id^=vf][data-id]' },
20
21
  thumb: {
21
22
  selectors: {
22
- quality: { type: 'number', selector: '[title="Quality"]' },
23
23
  title: 'a',
24
24
  uploader: '[title="Uploader"]',
25
25
  duration: '[title="Duration"]',
26
+ views: { selector: '[title="Views"]', type: 'float' },
27
+ quality: { selector: '[title="Quality"]', type: 'number' },
26
28
  },
27
29
  },
28
30
  thumbImg: {
@@ -30,52 +32,34 @@ const rules = new Rules({
30
32
  remove: 'auto',
31
33
  },
32
34
  containerSelectorLast: '#vidresults',
33
- customDataSelectorFns: [
34
- 'filterInclude',
35
- 'filterExclude',
36
- 'filterDuration',
37
- {
38
- quality360: (el, state) => !!state.quality360 && el.quality !== 360,
39
- },
40
- {
41
- quality480: (el, state) => !!state.quality480 && el.quality !== 480,
42
- },
43
- {
44
- quality720: (el, state) => !!state.quality720 && el.quality !== 720,
45
- },
46
- {
47
- quality1080: (el, state) => !!state.quality1080 && el.quality !== 1080,
48
- },
49
- {
50
- quality4k: (el, state) => !!state.quality4k && el.quality !== 4,
51
- },
35
+ customDataFilterFns: [
36
+ { quality360: (el, state) => !!state.quality360 && el.quality !== 360 },
37
+ { quality480: (el, state) => !!state.quality480 && el.quality !== 480 },
38
+ { quality720: (el, state) => !!state.quality720 && el.quality !== 720 },
39
+ { quality1080: (el, state) => !!state.quality1080 && el.quality !== 1080 },
40
+ { quality2k: (el, state) => !!state.quality2k && el.quality !== 2 },
41
+ { quality4k: (el, state) => !!state.quality4k && el.quality !== 4 },
52
42
  ],
53
43
  schemeOptions: [
54
- 'Text Filter',
55
- 'Badge',
44
+ 'Title Filter',
45
+ 'Uploader Filter',
56
46
  'Duration Filter',
57
47
  {
58
48
  title: 'Quality Filter ',
59
49
  content: [
60
- {
61
- quality360: false,
62
- },
63
- {
64
- quality480: false,
65
- },
66
- {
67
- quality720: false,
68
- },
69
- {
70
- quality1080: false,
71
- },
72
- {
73
- quality4k: false,
74
- },
50
+ { quality360: false },
51
+ { quality480: false },
52
+ { quality720: false },
53
+ { quality1080: false },
54
+ { quality2k: false },
55
+ { quality4k: false },
75
56
  ],
76
57
  },
58
+ 'Sort By',
59
+ 'Badge',
77
60
  'Advanced',
78
61
  ],
62
+ gropeStrategy: 'all-in-all',
79
63
  animatePreview,
80
64
  });
81
65
 
@@ -4,8 +4,9 @@ import { Rules } from '../../core';
4
4
 
5
5
  export const meta: MonkeyUserScript = {
6
6
  name: 'Erome PervertMonkey',
7
- version: '5.0.3',
8
- description: 'Infinite scroll [optional], Filter by Title and Video/Photo albums',
7
+ version: '5.0.8',
8
+ description:
9
+ 'Infinite scroll [optional], Filter by Title, Uploader and Video/Photo albums, Sort by Views. Show/Hide Photos in album. Remove disclaimer.',
9
10
  match: ['*://*.erome.com/*'],
10
11
  };
11
12
 
@@ -22,37 +23,32 @@ const rules = new Rules({
22
23
  selectors: {
23
24
  title: '.album-title',
24
25
  uploader: '.album-user',
25
- videoAlbum: { type: 'boolean', selector: '.album-videos' },
26
+ videoAlbum: { selector: '.album-videos', type: 'boolean' },
27
+ views: { selector: '.album-bottom-views', type: 'float' },
26
28
  },
27
29
  },
28
30
  storeOptions: { showPhotos: true },
29
- customDataSelectorFns: [
30
- 'filterInclude',
31
- 'filterExclude',
32
- {
33
- filterPhotoAlbums: (el, state) =>
34
- (state.filterPhotoAlbums && !el.videoAlbum) as boolean,
35
- },
36
- {
37
- filterVideoAlbums: (el, state) =>
38
- (state.filterVideoAlbums && el.videoAlbum) as boolean,
39
- },
31
+ customDataFilterFns: [
32
+ { filterPhotoAlbums: (el, state) => !!state.filterPhotoAlbums && !el.videoAlbum },
33
+ { filterVideoAlbums: (el, state) => !!state.filterVideoAlbums && !!el.videoAlbum },
40
34
  ],
41
35
  schemeOptions: [
42
- 'Text Filter',
36
+ 'Title Filter',
37
+ 'Uploader Filter',
43
38
  {
44
39
  title: 'Filter Albums',
45
40
  content: [
46
41
  {
47
42
  filterVideoAlbums: false,
48
- label: 'video albums',
43
+ label: 'photo',
49
44
  },
50
45
  {
51
46
  filterPhotoAlbums: false,
52
- label: 'photo albums',
47
+ label: 'video',
53
48
  },
54
49
  ],
55
50
  },
51
+ 'Sort By Views',
56
52
  'Badge',
57
53
  'Advanced',
58
54
  ],
@@ -3,8 +3,8 @@ import { Rules } from '../../core';
3
3
 
4
4
  export const meta: MonkeyUserScript = {
5
5
  name: 'Eroprofile PervertMonkey',
6
- version: '2.0.3',
7
- description: 'Infinite scroll [optional], Filter by Title and Duration',
6
+ version: '2.0.7',
7
+ description: 'Infinite scroll [optional], Filter by Title and Duration, Sort by Duration',
8
8
  match: ['https://*.eroprofile.com/*'],
9
9
  };
10
10
 
@@ -23,18 +23,10 @@ const rules = new Rules({
23
23
  },
24
24
  },
25
25
  containerSelector: '.videoGrid',
26
- customDataSelectorFns: ['filterInclude', 'filterExclude', 'filterDuration'],
27
26
  schemeOptions: [
28
- 'Text Filter',
27
+ 'Title Filter',
29
28
  'Duration Filter',
30
- {
31
- title: 'Sort By ',
32
- content: [
33
- {
34
- 'sort by duration': () => {},
35
- },
36
- ],
37
- },
29
+ 'Sort By Duration',
38
30
  'Badge',
39
31
  'Advanced',
40
32
  ],
@@ -3,12 +3,10 @@ import { Rules } from '../../core';
3
3
 
4
4
  export const meta: MonkeyUserScript = {
5
5
  name: 'Javhdporn PervertMonkey',
6
- version: '3.0.3',
7
- description: 'Infinite scroll [optional], Filter by Title and Duration',
8
- match: [
9
- "https://*.javhdporn.net/*",
10
- "https://*.javhdporn.*/*"
11
- ],
6
+ version: '3.0.7',
7
+ description:
8
+ 'Infinite scroll [optional], Filter by Title and Duration, Sort By Duration and Views',
9
+ match: ['https://*.javhdporn.net/*', 'https://*.javhdporn.*/*'],
12
10
  };
13
11
 
14
12
  const rules = new Rules({
@@ -18,10 +16,11 @@ const rules = new Rules({
18
16
  selectors: {
19
17
  title: 'header.entry-header',
20
18
  duration: '.duration',
21
- }
19
+ views: { selector: '.views', type: 'float' },
20
+ },
22
21
  },
23
22
  paginationStrategyOptions: {
24
23
  pathnameSelector: /\/page\/(\d+)\/?$/,
25
24
  },
26
- schemeOptions: ['Text Filter', 'Badge', 'Duration Filter', 'Advanced'],
25
+ schemeOptions: ['Title Filter', 'Duration Filter', 'Sort By', 'Badge', 'Advanced'],
27
26
  });
@@ -3,8 +3,8 @@ import { Rules } from '../../core';
3
3
 
4
4
  export const meta: MonkeyUserScript = {
5
5
  name: 'Missav PervertMonkey',
6
- version: '3.0.3',
7
- description: 'Infinite scroll [optional], Filter by Title and Duration',
6
+ version: '3.0.7',
7
+ description: 'Infinite scroll [optional], Filter by Title and Duration, Sort by Duration',
8
8
  match: [
9
9
  'https://*.missav123.com/*',
10
10
  'https://*.missav.*/*',
@@ -24,8 +24,14 @@ const rules = new Rules({
24
24
  selectors: {
25
25
  title: 'div > div > a.text-secondary',
26
26
  duration: 'div > a > span.text-xs',
27
- }
27
+ },
28
28
  },
29
29
  thumbImg: { strategy: 'auto' },
30
- schemeOptions: ['Text Filter', 'Duration Filter', 'Badge', 'Advanced'],
30
+ schemeOptions: [
31
+ 'Title Filter',
32
+ 'Duration Filter',
33
+ 'Sort By Duration',
34
+ 'Badge',
35
+ 'Advanced',
36
+ ],
31
37
  });
@@ -5,8 +5,9 @@ import { fetchWith, OnHover, replaceElementTag, Tick } from '../../utils';
5
5
 
6
6
  export const meta: MonkeyUserScript = {
7
7
  name: 'Motherless PervertMonkey',
8
- version: '5.0.4',
9
- description: 'Infinite scroll [optional], Filter by Title and Duration',
8
+ version: '5.0.8',
9
+ description:
10
+ 'Infinite scroll [optional], Filter by Title, Uploader and Duration, Sort by Duration and Views',
10
11
  match: ['https://motherless.com/*'],
11
12
  grant: ['GM_addElement', 'GM_addStyle', 'unsafeWindow'],
12
13
  };
@@ -31,7 +32,14 @@ const rules = new Rules({
31
32
  },
32
33
  animatePreview,
33
34
  gropeStrategy: 'all-in-all',
34
- schemeOptions: ['Text Filter', 'Sort By', 'Duration Filter', 'Badge', 'Advanced'],
35
+ schemeOptions: [
36
+ 'Title Filter',
37
+ 'Uploader Filter',
38
+ 'Duration Filter',
39
+ 'Sort By',
40
+ 'Badge',
41
+ 'Advanced',
42
+ ],
35
43
  });
36
44
 
37
45
  function animatePreview(_: HTMLElement) {
@@ -152,7 +160,7 @@ async function desktopAddMobGalleries() {
152
160
  const overwrite1 = (x: string) => `@media only screen and (max-width: 1280px) {
153
161
  #categories-page.inner ${x} }`;
154
162
 
155
- rules.dataManager.dataFilter.applyCSSFilters(overwrite1);
163
+ rules.dataManager.dataFilter.createCssFilters(overwrite1);
156
164
 
157
165
  GM_addStyle(`
158
166
  .img-container, .desktop-thumb { min-height: 150px; max-height: 150px; }
@@ -174,9 +182,7 @@ function applySearchFilters() {
174
182
  let pathname = window.location.pathname;
175
183
 
176
184
  const wordsToFilter =
177
- (rules.store.state.filterExcludeWords as string)
178
- .replace(/f:/g, '')
179
- .match(/(?<!user:)\b\w+\b(?!\s*:)/g) || [];
185
+ (rules.store.state.filterExcludeWords as string).match(/\w+/g) || [];
180
186
 
181
187
  wordsToFilter
182
188
  .filter((w) => !pathname.includes(w))
@@ -4,8 +4,8 @@ import { Rules } from '../../core';
4
4
 
5
5
  export const meta: MonkeyUserScript = {
6
6
  name: 'NameThatPorn PervertMonkey',
7
- version: '3.0.3',
8
- description: 'Infinite scroll [optional], Filter by Title and Un/Solved',
7
+ version: '3.0.7',
8
+ description: 'Infinite scroll [optional], Filter by Title, Uploader and Solved/Unsolved',
9
9
  match: ['https://namethatporn.com/*'],
10
10
  };
11
11
 
@@ -16,35 +16,28 @@ const rules = new Rules({
16
16
  selectors: {
17
17
  title: '.item_title, .nsw_r_tit',
18
18
  uploader: '.item_answer b, .nsw_r_desc',
19
- solved: {
20
- type: 'boolean',
21
- selector: '.item_solved, .nsw_r_slvd',
22
- },
19
+ solved: { selector: '.item_solved, .nsw_r_slvd', type: 'boolean' },
23
20
  },
24
21
  },
25
22
  thumbImg: {
26
- selector: (img: HTMLImageElement) => {
27
- return (
28
- img.getAttribute('data-dyn')?.concat('.webp') || (img.getAttribute('src') as string)
29
- );
30
- },
23
+ selector: (img: HTMLImageElement) =>
24
+ img.getAttribute('data-dyn')?.concat('.webp') || (img.getAttribute('src') as string),
31
25
  },
32
26
  paginationStrategyOptions: {
33
27
  paginationSelector: '#smi_wrp, #nsw_p',
34
28
  },
35
29
  gropeStrategy: 'all-in-all',
36
- customDataSelectorFns: [
37
- 'filterInclude',
38
- 'filterExclude',
30
+ customDataFilterFns: [
39
31
  {
40
- filterSolved: (el, state) => (state.filterSolved && el.solved) as boolean,
32
+ filterSolved: (e, state) => (state.filterSolved && e.solved) as boolean,
41
33
  },
42
34
  {
43
- filterUnsolved: (el, state) => (state.filterUnsolved && !el.solved) as boolean,
35
+ filterUnsolved: (e, state) => (state.filterUnsolved && !e.solved) as boolean,
44
36
  },
45
37
  ],
46
38
  schemeOptions: [
47
- 'Text Filter',
39
+ 'Title Filter',
40
+ 'Uploader Filter',
48
41
  {
49
42
  title: 'Filter Status',
50
43
  content: [
@@ -4,7 +4,7 @@ import { parseHtml } from '../../utils';
4
4
 
5
5
  export const meta: MonkeyUserScript = {
6
6
  name: 'NHentai PervertMonkey',
7
- version: '4.0.3',
7
+ version: '4.0.7',
8
8
  description: 'Infinite scroll [optional], Filter by Title',
9
9
  match: ['https://*.nhentai.net/*', 'https://*.nhentai.*/*'],
10
10
  };
@@ -14,18 +14,10 @@ const IS_SEARCH_PAGE = /^\/search\//.test(location.pathname);
14
14
 
15
15
  const nhentaiRules = new Rules({
16
16
  thumbs: { selector: '.gallery' },
17
- thumb: {
18
- selectors: {
19
- title: '.caption'
20
- }
21
- },
22
- thumbImg: {
23
- strategy: 'auto',
24
- remove: 'auto'
25
- },
17
+ thumb: { selectors: { title: '.caption' } },
18
+ thumbImg: { strategy: 'auto', remove: 'auto' },
26
19
  containerSelectorLast: '.index-container, .container',
27
- customDataSelectorFns: ['filterInclude', 'filterExclude'],
28
- schemeOptions: ['Text Filter', 'Badge', 'Advanced'],
20
+ schemeOptions: ['Title Filter', 'Badge', 'Advanced'],
29
21
  gropeStrategy: 'all-in-all',
30
22
  });
31
23
 
@@ -57,7 +49,8 @@ function filtersUI() {
57
49
  const btns = parseHtml(`<div class="sort-type"></div>`);
58
50
  groupOfButtons.forEach((k) => {
59
51
  const btn = parseHtml(
60
- `<a href="#" ${state.custom[k] ? 'style="background: rgba(59, 49, 70, 1)"' : ''
52
+ `<a href="#" ${
53
+ state.custom[k] ? 'style="background: rgba(59, 49, 70, 1)"' : ''
61
54
  }>${filterDescriptors[k as keyof typeof filterDescriptors].name}</a>`,
62
55
  );
63
56
  btn.addEventListener('click', (e) => {
@@ -5,9 +5,13 @@ import { fetchHtml, parseUrl } from '../../utils';
5
5
 
6
6
  export const meta: MonkeyUserScript = {
7
7
  name: 'Obmensvem PervertMonkey',
8
- version: '1.0.3',
9
- description: 'Infinite scroll [optional], Filter by Title and Duration',
10
- match: ['https://*.obmenvsem.com/*', 'https://*.obmenvsem.*/*'],
8
+ version: '1.0.8',
9
+ description: 'Infinite scroll [optional], Filter by Title and Duration, Sort by Duration',
10
+ match: [
11
+ 'https://*.obmenvsem.com/*',
12
+ 'https://*.obmenvsem.*/*',
13
+ 'https://*.obmenvsems.*/*',
14
+ ],
11
15
  grant: ['GM_addStyle', 'GM_addElement', 'unsafeWindow'],
12
16
  };
13
17
 
@@ -67,5 +71,11 @@ const rules = new Rules({
67
71
  return img.src;
68
72
  },
69
73
  },
70
- schemeOptions: ['Text Filter', 'Duration Filter', 'Badge', 'Advanced'],
74
+ schemeOptions: [
75
+ 'Title Filter',
76
+ 'Duration Filter',
77
+ 'Sort By Duration',
78
+ 'Badge',
79
+ 'Advanced',
80
+ ],
71
81
  });
@@ -3,8 +3,9 @@ import { Rules } from '../../core';
3
3
 
4
4
  export const meta: MonkeyUserScript = {
5
5
  name: 'PornHub PervertMonkey',
6
- version: '4.0.3',
7
- description: 'Infinite scroll [optional]. Filter by Title and Duration',
6
+ version: '4.0.7',
7
+ description:
8
+ 'Infinite scroll [optional]. Filter by Title, Uploader and Duration. Sort by Duration and Views',
8
9
  match: ['https://*.pornhub.com/*'],
9
10
  exclude: 'https://*.pornhub.com/embed/*',
10
11
  };
@@ -19,20 +20,28 @@ const rules = new Rules({
19
20
  .filter((e) => e.children.length > 0 && e.checkVisibility())
20
21
  .pop() as HTMLElement,
21
22
 
22
- dataHomogenity: { id: true, className: true },
23
+ containerHomogenity: { id: true, className: true },
23
24
  thumbs: { selector: 'li[data-video-vkey]' },
24
25
  thumb: {
25
26
  selectors: {
26
27
  title: 'span.title',
27
28
  uploader: '.usernameWrap',
28
29
  duration: '.duration',
30
+ views: { selector: '.views', type: 'float' },
29
31
  },
30
32
  },
31
33
  thumbImg: {
32
34
  selector: ['data-mediumthumb', 'data-image'],
33
35
  },
34
36
  gropeStrategy: 'all-in-all',
35
- schemeOptions: ['Text Filter', 'Duration Filter', 'Badge', 'Advanced'],
37
+ schemeOptions: [
38
+ 'Title Filter',
39
+ 'Uploader Filter',
40
+ 'Duration Filter',
41
+ 'Sort By',
42
+ 'Badge',
43
+ 'Advanced',
44
+ ],
36
45
  });
37
46
 
38
47
  function bypassAgeVerification() {
@@ -3,8 +3,9 @@ import { Rules } from '../../core';
3
3
 
4
4
  export const meta: MonkeyUserScript = {
5
5
  name: 'SpankBang.com PervertMonkey',
6
- version: '4.0.3',
7
- description: 'Infinite scroll [optional]. Filter by Title and Duration',
6
+ version: '4.0.7',
7
+ description:
8
+ 'Infinite scroll [optional]. Filter by Title and Duration. Sort by Duration and Views',
8
9
  match: ['https://*.spankbang.com/*', 'https://*.spankbang.*/*'],
9
10
  };
10
11
 
@@ -17,11 +18,34 @@ const rules = new Rules({
17
18
  thumb: {
18
19
  selectors: {
19
20
  title: '[title]',
20
- tags: { selector: '[data-testid="title"]', type: 'string' },
21
21
  duration: '[data-testid="video-item-length"]',
22
- }
22
+ // tags: { selector: '[data-testid="title"]', type: 'string' },
23
+ views: { selector: '[data-testid="views"]', type: 'float' },
24
+ quality: { selector: '[data-testid="video-item-resolution"]', type: 'string' },
25
+ },
23
26
  },
24
27
  thumbImg: { strategy: 'auto' },
25
28
  gropeStrategy: 'all-in-all',
26
- schemeOptions: ['Text Filter', 'Duration Filter', 'Badge', 'Advanced'],
29
+ customDataFilterFns: [
30
+ { qualityLow: (e, state) => !!state.qualityLow && e.quality !== '' },
31
+ { qualityHD: (e, state) => !!state.qualityHD && e.quality !== 'HD' },
32
+ { quality4k: (e, state) => !!state.quality4k && e.quality !== '4K' },
33
+ ],
34
+ schemeOptions: [
35
+ 'Title Filter',
36
+ 'Duration Filter',
37
+ {
38
+ title: 'Quality Filter',
39
+ content: [
40
+ { qualityLow: false, label: 'Low' },
41
+ { qualityHD: false, label: 'HD' },
42
+ { quality4k: false, label: '4K' },
43
+ ],
44
+ },
45
+ 'Sort By',
46
+ 'Badge',
47
+ 'Advanced',
48
+ ],
27
49
  });
50
+
51
+ console.log(rules.dataManager.data.values().toArray());