Skip to content

Commit dbff156

Browse files
committed
Update
1 parent b6d874b commit dbff156

File tree

1 file changed

+94
-70
lines changed

1 file changed

+94
-70
lines changed

improve-adult-experience.js

Lines changed: 94 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// ==UserScript==
22
// @name Improve Adult Experience
3-
// @description Skip intros, set best quality and duration filters by default, make unwanted video previews transparent
4-
// @version 0.8
3+
// @description Skip intros, set best quality and duration filters by default, make unwanted video previews transparent, do fallbacks in case of load failures
4+
// @version 0.9
55
// @downloadURL https://userscripts.codonaft.com/improve-adult-experience.js
66
// @exclude-match https://spankbang.com/*/video/*
77
// @match https://spankbang.com/*
@@ -39,19 +39,27 @@
3939

4040
const simulateClick = (document, node) => {
4141
console.log('simulateClick');
42-
if (!node) return;
43-
const rect = node.getBoundingClientRect();
44-
const clientX = rect.x + rect.width / 2;
45-
const clientY = rect.y + rect.height / 2;
46-
const target = document.elementFromPoint(clientX, clientY);
47-
['mouseover', 'mousemove', 'mousedown', 'mouseup', 'click']
48-
.forEach(i => target.dispatchEvent(new MouseEvent(i, { clientX, clientY, bubbles: true })))
42+
try {
43+
if (!node) return;
44+
const rect = node.getBoundingClientRect();
45+
const clientX = rect.x + rect.width / 2;
46+
const clientY = rect.y + rect.height / 2;
47+
const target = document.elementFromPoint(clientX, clientY);
48+
['mouseover', 'mousemove', 'mousedown', 'mouseup', 'click']
49+
.forEach(i => target.dispatchEvent(new MouseEvent(i, { clientX, clientY, bubbles: true })))
50+
} catch (e) {
51+
console.error(e);
52+
}
4953
};
5054

5155
const subscribeOnChanges = (node, f) => {
52-
f(node);
53-
new MutationObserver(mutations => mutations.forEach(m => m.addedNodes.forEach(f)))
54-
.observe(node, { childList: true, subtree: true });
56+
try {
57+
f(node);
58+
new MutationObserver(mutations => mutations.forEach(m => m.addedNodes.forEach(f)))
59+
.observe(node, { childList: true, subtree: true });
60+
} catch (e) {
61+
console.error(e);
62+
}
5563
};
5664

5765
const pornhub = _ => {
@@ -68,32 +76,40 @@
6876
const isUnwanted = url => currentTime() < loadUnwanted()[videoId(url)];
6977
const videoId = url => url.searchParams.get('viewkey') || url.pathname.split('/').slice(-1)[0];
7078
const watchedVideos = new Set;
71-
const disliked = main => !!main.querySelector('div.active[data-title="I Dislike This"]');
7279

73-
const processEmbedded = (document, similarVideos) => {
74-
const main = document.querySelector('div#main-container') || document.body;
80+
const disliked = body => !!body.querySelector('div.active[data-title="I Dislike This"]');
81+
const premiumRedirect = node => node.href.startsWith('javascript:');
7582

83+
const searchFilterParams = Object.entries({
84+
'min_duration': MIN_DURATION_MINS,
85+
'hd': 1,
86+
'o': 'tr',
87+
't': 'm',
88+
});
89+
90+
const processEmbedded = (document, similarVideos) => {
91+
const body = document.body;
7692
try {
7793
const css = `
7894
div.mgp_topBar { display: none !important; }
7995
div.mgp_thumbnailsGrid { display: none !important; }
8096
img.mgp_pornhub { display: none !important; }
8197
`;
82-
const styleApplied = !![...main.querySelectorAll('style')].find(i => i.innerHTML === css);
98+
const styleApplied = !![...body.querySelectorAll('style')].find(i => i.innerHTML === css);
8399
if (styleApplied) {
84100
console.log('embedded video is already initialized');
85101
return;
86102
}
87103
console.log('applying style');
88104
const style = document.createElement('style');
89105
style.innerHTML = css;
90-
main.appendChild(style);
106+
body.appendChild(style);
91107
} catch (e) {
92108
console.error(e);
93109
}
94110

95111
try {
96-
const requiresRefresh = main.querySelector('div.mgp_errorIcon') && main.querySelector('p')?.textContent.includes('Please refresh the page');
112+
const requiresRefresh = body.querySelector('div.mgp_errorIcon') && body.querySelector('p')?.textContent.includes('Please refresh the page');
97113
if (requiresRefresh) {
98114
console.log('refreshing after error');
99115
window.location.href = window.location.toString();
@@ -102,7 +118,7 @@
102118
console.error(e);
103119
}
104120

105-
const video = main.querySelector('video');
121+
const video = body.querySelector('video');
106122
try {
107123
if (!video) {
108124
console.log('embedding this video is probably not allowed');
@@ -128,17 +144,17 @@
128144
console.error(e);
129145
}
130146

131-
video.addEventListener('loadstart', _ => simulateClick(document, main.querySelector('div.mgp_playIcon')));
147+
video.addEventListener('loadstart', _ => simulateClick(document, body.querySelector('div.mgp_playIcon')));
132148
video.addEventListener('loadedmetadata', _ => {
133-
if (disliked(main)) {
149+
if (disliked(body)) {
134150
setUnwanted(url, Number.MAX_SAFE_INTEGER);
135151
}
136152
video.currentTime = random(video.duration / 4, video.duration / 3);
137153
});
138-
main.querySelector('div.mgp_gridMenu')?.addEventListener('click', _ => setTimeout(_ => {
154+
body.querySelector('div.mgp_gridMenu')?.addEventListener('click', _ => setTimeout(_ => {
139155
if (video.paused) {
140156
console.log('paused on grid menu');
141-
const button = main.querySelector('div.mgp_playIcon');
157+
const button = body.querySelector('div.mgp_playIcon');
142158
simulateClick(document, button);
143159
setTimeout(_ => {
144160
if (video.paused) {
@@ -152,7 +168,7 @@
152168
video.load();
153169
};
154170

155-
const premiumRedirect = node => node.href.startsWith('javascript:');
171+
const body = document.body;
156172

157173
const processPreview = node => {
158174
try {
@@ -182,48 +198,40 @@
182198

183199
const processPlaylistItem = node => {
184200
if (node.nodeType !== 1) return;
185-
186201
if (node.tagName === 'SPAN' && node.classList.contains('duration')) {
187202
processPreview(node);
188203
return;
189204
}
190-
191205
node.childNodes.forEach(processPlaylistItem);
192206
};
193207

194-
const main = document.querySelector('div#main-container') || document.body;
195-
subscribeOnChanges(main, processPlaylistItem);
196-
197-
try {
198-
const style = document.createElement('style');
199-
style.innerHTML = `
200-
div.${UNWANTED}, li.${UNWANTED} { opacity: 10%; }
201-
div.${UNWANTED}:hover, li.${UNWANTED}:hover { opacity: 40%; }
202-
`;
203-
main.appendChild(style);
204-
} catch (e) {
205-
console.error(e);
206-
}
207-
208-
const filterParams = Object.entries({
209-
'min_duration': MIN_DURATION_MINS,
210-
'hd': 1,
211-
'o': 'tr',
212-
't': 'm',
213-
});
214-
215208
const processLink = node => {
216209
if (node.nodeType !== 1) return;
217210
if (node.tagName === 'A') {
218211
try {
219-
if (premiumRedirect(node)) return;
212+
if (premiumRedirect(node) || node.closest('ul.filterListItem')) return;
220213
const url = new URL(node.href.startsWith('https:') ? node.href : `${window.location.origin}${node.href}`);
221214
const params = url.searchParams;
222215
const p = url.pathname;
223-
if (p === '/video' || p === '/video/search' || p.startsWith('/categories/')) {
224-
filterParams.forEach(([key, value]) => params.set(key, value));
225-
node.href = url.toString();
216+
const parts = p.split('/');
217+
if (['/video', '/video/search'].includes(p) || p.startsWith('/categories/')) {
218+
searchFilterParams.forEach(([key, value]) => params.set(key, value));
219+
} else if (p.startsWith('/pornstar/')) {
220+
if (parts.length === 3) {
221+
url.pathname = [...parts, 'videos', 'upload'].join('/');
222+
} else if (!p.endsWith('/videos/upload')) {
223+
return;
224+
}
225+
params.set('o', 'lg');
226+
} else if (['/model/', '/channels/'].find(i => p.startsWith(i))) {
227+
if (parts.length === 3) {
228+
url.pathname = [...parts, 'videos'].join('/');
229+
} else if (!p.endsWith('/videos')) {
230+
return;
231+
}
232+
params.set('o', p.startsWith('/model/') ? 'lg' : 'ra');
226233
}
234+
setTimeout(_ => node.href = url.toString(), 500);
227235
} catch (e) {
228236
console.error(node.href, e);
229237
}
@@ -232,23 +240,39 @@
232240
node.childNodes.forEach(processLink);
233241
};
234242

235-
subscribeOnChanges(main, processLink);
236-
237-
// TODO
238-
/*const searchForm = main.querySelector('form#search_form') || main.querySelector('form');
239-
if (searchForm) {
240-
filterParams.forEach(([key, value]) => {
241-
const input = document.createElement('input');
242-
input.type = 'hidden';
243-
input.name = key;
244-
input.value = value;
245-
searchForm.appendChild(input);
246-
});
247-
}*/
248-
249-
const similarVideos = [...main.querySelectorAll('var.duration')]
243+
const similarVideos = [...body.querySelectorAll('var.duration')]
250244
.map(i => processPreview(i))
251245
.filter(i => i);
246+
subscribeOnChanges(body, processPlaylistItem);
247+
subscribeOnChanges(body, processLink);
248+
249+
try {
250+
const style = document.createElement('style');
251+
style.innerHTML = `
252+
div.${UNWANTED}, li.${UNWANTED} { opacity: 10%; }
253+
div.${UNWANTED}:hover, li.${UNWANTED}:hover { opacity: 40%; }
254+
#searchSuggestions a:focus { background-color: #111111; }
255+
`;
256+
body.appendChild(style);
257+
} catch (e) {
258+
console.error(e);
259+
}
260+
261+
const searchForm = body.querySelector('form#search_form') || body.querySelector('form');
262+
searchForm?.addEventListener('submit', event => {
263+
event.preventDefault();
264+
event.stopImmediatePropagation();
265+
266+
const node = document.activeElement;
267+
const searchInput = searchForm.querySelector('input#searchInput, input[name="search"]') || (node.tagName === 'INPUT' && searchForm.contains(node) ? node : undefined);
268+
const query = (searchInput?.value || '').trim();
269+
if (query.length === 0) return;
270+
271+
const url = new URL(searchForm.action); // TODO
272+
searchFilterParams.forEach(([key, value]) => url.searchParams.set(key, value));
273+
url.searchParams.set('search', query);
274+
window.location.href = url.toString();
275+
}, true);
252276

253277
if (p.startsWith('/embed/')) {
254278
// this branch gets selected for both iframed and redirected embedded player
@@ -257,11 +281,11 @@
257281
processEmbedded(document, similarVideos); // document is a part of iframe here
258282
}, 1000);
259283
} else if (p === '/view_video.php') {
260-
const durationFromNormalPlayer = timeToSeconds(main.querySelector('span.mgp_total')?.textContent);
284+
const durationFromNormalPlayer = timeToSeconds(body.querySelector('span.mgp_total')?.textContent);
261285
if (durationFromNormalPlayer) {
262-
const lowQuality = ![...main.querySelectorAll('ul.mgp_quality > li')].find(i => i.textContent.includes(MIN_VIDEO_HEIGHT));
286+
const lowQuality = ![...body.querySelectorAll('ul.mgp_quality > li')].find(i => i.textContent.includes(MIN_VIDEO_HEIGHT));
263287
console.log('low quality', lowQuality);
264-
if (lowQuality || disliked(main)) {
288+
if (lowQuality || disliked(body)) {
265289
setUnwanted(url, Number.MAX_SAFE_INTEGER);
266290
}
267291

@@ -273,7 +297,7 @@
273297
} else {
274298
console.log('fallback to embedded player');
275299
const embedUrl = `https://www.pornhub.com/embed/${params.get('viewkey')}`;
276-
const container = main.querySelector('div.playerFlvContainer');
300+
const container = body.querySelector('div.playerFlvContainer');
277301
if (container) {
278302
const iframe = document.createElement('iframe');
279303
iframe.onload = _ => {

0 commit comments

Comments
 (0)