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.
- package/dist/core/pervertmonkey.core.es.d.ts +90 -36
- package/dist/core/pervertmonkey.core.es.js +258 -129
- package/dist/core/pervertmonkey.core.es.js.map +1 -1
- package/dist/core/pervertmonkey.core.umd.js +258 -129
- package/dist/core/pervertmonkey.core.umd.js.map +1 -1
- package/dist/userscripts/3hentai.user.js +4 -5
- package/dist/userscripts/camgirlfinder.user.js +2 -2
- package/dist/userscripts/camwhores.user.js +7 -16
- package/dist/userscripts/e-hentai.user.js +8 -8
- package/dist/userscripts/ebalka.user.js +18 -10
- package/dist/userscripts/eporner.user.js +24 -41
- package/dist/userscripts/erome.user.js +13 -16
- package/dist/userscripts/eroprofile.user.js +5 -14
- package/dist/userscripts/javhdporn.user.js +6 -5
- package/dist/userscripts/missav.user.js +10 -4
- package/dist/userscripts/motherless.user.js +13 -6
- package/dist/userscripts/namethatporn.user.js +10 -16
- package/dist/userscripts/nhentai.user.js +5 -13
- package/dist/userscripts/obmenvsem.user.js +11 -4
- package/dist/userscripts/pornhub.user.js +14 -6
- package/dist/userscripts/spankbang.user.js +28 -7
- package/dist/userscripts/thisvid.user.js +15 -33
- package/dist/userscripts/xhamster.user.js +13 -18
- package/dist/userscripts/xvideos.user.js +33 -5
- package/package.json +1 -1
- package/src/core/data-handler/data-filter-fn-defaults.ts +52 -0
- package/src/core/data-handler/data-filter-fn.ts +62 -0
- package/src/core/data-handler/data-filter.ts +31 -103
- package/src/core/data-handler/data-manager.ts +91 -28
- package/src/core/jabroni-config/default-scheme.ts +54 -5
- package/src/core/jabroni-config/index.ts +1 -0
- package/src/core/jabroni-config/jabroni-gui-controller.ts +1 -1
- package/src/core/jabroni-config/scheme-selectors-mapping.ts +12 -0
- package/src/core/parsers/thumb-data-parser.ts +15 -19
- package/src/core/rules/index.ts +15 -9
- package/src/userscripts/index.ts +1 -1
- package/src/userscripts/scripts/3hentai.ts +3 -4
- package/src/userscripts/scripts/camgirlfinder.ts +1 -1
- package/src/userscripts/scripts/camwhores.ts +5 -14
- package/src/userscripts/scripts/e-hentai.ts +12 -12
- package/src/userscripts/scripts/ebalka.ts +16 -8
- package/src/userscripts/scripts/eporner.ts +23 -39
- package/src/userscripts/scripts/erome.ts +13 -17
- package/src/userscripts/scripts/eroprofile.ts +4 -12
- package/src/userscripts/scripts/javhdporn.ts +7 -8
- package/src/userscripts/scripts/missav.ts +10 -4
- package/src/userscripts/scripts/motherless.ts +13 -7
- package/src/userscripts/scripts/namethatporn.ts +10 -17
- package/src/userscripts/scripts/nhentai.ts +6 -13
- package/src/userscripts/scripts/obmenvsem.ts +14 -4
- package/src/userscripts/scripts/pornhub.ts +13 -4
- package/src/userscripts/scripts/spankbang.ts +29 -5
- package/src/userscripts/scripts/thisvid.ts +16 -31
- package/src/userscripts/scripts/xhamster.ts +13 -18
- package/src/userscripts/scripts/xvideos.ts +32 -3
- package/src/utils/dom/dom-observers.ts +3 -3
- package/src/utils/dom/index.ts +1 -1
- package/src/utils/parsers/index.ts +5 -2
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
objectToFormData,
|
|
14
14
|
parseCssUrl,
|
|
15
15
|
parseHtml,
|
|
16
|
+
querySelectorLast,
|
|
16
17
|
querySelectorLastNumber,
|
|
17
18
|
range,
|
|
18
19
|
replaceElementTag,
|
|
@@ -21,9 +22,9 @@ import {
|
|
|
21
22
|
|
|
22
23
|
export const meta: MonkeyUserScript = {
|
|
23
24
|
name: 'ThisVid.com Improved',
|
|
24
|
-
version: '8.0.
|
|
25
|
+
version: '8.0.7',
|
|
25
26
|
description:
|
|
26
|
-
'Infinite scroll [optional]. Preview for private videos. Filter
|
|
27
|
+
'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
28
|
match: ['https://*.thisvid.com/*'],
|
|
28
29
|
};
|
|
29
30
|
|
|
@@ -88,36 +89,18 @@ const defaultRulesConfig: RulesConfig = {
|
|
|
88
89
|
return { img, imgSrc };
|
|
89
90
|
},
|
|
90
91
|
},
|
|
91
|
-
|
|
92
|
+
containerSelector: () =>
|
|
93
|
+
(querySelectorLast(
|
|
94
|
+
document,
|
|
95
|
+
'div:has(> .tumbpu[title]):not(.thumbs-photo), div:has(> .thumb-holder)',
|
|
96
|
+
) as HTMLElement) || document.querySelector<HTMLElement>('.thumbs-items'),
|
|
92
97
|
animatePreview,
|
|
93
|
-
customDataSelectorFns: [
|
|
94
|
-
'filterInclude',
|
|
95
|
-
'filterExclude',
|
|
96
|
-
'filterDuration',
|
|
97
|
-
{
|
|
98
|
-
filterPrivate: (el, state) => (state.filterPrivate && el.private) as boolean,
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
filterPublic: (el, state) => (state.filterPublic && !el.private) as boolean,
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
filterHD: (el, state) => (state.filterHD && !el.hd) as boolean,
|
|
105
|
-
},
|
|
106
|
-
{
|
|
107
|
-
filterNonHD: (el, state) => (state.filterNonHD && el.hd) as boolean,
|
|
108
|
-
},
|
|
109
|
-
],
|
|
110
98
|
schemeOptions: [
|
|
111
|
-
'
|
|
99
|
+
'Title Filter',
|
|
112
100
|
'Duration Filter',
|
|
113
101
|
'Privacy Filter',
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
content: [
|
|
117
|
-
{ filterHD: false, label: 'hd' },
|
|
118
|
-
{ filterNonHD: false, label: 'non-hd' },
|
|
119
|
-
],
|
|
120
|
-
},
|
|
102
|
+
'HD Filter',
|
|
103
|
+
'Sort By',
|
|
121
104
|
'Badge',
|
|
122
105
|
{
|
|
123
106
|
title: 'Advanced',
|
|
@@ -192,8 +175,8 @@ async function getMemberFriends(
|
|
|
192
175
|
return g();
|
|
193
176
|
}
|
|
194
177
|
|
|
195
|
-
function getMembers(
|
|
196
|
-
const friendsList =
|
|
178
|
+
function getMembers(e: HTMLElement) {
|
|
179
|
+
const friendsList = e.querySelector('#list_members_friends_items') || e;
|
|
197
180
|
return Array.from(friendsList.querySelectorAll<HTMLAnchorElement>('.tumbpu') || [])
|
|
198
181
|
.map((e) => e.href.match(/\d+/)?.[0] as string)
|
|
199
182
|
.filter((_) => _);
|
|
@@ -398,6 +381,8 @@ function animatePreview(_: HTMLElement) {
|
|
|
398
381
|
(target) => {
|
|
399
382
|
const img = target.querySelector('img') as HTMLImageElement;
|
|
400
383
|
const orig = img.getAttribute('src') as string;
|
|
384
|
+
if (!orig) return;
|
|
385
|
+
|
|
401
386
|
tick.start(
|
|
402
387
|
() => iteratePreviewFrames(img),
|
|
403
388
|
() => {
|
|
@@ -610,7 +595,7 @@ async function createPrivateFeed() {
|
|
|
610
595
|
paginationSelector: '.footer',
|
|
611
596
|
},
|
|
612
597
|
schemeOptions: [
|
|
613
|
-
'
|
|
598
|
+
'Title Filter',
|
|
614
599
|
'Duration Filter',
|
|
615
600
|
'Privacy Filter',
|
|
616
601
|
'Badge',
|
|
@@ -11,12 +11,12 @@ import {
|
|
|
11
11
|
waitForElementToAppear,
|
|
12
12
|
watchElementChildrenCount,
|
|
13
13
|
} from '../../utils';
|
|
14
|
-
import { findSelfOrChild } from '../../utils/dom';
|
|
15
14
|
|
|
16
15
|
export const meta: MonkeyUserScript = {
|
|
17
16
|
name: 'Xhamster Improved',
|
|
18
|
-
version: '5.0.
|
|
19
|
-
description:
|
|
17
|
+
version: '5.0.8',
|
|
18
|
+
description:
|
|
19
|
+
'Infinite scroll [optional], Filter by Title, Duration and Watched/Unwatched. Sort by Duration and Views',
|
|
20
20
|
match: ['https://*.xhamster.com/*', 'https://*.xhamster.*/*'],
|
|
21
21
|
exclude: 'https://*.xhamster.com/embed*',
|
|
22
22
|
grant: ['GM_addElement', 'GM_addStyle', 'unsafeWindow'],
|
|
@@ -93,10 +93,8 @@ const rules = new Rules({
|
|
|
93
93
|
selectors: {
|
|
94
94
|
title: '.video-thumb-info__name,.video-thumb-info>a',
|
|
95
95
|
duration: '.thumb-image-container__duration',
|
|
96
|
-
watched: {
|
|
97
|
-
|
|
98
|
-
selector: '[data-role="video-watched',
|
|
99
|
-
},
|
|
96
|
+
watched: { selector: '[data-role="video-watched', type: 'boolean' },
|
|
97
|
+
views: { selector: '.video-thumb-views', type: 'float' },
|
|
100
98
|
},
|
|
101
99
|
},
|
|
102
100
|
thumbImg: {
|
|
@@ -104,20 +102,16 @@ const rules = new Rules({
|
|
|
104
102
|
remove: '[loading]',
|
|
105
103
|
},
|
|
106
104
|
gropeStrategy: 'all-in-all',
|
|
107
|
-
|
|
108
|
-
'filterInclude',
|
|
109
|
-
'filterExclude',
|
|
110
|
-
'filterDuration',
|
|
105
|
+
customDataFilterFns: [
|
|
111
106
|
{
|
|
112
|
-
filterWatched: (
|
|
107
|
+
filterWatched: (e, state) => !!(state.filterWatched && e.watched),
|
|
113
108
|
},
|
|
114
109
|
{
|
|
115
|
-
filterUnwatched: (
|
|
110
|
+
filterUnwatched: (e, state) => !!(state.filterUnwatched && !e.watched),
|
|
116
111
|
},
|
|
117
112
|
],
|
|
118
113
|
schemeOptions: [
|
|
119
|
-
'
|
|
120
|
-
'Badge',
|
|
114
|
+
'Title Filter',
|
|
121
115
|
{
|
|
122
116
|
title: 'Filter Watched',
|
|
123
117
|
content: [
|
|
@@ -125,7 +119,9 @@ const rules = new Rules({
|
|
|
125
119
|
{ filterUnwatched: false, label: 'unwatched' },
|
|
126
120
|
],
|
|
127
121
|
},
|
|
122
|
+
'Sort By',
|
|
128
123
|
'Duration Filter',
|
|
124
|
+
'Badge',
|
|
129
125
|
'Advanced',
|
|
130
126
|
],
|
|
131
127
|
animatePreview,
|
|
@@ -156,18 +152,17 @@ function animatePreview() {
|
|
|
156
152
|
const videoSrc = e
|
|
157
153
|
.querySelector('[data-previewvideo]')
|
|
158
154
|
?.getAttribute('data-previewvideo') as string;
|
|
159
|
-
console.log(container, videoSrc);
|
|
160
155
|
return createPreviewVideoElement(videoSrc, container);
|
|
161
156
|
});
|
|
162
157
|
}
|
|
163
158
|
|
|
164
159
|
function expandMoreVideoPage() {
|
|
165
160
|
watchElementChildrenCount(rules.container, () => setTimeout(rules.gropeInit, 1800));
|
|
166
|
-
waitForElementToAppear(document.body, 'button[data-role="show-more-next"]', (
|
|
161
|
+
waitForElementToAppear(document.body, 'button[data-role="show-more-next"]', (e) => {
|
|
167
162
|
const observer = new Observer((target) => {
|
|
168
163
|
(target as HTMLButtonElement).click();
|
|
169
164
|
});
|
|
170
|
-
observer.observe(
|
|
165
|
+
observer.observe(e);
|
|
171
166
|
});
|
|
172
167
|
}
|
|
173
168
|
|
|
@@ -5,8 +5,9 @@ import { exterminateVideo, OnHover, parseHtml } from '../../utils';
|
|
|
5
5
|
|
|
6
6
|
export const meta: MonkeyUserScript = {
|
|
7
7
|
name: 'XVideos Improved',
|
|
8
|
-
version: '4.0.
|
|
9
|
-
description:
|
|
8
|
+
version: '4.0.8',
|
|
9
|
+
description:
|
|
10
|
+
'Infinite scroll [optional], Filter by Title, Uploader and Duration. Sort by Duration and Views.',
|
|
10
11
|
match: 'https://*.xvideos.com/*',
|
|
11
12
|
};
|
|
12
13
|
|
|
@@ -24,6 +25,8 @@ const rules = new Rules({
|
|
|
24
25
|
title: '[class*=title]',
|
|
25
26
|
uploader: '[class*=name]',
|
|
26
27
|
duration: '[class*=duration]',
|
|
28
|
+
views: { selector: '.metadata a ~ span', type: 'float' },
|
|
29
|
+
quality: { selector: '.video-hd-mark', type: 'string' },
|
|
27
30
|
},
|
|
28
31
|
callback: (thumb) => {
|
|
29
32
|
setTimeout(() => {
|
|
@@ -32,7 +35,33 @@ const rules = new Rules({
|
|
|
32
35
|
}, 200);
|
|
33
36
|
},
|
|
34
37
|
},
|
|
35
|
-
|
|
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' },
|
|
45
|
+
],
|
|
46
|
+
schemeOptions: [
|
|
47
|
+
'Title Filter',
|
|
48
|
+
'Uploader Filter',
|
|
49
|
+
'Duration Filter',
|
|
50
|
+
{
|
|
51
|
+
title: 'Quality Filter',
|
|
52
|
+
content: [
|
|
53
|
+
{ qualityLow: false, label: 'Low' },
|
|
54
|
+
{ quality360: false, label: '360p' },
|
|
55
|
+
{ quality720: false, label: '720p' },
|
|
56
|
+
{ quality1080: false, label: '1080p' },
|
|
57
|
+
{ quality1440: false, label: '1440p' },
|
|
58
|
+
{ quality4k: false, label: '4k' },
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
'Sort By',
|
|
62
|
+
'Badge',
|
|
63
|
+
'Advanced',
|
|
64
|
+
],
|
|
36
65
|
animatePreview,
|
|
37
66
|
});
|
|
38
67
|
|
|
@@ -4,10 +4,10 @@ export function waitForElementToAppear(
|
|
|
4
4
|
callback: (el: Element) => void,
|
|
5
5
|
) {
|
|
6
6
|
const observer = new MutationObserver((_mutations) => {
|
|
7
|
-
const
|
|
8
|
-
if (
|
|
7
|
+
const e = parent.querySelector(selector);
|
|
8
|
+
if (e) {
|
|
9
9
|
observer.disconnect();
|
|
10
|
-
callback(
|
|
10
|
+
callback(e);
|
|
11
11
|
}
|
|
12
12
|
});
|
|
13
13
|
|
package/src/utils/dom/index.ts
CHANGED
|
@@ -80,7 +80,7 @@ export function removeClassesAndDataAttributes(
|
|
|
80
80
|
|
|
81
81
|
export function getCommonParents(elements: HTMLCollection | HTMLElement[]): HTMLElement[] {
|
|
82
82
|
const parents = Array.from(elements)
|
|
83
|
-
.map((
|
|
83
|
+
.map((e) => e.parentElement)
|
|
84
84
|
.filter((parent): parent is HTMLElement => parent !== null);
|
|
85
85
|
|
|
86
86
|
return [...new Set(parents)];
|
|
@@ -11,11 +11,14 @@ export function parseIntegerOr(n: string | number, or: number): number {
|
|
|
11
11
|
|
|
12
12
|
export function parseNumberWithLetter(str: string): number {
|
|
13
13
|
const multipliers = { k: 1e3, m: 1e6 } as const;
|
|
14
|
-
const match = str.trim().match(
|
|
14
|
+
const match = str.trim().match(/([\d., ]+)(\w)?/);
|
|
15
15
|
|
|
16
16
|
if (!match) return 0;
|
|
17
17
|
|
|
18
|
-
const
|
|
18
|
+
const s1 = match[1].replace(/,/g, '.').replace(/[ ]/g, '');
|
|
19
|
+
const s2 = s1.split('.').filter(Boolean).length < 3 ? s1 : s1.replace('.', '');
|
|
20
|
+
|
|
21
|
+
const num = parseFloat(s2);
|
|
19
22
|
const suffix = match[2]?.toLowerCase() as keyof typeof multipliers;
|
|
20
23
|
|
|
21
24
|
if (suffix && suffix in multipliers) {
|