pervert-monkey 1.0.25 → 1.0.26
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/README.md +5 -2
- package/dist/core/pervertmonkey.core.es.d.ts +2 -541
- package/dist/core/pervertmonkey.core.es.js +8001 -9281
- package/dist/core/pervertmonkey.core.es.js.map +1 -1
- package/dist/core/pervertmonkey.core.umd.js +8829 -10051
- package/dist/core/pervertmonkey.core.umd.js.map +1 -1
- package/dist/userscripts/3hentai.user.js +40 -46
- package/dist/userscripts/camgirlfinder.user.js +56 -49
- package/dist/userscripts/camwhores.user.js +286 -343
- package/dist/userscripts/e-hentai.user.js +54 -57
- package/dist/userscripts/ebalka.user.js +52 -55
- package/dist/userscripts/eporner.user.js +76 -68
- package/dist/userscripts/erome.user.js +79 -84
- package/dist/userscripts/eroprofile.user.js +28 -29
- package/dist/userscripts/javhdporn.user.js +28 -22
- package/dist/userscripts/missav.user.js +22 -23
- package/dist/userscripts/motherless.user.js +141 -152
- package/dist/userscripts/namethatporn.user.js +49 -58
- package/dist/userscripts/nhentai.user.js +104 -99
- package/dist/userscripts/obmenvsem.user.js +61 -69
- package/dist/userscripts/pornhub.user.js +50 -47
- package/dist/userscripts/simpcity.user.js +26 -23
- package/dist/userscripts/socialmediagirls.user.js +26 -22
- package/dist/userscripts/spankbang.user.js +62 -44
- package/dist/userscripts/thisvid.user.js +1269 -1366
- package/dist/userscripts/xhamster.user.js +119 -132
- package/dist/userscripts/xvideos.user.js +115 -91
- package/package.json +10 -6
- package/src/core/data-handler/data-filter.ts +4 -3
- package/src/core/parsers/pagination-parser/index.ts +0 -4
- package/src/core/parsers/pagination-parser/pagination-strategies/PaginationStrategyPathnameParams.ts +36 -1
- package/src/userscripts/index.ts +1 -1
- package/src/userscripts/meta.json +1 -1
- package/src/userscripts/scripts/3hentai.ts +1 -1
- package/src/userscripts/scripts/camgirlfinder.ts +1 -1
- package/src/userscripts/scripts/camwhores.ts +2 -2
- package/src/userscripts/scripts/e-hentai.ts +1 -1
- package/src/userscripts/scripts/ebalka.ts +1 -1
- package/src/userscripts/scripts/eporner.ts +41 -15
- package/src/userscripts/scripts/erome.ts +1 -1
- package/src/userscripts/scripts/eroprofile.ts +6 -6
- package/src/userscripts/scripts/javhdporn.ts +1 -1
- package/src/userscripts/scripts/missav.ts +1 -1
- package/src/userscripts/scripts/motherless.ts +28 -19
- package/src/userscripts/scripts/namethatporn.ts +1 -1
- package/src/userscripts/scripts/nhentai.ts +1 -1
- package/src/userscripts/scripts/obmenvsem.ts +1 -1
- package/src/userscripts/scripts/pornhub.ts +1 -1
- package/src/userscripts/scripts/simpcity.ts +1 -1
- package/src/userscripts/scripts/{socialmediagirls copy.ts → socialmediagirls.ts} +1 -1
- package/src/userscripts/scripts/spankbang.ts +20 -4
- package/src/userscripts/scripts/thisvid.ts +8 -21
- package/src/userscripts/scripts/xhamster.ts +11 -3
- package/src/userscripts/scripts/xvideos.ts +26 -7
- package/src/utils/fetch/index.ts +2 -0
- package/src/utils/objects/memoize.ts +1 -9
- package/dist/test/test.user.js +0 -10301
- package/dist/userscripts/socialmediagirls copy.user.js +0 -41
package/src/userscripts/index.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import './scripts/
|
|
1
|
+
import './scripts/eporner';
|
|
@@ -6,5 +6,5 @@
|
|
|
6
6
|
"grant": ["unsafeWindow", "GM_addStyle"],
|
|
7
7
|
"homepageURL": "https://sleazyfork.org/en/users/1253342-smartacephale",
|
|
8
8
|
"supportURL": "https://github.com/smartacephale/sleazy-fork/issues",
|
|
9
|
-
"source": "https://github.com/smartacephale"
|
|
9
|
+
"source": "https://github.com/smartacephale/sleazy-fork"
|
|
10
10
|
}
|
|
@@ -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.
|
|
7
|
+
version: '1.0.20',
|
|
8
8
|
description: 'Infinite scroll [optional], Filter by Title, thumb preview',
|
|
9
9
|
match: 'https://*.3hentai.net/*',
|
|
10
10
|
};
|
|
@@ -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.
|
|
5
|
+
version: '1.6.19',
|
|
6
6
|
description:
|
|
7
7
|
'Adds model links for CamWhores, webcamrecordings, recu.me, camvideos, privat-zapisi',
|
|
8
8
|
match: ['https://camgirlfinder.net/*'],
|
|
@@ -17,10 +17,10 @@ import {
|
|
|
17
17
|
|
|
18
18
|
export const meta: MonkeyUserScript = {
|
|
19
19
|
name: 'CamWhores PervertMonkey',
|
|
20
|
-
version: '3.0.
|
|
20
|
+
version: '3.0.24',
|
|
21
21
|
description:
|
|
22
22
|
'Infinite scroll [optional]. Filter by Title, Duration and Private/Public. Sort by Duration and Views. Mass friend request button. Download button',
|
|
23
|
-
match: ['https://*.camwhores.tv', 'https://*.camwhores.*/*'],
|
|
23
|
+
match: ['https://*.camwhores.tv/*', 'https://*.camwhores.*/*'],
|
|
24
24
|
exclude: 'https://*.camwhores.tv/*mode=async*',
|
|
25
25
|
};
|
|
26
26
|
|
|
@@ -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.
|
|
7
|
+
version: '1.0.20',
|
|
8
8
|
description: 'Infinite scroll [optional], Filter by Title',
|
|
9
9
|
match: ['https://*.e-hentai.org/*'],
|
|
10
10
|
};
|
|
@@ -4,7 +4,7 @@ import { downloader, exterminateVideo, OnHover, parseHtml } from '../../utils';
|
|
|
4
4
|
|
|
5
5
|
export const meta: MonkeyUserScript = {
|
|
6
6
|
name: 'Ebalka PervertMonkey',
|
|
7
|
-
version: '3.0.
|
|
7
|
+
version: '3.0.21',
|
|
8
8
|
description:
|
|
9
9
|
'Infinite scroll [optional], Filter by Title and Duration, Sort by Duration, Download button.',
|
|
10
10
|
match: [
|
|
@@ -5,22 +5,24 @@ import { OnHover } from '../../utils';
|
|
|
5
5
|
|
|
6
6
|
export const meta: MonkeyUserScript = {
|
|
7
7
|
name: 'Eporner PervertMonkey',
|
|
8
|
-
version: '2.
|
|
8
|
+
version: '2.1.3',
|
|
9
9
|
description:
|
|
10
10
|
'Infinite scroll [optional], Filter by Title, Uploader, Duration and HD, Sort by Views and Duration',
|
|
11
11
|
match: ['https://*.eporner.com/*', 'https://*.eporner.*/*'],
|
|
12
|
+
supportURL: 'https://sleazyfork.org/en/scripts/552559-eporner-pervertmonkey/feedback',
|
|
12
13
|
};
|
|
13
14
|
|
|
14
|
-
const show_video_prev = (unsafeWindow as any).show_video_prev;
|
|
15
|
-
|
|
16
15
|
const rules = new Rules({
|
|
17
16
|
paginationStrategyOptions: {
|
|
18
17
|
paginationSelector: '.numlist2',
|
|
18
|
+
// pathnameSelector: /\/(\d+)\/?$/,
|
|
19
|
+
// pathnameSelector: /\/(\d+)\/([\w-]+\/)?$/
|
|
20
|
+
overwritePaginationLast: (n, _) => (n === 9 ? 9999 : n),
|
|
19
21
|
},
|
|
20
22
|
thumbs: { selector: 'div[id^=vf][data-id]' },
|
|
21
23
|
thumb: {
|
|
22
24
|
selectors: {
|
|
23
|
-
title: 'a',
|
|
25
|
+
title: 'a[href*=video-]',
|
|
24
26
|
uploader: '[title="Uploader"]',
|
|
25
27
|
duration: '[title="Duration"]',
|
|
26
28
|
views: { selector: '[title="Views"]', type: 'float' },
|
|
@@ -33,12 +35,38 @@ const rules = new Rules({
|
|
|
33
35
|
},
|
|
34
36
|
containerSelectorLast: '#vidresults',
|
|
35
37
|
customDataFilterFns: [
|
|
36
|
-
{
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
{
|
|
39
|
+
qualityFilter: {
|
|
40
|
+
handle(el, state) {
|
|
41
|
+
const hasAnyQualitySelected =
|
|
42
|
+
state.quality360 ||
|
|
43
|
+
state.quality480 ||
|
|
44
|
+
state.quality720 ||
|
|
45
|
+
state.quality1080 ||
|
|
46
|
+
state.quality2k ||
|
|
47
|
+
state.quality4k;
|
|
48
|
+
|
|
49
|
+
if (!hasAnyQualitySelected) return false;
|
|
50
|
+
|
|
51
|
+
return !(
|
|
52
|
+
(state.quality360 && el.quality === 360) ||
|
|
53
|
+
(state.quality480 && el.quality === 480) ||
|
|
54
|
+
(state.quality720 && el.quality === 720) ||
|
|
55
|
+
(state.quality1080 && el.quality === 1080) ||
|
|
56
|
+
(state.quality2k && el.quality === 2) ||
|
|
57
|
+
(state.quality4k && el.quality === 4)
|
|
58
|
+
);
|
|
59
|
+
},
|
|
60
|
+
deps: [
|
|
61
|
+
'quality360',
|
|
62
|
+
'quality480',
|
|
63
|
+
'quality720',
|
|
64
|
+
'quality1080',
|
|
65
|
+
'quality2k',
|
|
66
|
+
'quality4k',
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
},
|
|
42
70
|
],
|
|
43
71
|
schemeOptions: [
|
|
44
72
|
'Title Filter',
|
|
@@ -59,15 +87,13 @@ const rules = new Rules({
|
|
|
59
87
|
'Badge',
|
|
60
88
|
'Advanced',
|
|
61
89
|
],
|
|
62
|
-
gropeStrategy: 'all-in-
|
|
90
|
+
gropeStrategy: 'all-in-one',
|
|
63
91
|
animatePreview,
|
|
64
92
|
});
|
|
65
93
|
|
|
66
94
|
function animatePreview(doc: HTMLElement) {
|
|
67
95
|
OnHover.create(doc, 'div[id^=vf][data-id]', (e) => {
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
const id = thumb?.getAttribute('data-id');
|
|
71
|
-
show_video_prev(id);
|
|
96
|
+
const thumb = e.closest('[data-id]');
|
|
97
|
+
(unsafeWindow as any).EP.thumbs.preview.start(thumb);
|
|
72
98
|
});
|
|
73
99
|
}
|
|
@@ -4,7 +4,7 @@ import { Rules } from '../../core';
|
|
|
4
4
|
|
|
5
5
|
export const meta: MonkeyUserScript = {
|
|
6
6
|
name: 'Erome PervertMonkey',
|
|
7
|
-
version: '5.0.
|
|
7
|
+
version: '5.0.21',
|
|
8
8
|
description:
|
|
9
9
|
'Infinite scroll [optional], Filter by Title, Uploader and Video/Photo albums, Sort by Views. Show/Hide Photos in album. Remove disclaimer. Restore Search Bar',
|
|
10
10
|
match: ['*://*.erome.com/*'],
|
|
@@ -3,7 +3,7 @@ import { Rules } from '../../core';
|
|
|
3
3
|
|
|
4
4
|
export const meta: MonkeyUserScript = {
|
|
5
5
|
name: 'Eroprofile PervertMonkey',
|
|
6
|
-
version: '2.0.
|
|
6
|
+
version: '2.0.21',
|
|
7
7
|
description: 'Infinite scroll [optional], Filter by Title and Duration, Sort by Duration',
|
|
8
8
|
match: ['https://*.eroprofile.com/*'],
|
|
9
9
|
};
|
|
@@ -12,17 +12,17 @@ document.querySelector('.videoGrid')?.after(document.querySelector('.clB') as HT
|
|
|
12
12
|
|
|
13
13
|
const rules = new Rules({
|
|
14
14
|
paginationStrategyOptions: {
|
|
15
|
-
paginationSelector: '.
|
|
15
|
+
paginationSelector: '.page-nav',
|
|
16
16
|
searchParamSelector: 'pnum',
|
|
17
17
|
},
|
|
18
|
-
thumbs: { selector: '.video' },
|
|
18
|
+
thumbs: { selector: '.grid-tile-video' },
|
|
19
19
|
thumb: {
|
|
20
20
|
selectors: {
|
|
21
|
-
title: '
|
|
22
|
-
duration: '.
|
|
21
|
+
title: '.title',
|
|
22
|
+
duration: '.duration',
|
|
23
23
|
},
|
|
24
24
|
},
|
|
25
|
-
containerSelector: '
|
|
25
|
+
containerSelector: 'div:has(>.grid-tile-video)',
|
|
26
26
|
schemeOptions: [
|
|
27
27
|
'Title Filter',
|
|
28
28
|
'Duration Filter',
|
|
@@ -3,7 +3,7 @@ import { Rules } from '../../core';
|
|
|
3
3
|
|
|
4
4
|
export const meta: MonkeyUserScript = {
|
|
5
5
|
name: 'Javhdporn PervertMonkey',
|
|
6
|
-
version: '3.0.
|
|
6
|
+
version: '3.0.20',
|
|
7
7
|
description:
|
|
8
8
|
'Infinite scroll [optional], Filter by Title and Duration, Sort By Duration and Views',
|
|
9
9
|
match: ['https://*.javhdporn.net/*', 'https://*.javhdporn.*/*'],
|
|
@@ -3,7 +3,7 @@ import { Rules } from '../../core';
|
|
|
3
3
|
|
|
4
4
|
export const meta: MonkeyUserScript = {
|
|
5
5
|
name: 'Missav PervertMonkey',
|
|
6
|
-
version: '3.0.
|
|
6
|
+
version: '3.0.19',
|
|
7
7
|
description: 'Infinite scroll [optional], Filter by Title and Duration, Sort by Duration',
|
|
8
8
|
match: [
|
|
9
9
|
'https://*.missav123.com/*',
|
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
import type { MonkeyUserScript } from 'vite-plugin-monkey';
|
|
2
2
|
import { GM_addElement, GM_addStyle, unsafeWindow } from '$';
|
|
3
3
|
import { Rules } from '../../core';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
fetchWith,
|
|
6
|
+
OnHover,
|
|
7
|
+
replaceElementTag,
|
|
8
|
+
Tick,
|
|
9
|
+
waitForElementToAppear,
|
|
10
|
+
} from '../../utils';
|
|
5
11
|
|
|
6
12
|
export const meta: MonkeyUserScript = {
|
|
7
13
|
name: 'Motherless PervertMonkey',
|
|
8
|
-
version: '5.0.
|
|
14
|
+
version: '5.0.25',
|
|
9
15
|
description:
|
|
10
16
|
'Infinite scroll [optional], Filter by Title, Uploader and Duration, Sort by Duration and Views',
|
|
11
|
-
match: ['https://motherless.
|
|
17
|
+
match: ['https://motherless.xxx/*'],
|
|
12
18
|
grant: ['GM_addElement', 'GM_addStyle', 'unsafeWindow'],
|
|
13
19
|
};
|
|
14
20
|
|
|
@@ -16,7 +22,7 @@ export const meta: MonkeyUserScript = {
|
|
|
16
22
|
const $ = (unsafeWindow as any).$;
|
|
17
23
|
|
|
18
24
|
const rules = new Rules({
|
|
19
|
-
|
|
25
|
+
containerSelector: '.content-inner',
|
|
20
26
|
thumbs: { selector: '.thumb-container, .mobile-thumb' },
|
|
21
27
|
thumb: {
|
|
22
28
|
selectors: {
|
|
@@ -142,25 +148,28 @@ async function desktopAddMobGalleries() {
|
|
|
142
148
|
const galleries = document.querySelector('.media-related-galleries');
|
|
143
149
|
if (!galleries) return;
|
|
144
150
|
|
|
151
|
+
await new Promise((resolve) => {
|
|
152
|
+
waitForElementToAppear(document, '.thumb-container.gallery-container', resolve);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
const mobDom = await fetchWith<HTMLElement>(window.location.href, {
|
|
156
|
+
type: 'html',
|
|
157
|
+
mobile: true,
|
|
158
|
+
});
|
|
159
|
+
const mobGalleries = mobDom.querySelectorAll<HTMLElement>('.ml-gallery-thumb');
|
|
160
|
+
|
|
145
161
|
const galleriesContainer = galleries.querySelector('.content-inner') as HTMLElement;
|
|
146
|
-
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
'.
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
galleriesContainer.append(mobileGalleryToDesktop(x));
|
|
155
|
-
}
|
|
162
|
+
|
|
163
|
+
for (const x of mobGalleries.values()) {
|
|
164
|
+
const mobGallery = mobileGalleryToDesktop(x);
|
|
165
|
+
const mobGalleryId = (mobGallery.querySelector('a') as HTMLAnchorElement).href
|
|
166
|
+
.split('/')
|
|
167
|
+
.at(-1);
|
|
168
|
+
if (galleriesContainer.querySelector(`a[href*=${mobGalleryId}]`)) continue;
|
|
169
|
+
galleriesContainer.append(mobGallery);
|
|
156
170
|
}
|
|
157
171
|
}
|
|
158
172
|
|
|
159
|
-
const overwrite1 = (x: string) => `@media only screen and (max-width: 1280px) {
|
|
160
|
-
#categories-page.inner ${x} }`;
|
|
161
|
-
|
|
162
|
-
rules.dataManager.dataFilter.createCssFilters(overwrite1);
|
|
163
|
-
|
|
164
173
|
GM_addStyle(`
|
|
165
174
|
.img-container, .desktop-thumb { min-height: 150px; max-height: 150px; }
|
|
166
175
|
|
|
@@ -4,7 +4,7 @@ import { Rules } from '../../core';
|
|
|
4
4
|
|
|
5
5
|
export const meta: MonkeyUserScript = {
|
|
6
6
|
name: 'NameThatPorn PervertMonkey',
|
|
7
|
-
version: '3.0.
|
|
7
|
+
version: '3.0.20',
|
|
8
8
|
description: 'Infinite scroll [optional], Filter by Title, Uploader and Solved/Unsolved',
|
|
9
9
|
match: ['https://namethatporn.com/*'],
|
|
10
10
|
};
|
|
@@ -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.
|
|
7
|
+
version: '4.0.20',
|
|
8
8
|
description: 'Infinite scroll [optional], Filter by Title',
|
|
9
9
|
match: ['https://*.nhentai.net/*', 'https://*.nhentai.*/*'],
|
|
10
10
|
};
|
|
@@ -5,7 +5,7 @@ import { fetchHtml, parseUrl } from '../../utils';
|
|
|
5
5
|
|
|
6
6
|
export const meta: MonkeyUserScript = {
|
|
7
7
|
name: 'Obmenvsem PervertMonkey',
|
|
8
|
-
version: '1.0.
|
|
8
|
+
version: '1.0.22',
|
|
9
9
|
description: 'Infinite scroll [optional], Filter by Title and Duration, Sort by Duration',
|
|
10
10
|
match: [
|
|
11
11
|
'https://*.obmenvsem.com/*',
|
|
@@ -3,7 +3,7 @@ import { Rules } from '../../core';
|
|
|
3
3
|
|
|
4
4
|
export const meta: MonkeyUserScript = {
|
|
5
5
|
name: 'PornHub PervertMonkey',
|
|
6
|
-
version: '4.0.
|
|
6
|
+
version: '4.0.20',
|
|
7
7
|
description:
|
|
8
8
|
'Infinite scroll [optional]. Filter by Title, Uploader and Duration. Sort by Duration and Views',
|
|
9
9
|
match: ['https://*.pornhub.com/*'],
|
|
@@ -3,7 +3,7 @@ import { Rules } from '../../core';
|
|
|
3
3
|
|
|
4
4
|
export const meta: MonkeyUserScript = {
|
|
5
5
|
name: 'Simpcity PervertMonkey',
|
|
6
|
-
version: '1.0.
|
|
6
|
+
version: '1.0.2',
|
|
7
7
|
description: 'Infinite scroll [optional], Filter by Title',
|
|
8
8
|
match: 'https://simpcity.cr/threads/*',
|
|
9
9
|
'run-at': 'document-end',
|
|
@@ -3,7 +3,7 @@ import { Rules } from '../../core';
|
|
|
3
3
|
|
|
4
4
|
export const meta: MonkeyUserScript = {
|
|
5
5
|
name: 'Socialmediagirls PervertMonkey',
|
|
6
|
-
version: '1.0.
|
|
6
|
+
version: '1.0.5',
|
|
7
7
|
description: 'Infinite scroll [optional], Filter by Title',
|
|
8
8
|
match: 'https://forums.socialmediagirls.com/threads/*',
|
|
9
9
|
'run-at': 'document-end',
|
|
@@ -3,7 +3,7 @@ import { Rules } from '../../core';
|
|
|
3
3
|
|
|
4
4
|
export const meta: MonkeyUserScript = {
|
|
5
5
|
name: 'SpankBang.com PervertMonkey',
|
|
6
|
-
version: '4.0
|
|
6
|
+
version: '4.1.0',
|
|
7
7
|
description:
|
|
8
8
|
'Infinite scroll [optional]. Filter by Title and Duration. Sort by Duration and Views',
|
|
9
9
|
match: ['https://*.spankbang.com/*', 'https://*.spankbang.*/*'],
|
|
@@ -27,9 +27,25 @@ const rules = new Rules({
|
|
|
27
27
|
thumbImg: { strategy: 'auto' },
|
|
28
28
|
gropeStrategy: 'all-in-all',
|
|
29
29
|
customDataFilterFns: [
|
|
30
|
-
{
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
{
|
|
31
|
+
qualityFilter: {
|
|
32
|
+
handle(el, state) {
|
|
33
|
+
const hasAnyQualitySelected =
|
|
34
|
+
state.qualityLow ||
|
|
35
|
+
state.qualityHD ||
|
|
36
|
+
state.quality4k;
|
|
37
|
+
|
|
38
|
+
if (!hasAnyQualitySelected) return false;
|
|
39
|
+
|
|
40
|
+
return !(
|
|
41
|
+
(state.qualityLow && el.quality === '') ||
|
|
42
|
+
(state.qualityHD && el.quality === 'HD') ||
|
|
43
|
+
(state.quality4k && el.quality === '4K')
|
|
44
|
+
);
|
|
45
|
+
},
|
|
46
|
+
deps: ['qualityLow', 'qualityHD', 'quality4k'],
|
|
47
|
+
},
|
|
48
|
+
},
|
|
33
49
|
],
|
|
34
50
|
schemeOptions: [
|
|
35
51
|
'Title Filter',
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
|
|
22
22
|
export const meta: MonkeyUserScript = {
|
|
23
23
|
name: 'ThisVid.com PervertMonkey',
|
|
24
|
-
version: '8.0.
|
|
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
|
-
},
|
|
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.
|
|
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: {
|
|
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: [
|
|
@@ -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
|
|
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
|
-
{
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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',
|
package/src/utils/fetch/index.ts
CHANGED
|
@@ -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;
|