pervert-monkey 1.0.1 → 1.0.3
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/userscripts/3hentai.user.js +5 -1143
- package/dist/userscripts/camgirlfinder.user.js +2 -0
- package/dist/userscripts/camwhores.user.js +28 -1251
- package/dist/userscripts/e-hentai.user.js +6 -1144
- package/dist/userscripts/ebalka.user.js +8 -1172
- package/dist/userscripts/eporner.user.js +6 -1164
- package/dist/userscripts/erome.user.js +5 -1141
- package/dist/userscripts/eroprofile.user.js +5 -1143
- package/dist/userscripts/javhdporn.user.js +5 -1143
- package/dist/userscripts/missav.user.js +5 -1143
- package/dist/userscripts/motherless.user.js +9 -1207
- package/dist/userscripts/namethatporn.user.js +5 -1142
- package/dist/userscripts/nhentai.user.js +9 -1147
- package/dist/userscripts/pornhub.user.js +5 -1143
- package/dist/userscripts/spankbang.user.js +8 -1172
- package/dist/userscripts/xhamster.user.js +14 -1223
- package/dist/userscripts/xvideos.user.js +8 -1171
- package/package.json +2 -1
- package/src/userscripts/meta.json +5 -1
|
@@ -13,13 +13,14 @@
|
|
|
13
13
|
// @match https://*.camwhores.*/*
|
|
14
14
|
// @match https://*.camwhores.tv
|
|
15
15
|
// @exclude https://*.camwhores.tv/*mode=async*
|
|
16
|
-
// @require https://cdn.jsdelivr.net/npm/
|
|
16
|
+
// @require https://cdn.jsdelivr.net/npm/pervert-monkey@latest/dist/core/pervertmonkey.core.umd.js
|
|
17
|
+
// @require data:application/javascript,var core = window.pervertmonkey.core || pervertmonkey.core; var utils = core;
|
|
17
18
|
// @grant GM_addStyle
|
|
18
19
|
// @grant unsafeWindow
|
|
19
20
|
// @run-at document-idle
|
|
20
21
|
// ==/UserScript==
|
|
21
22
|
|
|
22
|
-
(function (
|
|
23
|
+
(function (core, utils) {
|
|
23
24
|
'use strict';
|
|
24
25
|
|
|
25
26
|
class LSKDB {
|
|
@@ -78,1230 +79,6 @@
|
|
|
78
79
|
var _GM_addStyle = (() => typeof GM_addStyle != "undefined" ? GM_addStyle : undefined)();
|
|
79
80
|
var _unsafeWindow = (() => typeof unsafeWindow != "undefined" ? unsafeWindow : undefined)();
|
|
80
81
|
|
|
81
|
-
function memoize(fn) {
|
|
82
|
-
const cache = new Map();
|
|
83
|
-
const memoizedFunction = ((...args) => {
|
|
84
|
-
const key = JSON.stringify(args);
|
|
85
|
-
if (cache.has(key)) {
|
|
86
|
-
return cache.get(key);
|
|
87
|
-
}
|
|
88
|
-
const result = fn(...args);
|
|
89
|
-
cache.set(key, result);
|
|
90
|
-
return result;
|
|
91
|
-
});
|
|
92
|
-
return memoizedFunction;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function objectToFormData(obj) {
|
|
96
|
-
const formData = new FormData();
|
|
97
|
-
Object.entries(obj).forEach(([k, v]) => {
|
|
98
|
-
formData.append(k, v);
|
|
99
|
-
});
|
|
100
|
-
return formData;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function splitWith(s, c = ",") {
|
|
104
|
-
return s.split(c).map((s2) => s2.trim()).filter(Boolean);
|
|
105
|
-
}
|
|
106
|
-
function sanitizeStr(s) {
|
|
107
|
-
return s?.replace(/\n|\t/g, " ").replace(/ {2,}/g, " ").trim() || "";
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
class RegexFilter {
|
|
111
|
-
regexes;
|
|
112
|
-
constructor(str, flags = "gi") {
|
|
113
|
-
this.regexes = memoize(this.compileSearchRegex)(str, flags);
|
|
114
|
-
}
|
|
115
|
-
compileSearchRegex(str, flags) {
|
|
116
|
-
try {
|
|
117
|
-
if (str.startsWith("r:")) return [new RegExp(str.slice(2), flags)];
|
|
118
|
-
const regexes = splitWith(str).map(
|
|
119
|
-
(s) => s.replace(/f:(\w+)/g, (_, w) => `(^|\\ |,)${w}($|\\ |,)`)
|
|
120
|
-
).map((_) => new RegExp(_, flags));
|
|
121
|
-
return regexes;
|
|
122
|
-
} catch (_) {
|
|
123
|
-
return [];
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
hasEvery(str) {
|
|
127
|
-
return this.regexes.every((r) => r.test(str));
|
|
128
|
-
}
|
|
129
|
-
hasNone(str) {
|
|
130
|
-
return this.regexes.every((r) => !r.test(str));
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
class DataFilter {
|
|
135
|
-
constructor(rules) {
|
|
136
|
-
this.rules = rules;
|
|
137
|
-
this.registerFilters(rules.customDataSelectorFns);
|
|
138
|
-
this.applyCSSFilters();
|
|
139
|
-
}
|
|
140
|
-
filters = new Map();
|
|
141
|
-
static isFiltered(el) {
|
|
142
|
-
return el.className.includes("filter-");
|
|
143
|
-
}
|
|
144
|
-
applyCSSFilters(wrapper) {
|
|
145
|
-
this.filters.forEach((_, name) => {
|
|
146
|
-
const cssRule = `.filter-${name} { display: none !important; }`;
|
|
147
|
-
if (wrapper) {
|
|
148
|
-
_GM_addStyle(wrapper(cssRule));
|
|
149
|
-
} else {
|
|
150
|
-
_GM_addStyle(cssRule);
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
customDataSelectorFns = {};
|
|
155
|
-
registerFilters(customFilters) {
|
|
156
|
-
customFilters.forEach((o) => {
|
|
157
|
-
if (typeof o === "string") {
|
|
158
|
-
this.customDataSelectorFns[o] = DataFilter.customDataSelectorFnsDefault[o];
|
|
159
|
-
this.registerFilter(o);
|
|
160
|
-
} else {
|
|
161
|
-
const k = Object.keys(o)[0];
|
|
162
|
-
this.customDataSelectorFns[k] = o[k];
|
|
163
|
-
this.registerFilter(k);
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
customSelectorParser(name, selector) {
|
|
168
|
-
if ("handle" in selector) {
|
|
169
|
-
return selector;
|
|
170
|
-
} else {
|
|
171
|
-
return { handle: selector, deps: [name] };
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
registerFilter(customSelectorName) {
|
|
175
|
-
const handler = this.customSelectorParser(
|
|
176
|
-
customSelectorName,
|
|
177
|
-
this.customDataSelectorFns[customSelectorName]
|
|
178
|
-
);
|
|
179
|
-
const tag = `filter-${customSelectorName}`;
|
|
180
|
-
[customSelectorName, ...handler.deps || []]?.forEach((name) => {
|
|
181
|
-
Object.assign(this.filterMapping, { [name]: customSelectorName });
|
|
182
|
-
});
|
|
183
|
-
const fn = () => {
|
|
184
|
-
const preDefined = handler.$preDefine?.(this.rules.store.state);
|
|
185
|
-
return (v) => {
|
|
186
|
-
const condition = handler.handle(v, this.rules.store.state, preDefined);
|
|
187
|
-
return {
|
|
188
|
-
condition,
|
|
189
|
-
tag
|
|
190
|
-
};
|
|
191
|
-
};
|
|
192
|
-
};
|
|
193
|
-
this.filters.set(customSelectorName, fn);
|
|
194
|
-
}
|
|
195
|
-
filterMapping = {};
|
|
196
|
-
selectFilters(filters) {
|
|
197
|
-
const selectedFilters = Object.keys(filters).filter((k) => k in this.filterMapping).map((k) => this.filterMapping[k]).map((k) => this.filters.get(k));
|
|
198
|
-
return selectedFilters;
|
|
199
|
-
}
|
|
200
|
-
static customDataSelectorFnsDefault = {
|
|
201
|
-
filterDuration: {
|
|
202
|
-
handle(el, state, notInRange) {
|
|
203
|
-
return state.filterDuration && notInRange(el.duration);
|
|
204
|
-
},
|
|
205
|
-
$preDefine: (state) => {
|
|
206
|
-
const from = state.filterDurationFrom;
|
|
207
|
-
const to = state.filterDurationTo;
|
|
208
|
-
function notInRange(d) {
|
|
209
|
-
return d < from || d > to;
|
|
210
|
-
}
|
|
211
|
-
return notInRange;
|
|
212
|
-
},
|
|
213
|
-
deps: ["filterDurationFrom", "filterDurationTo"]
|
|
214
|
-
},
|
|
215
|
-
filterExclude: {
|
|
216
|
-
handle(el, state, searchFilter) {
|
|
217
|
-
if (!state.filterExclude) return false;
|
|
218
|
-
return !searchFilter.hasNone(el.title);
|
|
219
|
-
},
|
|
220
|
-
$preDefine: (state) => new RegexFilter(state.filterExcludeWords),
|
|
221
|
-
deps: ["filterExcludeWords"]
|
|
222
|
-
},
|
|
223
|
-
filterInclude: {
|
|
224
|
-
handle(el, state, searchFilter) {
|
|
225
|
-
if (!state.filterInclude) return false;
|
|
226
|
-
return !searchFilter.hasEvery(el.title);
|
|
227
|
-
},
|
|
228
|
-
$preDefine: (state) => new RegexFilter(state.filterIncludeWords),
|
|
229
|
-
deps: ["filterIncludeWords"]
|
|
230
|
-
}
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
function waitForElementToAppear(parent, selector, callback) {
|
|
235
|
-
const observer = new MutationObserver((_mutations) => {
|
|
236
|
-
const el = parent.querySelector(selector);
|
|
237
|
-
if (el) {
|
|
238
|
-
observer.disconnect();
|
|
239
|
-
callback(el);
|
|
240
|
-
}
|
|
241
|
-
});
|
|
242
|
-
observer.observe(document.body, { childList: true, subtree: true });
|
|
243
|
-
return observer;
|
|
244
|
-
}
|
|
245
|
-
function waitForElementToDisappear(observable, callback) {
|
|
246
|
-
const observer = new MutationObserver((_mutations) => {
|
|
247
|
-
if (!observable.isConnected) {
|
|
248
|
-
observer.disconnect();
|
|
249
|
-
callback();
|
|
250
|
-
}
|
|
251
|
-
});
|
|
252
|
-
observer.observe(document.body, { childList: true, subtree: true });
|
|
253
|
-
return observer;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
function querySelectorLast(root = document, selector) {
|
|
257
|
-
const nodes = root.querySelectorAll(selector);
|
|
258
|
-
return nodes.length > 0 ? nodes[nodes.length - 1] : void 0;
|
|
259
|
-
}
|
|
260
|
-
function querySelectorLastNumber(selector, e = document) {
|
|
261
|
-
const text = querySelectorText(e, selector);
|
|
262
|
-
return Number(text.match(/\d+/g)?.pop() || 0);
|
|
263
|
-
}
|
|
264
|
-
function querySelectorText(e, selector) {
|
|
265
|
-
if (typeof selector !== "string") return "";
|
|
266
|
-
const text = e.querySelector(selector)?.innerText || "";
|
|
267
|
-
return sanitizeStr(text);
|
|
268
|
-
}
|
|
269
|
-
function parseHtml(html) {
|
|
270
|
-
const parsed = new DOMParser().parseFromString(html, "text/html").body;
|
|
271
|
-
if (parsed.children.length > 1) return parsed;
|
|
272
|
-
return parsed.firstElementChild;
|
|
273
|
-
}
|
|
274
|
-
function removeClassesAndDataAttributes(element, keyword) {
|
|
275
|
-
Array.from(element.classList).forEach((className) => {
|
|
276
|
-
if (className.includes(keyword)) {
|
|
277
|
-
element.classList.remove(className);
|
|
278
|
-
}
|
|
279
|
-
});
|
|
280
|
-
Array.from(element.attributes).forEach((attr) => {
|
|
281
|
-
if (attr.name.startsWith("data-") && attr.name.includes(keyword)) {
|
|
282
|
-
element.removeAttribute(attr.name);
|
|
283
|
-
}
|
|
284
|
-
});
|
|
285
|
-
}
|
|
286
|
-
function getCommonParents(elements) {
|
|
287
|
-
const parents = Array.from(elements).map((el) => el.parentElement).filter((parent) => parent !== null);
|
|
288
|
-
return [...new Set(parents)];
|
|
289
|
-
}
|
|
290
|
-
function checkHomogenity(a, b, options) {
|
|
291
|
-
if (!a || !b) return false;
|
|
292
|
-
if (options.id) {
|
|
293
|
-
if (a.id !== b.id) return false;
|
|
294
|
-
}
|
|
295
|
-
if (options.className) {
|
|
296
|
-
const ca = a.className;
|
|
297
|
-
const cb = b.className;
|
|
298
|
-
if (!(ca.length > cb.length ? ca.includes(cb) : cb.includes(ca))) {
|
|
299
|
-
return false;
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
return true;
|
|
303
|
-
}
|
|
304
|
-
function downloader(options = { append: "", after: "", button: "", cbBefore: () => {
|
|
305
|
-
} }) {
|
|
306
|
-
const btn = parseHtml(options.button);
|
|
307
|
-
if (options.append) document.querySelector(options.append)?.append(btn);
|
|
308
|
-
if (options.after) document.querySelector(options.after)?.after(btn);
|
|
309
|
-
btn.addEventListener("click", (e) => {
|
|
310
|
-
e.preventDefault();
|
|
311
|
-
if (options.cbBefore) options.cbBefore();
|
|
312
|
-
waitForElementToAppear(document.body, "video", (video) => {
|
|
313
|
-
window.location.href = video.getAttribute("src");
|
|
314
|
-
});
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
class LazyImgLoader {
|
|
319
|
-
lazyImgObserver;
|
|
320
|
-
attributeName = "data-lazy-load";
|
|
321
|
-
constructor(shouldDelazify) {
|
|
322
|
-
this.lazyImgObserver = new Observer((target) => {
|
|
323
|
-
if (shouldDelazify(target)) {
|
|
324
|
-
this.delazify(target);
|
|
325
|
-
}
|
|
326
|
-
});
|
|
327
|
-
}
|
|
328
|
-
lazify(_target, img, imgSrc) {
|
|
329
|
-
if (!img || !imgSrc) return;
|
|
330
|
-
img.setAttribute(this.attributeName, imgSrc);
|
|
331
|
-
img.src = "";
|
|
332
|
-
this.lazyImgObserver.observe(img);
|
|
333
|
-
}
|
|
334
|
-
delazify = (target) => {
|
|
335
|
-
this.lazyImgObserver.observer.unobserve(target);
|
|
336
|
-
target.src = target.getAttribute(this.attributeName);
|
|
337
|
-
target.removeAttribute(this.attributeName);
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
class Observer {
|
|
342
|
-
constructor(callback) {
|
|
343
|
-
this.callback = callback;
|
|
344
|
-
this.observer = new IntersectionObserver(this.handleIntersection.bind(this));
|
|
345
|
-
}
|
|
346
|
-
observer;
|
|
347
|
-
timeout;
|
|
348
|
-
observe(target) {
|
|
349
|
-
this.observer.observe(target);
|
|
350
|
-
}
|
|
351
|
-
throttle(target, throttleTime) {
|
|
352
|
-
this.observer.unobserve(target);
|
|
353
|
-
this.timeout = window.setTimeout(() => this.observer.observe(target), throttleTime);
|
|
354
|
-
}
|
|
355
|
-
handleIntersection(entries) {
|
|
356
|
-
for (const entry of entries) {
|
|
357
|
-
if (entry.isIntersecting) {
|
|
358
|
-
this.callback(entry.target);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
dispose() {
|
|
363
|
-
if (this.timeout) clearTimeout(this.timeout);
|
|
364
|
-
this.observer.disconnect();
|
|
365
|
-
}
|
|
366
|
-
static observeWhile(target, callback, throttleTime) {
|
|
367
|
-
const observer_ = new Observer(async (target2) => {
|
|
368
|
-
const condition = await callback();
|
|
369
|
-
if (condition) observer_.throttle(target2, throttleTime);
|
|
370
|
-
});
|
|
371
|
-
observer_.observe(target);
|
|
372
|
-
return observer_;
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
class DataManager {
|
|
377
|
-
constructor(rules) {
|
|
378
|
-
this.rules = rules;
|
|
379
|
-
this.dataFilter = new DataFilter(this.rules);
|
|
380
|
-
}
|
|
381
|
-
data = new Map();
|
|
382
|
-
lazyImgLoader = new LazyImgLoader(
|
|
383
|
-
(target) => !DataFilter.isFiltered(target)
|
|
384
|
-
);
|
|
385
|
-
dataFilter;
|
|
386
|
-
applyFilters = async (filters = {}, offset = 0) => {
|
|
387
|
-
const filtersToApply = this.dataFilter.selectFilters(filters);
|
|
388
|
-
if (filtersToApply.length === 0) return;
|
|
389
|
-
const iterator = this.data.values().drop(offset);
|
|
390
|
-
let finished = false;
|
|
391
|
-
await new Promise((resolve) => {
|
|
392
|
-
function runBatch(deadline) {
|
|
393
|
-
const updates = [];
|
|
394
|
-
while (deadline.timeRemaining() > 0) {
|
|
395
|
-
const { value, done } = iterator.next();
|
|
396
|
-
finished = !!done;
|
|
397
|
-
if (done) break;
|
|
398
|
-
for (const f of filtersToApply) {
|
|
399
|
-
const { tag, condition } = f()(value);
|
|
400
|
-
updates.push({ e: value.element, tag, condition });
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
if (updates.length > 0) {
|
|
404
|
-
requestAnimationFrame(() => {
|
|
405
|
-
updates.forEach((u) => {
|
|
406
|
-
u.e.classList.toggle(u.tag, u.condition);
|
|
407
|
-
});
|
|
408
|
-
});
|
|
409
|
-
}
|
|
410
|
-
if (!finished) {
|
|
411
|
-
requestIdleCallback(runBatch);
|
|
412
|
-
} else {
|
|
413
|
-
resolve(true);
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
requestIdleCallback(runBatch);
|
|
417
|
-
});
|
|
418
|
-
};
|
|
419
|
-
filterAll = async (offset) => {
|
|
420
|
-
const keys = Array.from(this.dataFilter.filters.keys());
|
|
421
|
-
const filters = Object.fromEntries(
|
|
422
|
-
keys.map((k) => [k, this.rules.store.state[k]])
|
|
423
|
-
);
|
|
424
|
-
await this.applyFilters(filters, offset);
|
|
425
|
-
};
|
|
426
|
-
parseDataParentHomogenity;
|
|
427
|
-
parseData = (html, container, removeDuplicates = false, shouldLazify = true) => {
|
|
428
|
-
const thumbs = this.rules.getThumbs(html);
|
|
429
|
-
const dataOffset = this.data.size;
|
|
430
|
-
const fragment = document.createDocumentFragment();
|
|
431
|
-
const parent = container || this.rules.container;
|
|
432
|
-
const homogenity = !!this.parseDataParentHomogenity;
|
|
433
|
-
for (const thumbElement of thumbs) {
|
|
434
|
-
const url = this.rules.getThumbUrl(thumbElement);
|
|
435
|
-
if (!url || this.data.has(url) || parent !== container && parent?.contains(thumbElement) || homogenity && !checkHomogenity(
|
|
436
|
-
parent,
|
|
437
|
-
thumbElement.parentElement,
|
|
438
|
-
this.parseDataParentHomogenity
|
|
439
|
-
)) {
|
|
440
|
-
if (removeDuplicates) thumbElement.remove();
|
|
441
|
-
continue;
|
|
442
|
-
}
|
|
443
|
-
const data = this.rules.getThumbData(thumbElement);
|
|
444
|
-
this.data.set(url, { element: thumbElement, ...data });
|
|
445
|
-
if (shouldLazify) {
|
|
446
|
-
const { img, imgSrc } = this.rules.getThumbImgData(thumbElement);
|
|
447
|
-
this.lazyImgLoader.lazify(thumbElement, img, imgSrc);
|
|
448
|
-
}
|
|
449
|
-
fragment.append(thumbElement);
|
|
450
|
-
}
|
|
451
|
-
this.filterAll(dataOffset).then(() => {
|
|
452
|
-
requestAnimationFrame(() => {
|
|
453
|
-
parent.appendChild(fragment);
|
|
454
|
-
});
|
|
455
|
-
});
|
|
456
|
-
};
|
|
457
|
-
sortBy(key, direction = true) {
|
|
458
|
-
if (this.data.size < 2) return;
|
|
459
|
-
let sorted = this.data.values().toArray().sort((a, b) => {
|
|
460
|
-
return a[key] - b[key];
|
|
461
|
-
});
|
|
462
|
-
if (!direction) sorted = sorted.reverse();
|
|
463
|
-
const container = sorted[0].element.parentElement;
|
|
464
|
-
container.style.visibility = "hidden";
|
|
465
|
-
sorted.forEach((s) => {
|
|
466
|
-
container.append(s.element);
|
|
467
|
-
});
|
|
468
|
-
container.style.visibility = "visible";
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
function wait(milliseconds) {
|
|
473
|
-
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
const MOBILE_UA = {
|
|
477
|
-
"User-Agent": [
|
|
478
|
-
"Mozilla/5.0 (Linux; Android 10; K)",
|
|
479
|
-
"AppleWebKit/537.36 (KHTML, like Gecko)",
|
|
480
|
-
"Chrome/114.0.0.0 Mobile Safari/537.36"
|
|
481
|
-
].join(" ")
|
|
482
|
-
};
|
|
483
|
-
async function fetchWith(input, options) {
|
|
484
|
-
const requestInit = options.init || {};
|
|
485
|
-
if (options.mobile) {
|
|
486
|
-
Object.assign(requestInit, { headers: new Headers(MOBILE_UA) });
|
|
487
|
-
}
|
|
488
|
-
const r = await fetch(input, requestInit).then((r2) => r2);
|
|
489
|
-
return parseHtml(await r.text());
|
|
490
|
-
}
|
|
491
|
-
const fetchHtml = (input) => fetchWith(input, { });
|
|
492
|
-
|
|
493
|
-
class InfiniteScroller {
|
|
494
|
-
enabled = true;
|
|
495
|
-
paginationOffset = 1;
|
|
496
|
-
parseData;
|
|
497
|
-
rules;
|
|
498
|
-
observer;
|
|
499
|
-
paginationGenerator;
|
|
500
|
-
constructor(options) {
|
|
501
|
-
this.rules = options.rules;
|
|
502
|
-
this.paginationOffset = this.rules.paginationStrategy.getPaginationOffset();
|
|
503
|
-
Object.assign(this, options);
|
|
504
|
-
if (this.rules.getPaginationData) {
|
|
505
|
-
this.getPaginationData = this.rules.getPaginationData;
|
|
506
|
-
}
|
|
507
|
-
this.paginationGenerator = this.rules.customGenerator || InfiniteScroller.generatorForPaginationStrategy(this.rules.paginationStrategy);
|
|
508
|
-
this.setObserver(this.rules.observable);
|
|
509
|
-
this.setAutoScroll();
|
|
510
|
-
}
|
|
511
|
-
dispose() {
|
|
512
|
-
if (this.observer) this.observer.dispose();
|
|
513
|
-
}
|
|
514
|
-
setObserver(observable) {
|
|
515
|
-
if (this.observer) this.observer.dispose();
|
|
516
|
-
this.observer = Observer.observeWhile(
|
|
517
|
-
observable,
|
|
518
|
-
this.generatorConsumer,
|
|
519
|
-
this.rules.store.state.delay
|
|
520
|
-
);
|
|
521
|
-
return this;
|
|
522
|
-
}
|
|
523
|
-
onScrollCBs = [];
|
|
524
|
-
onScroll(callback, initCall = false) {
|
|
525
|
-
if (initCall) callback(this);
|
|
526
|
-
this.onScrollCBs.push(callback);
|
|
527
|
-
return this;
|
|
528
|
-
}
|
|
529
|
-
_onScroll() {
|
|
530
|
-
this.onScrollCBs.forEach((cb) => {
|
|
531
|
-
cb(this);
|
|
532
|
-
});
|
|
533
|
-
}
|
|
534
|
-
setAutoScroll() {
|
|
535
|
-
const autoScrollWrapper = async () => {
|
|
536
|
-
if (this.rules.store.state.autoScroll) {
|
|
537
|
-
await wait(this.rules.store.state.delay);
|
|
538
|
-
await this.generatorConsumer();
|
|
539
|
-
await autoScrollWrapper();
|
|
540
|
-
}
|
|
541
|
-
};
|
|
542
|
-
autoScrollWrapper();
|
|
543
|
-
this.rules.store.stateSubject.subscribe((type) => {
|
|
544
|
-
if (type?.autoScroll) {
|
|
545
|
-
autoScrollWrapper();
|
|
546
|
-
}
|
|
547
|
-
});
|
|
548
|
-
}
|
|
549
|
-
generatorConsumer = async () => {
|
|
550
|
-
if (!this.enabled) return false;
|
|
551
|
-
const {
|
|
552
|
-
value: { url, offset },
|
|
553
|
-
done
|
|
554
|
-
} = await this.paginationGenerator.next();
|
|
555
|
-
if (!done && url) {
|
|
556
|
-
await this.doScroll(url, offset);
|
|
557
|
-
}
|
|
558
|
-
return !done;
|
|
559
|
-
};
|
|
560
|
-
async getPaginationData(url) {
|
|
561
|
-
return await fetchHtml(url);
|
|
562
|
-
}
|
|
563
|
-
async doScroll(url, offset) {
|
|
564
|
-
const nextPageHtml = await this.getPaginationData(url);
|
|
565
|
-
const prevScrollPos = document.documentElement.scrollTop;
|
|
566
|
-
this.paginationOffset = Math.max(this.paginationOffset, offset);
|
|
567
|
-
this.parseData?.(nextPageHtml);
|
|
568
|
-
this._onScroll();
|
|
569
|
-
window.scrollTo(0, prevScrollPos);
|
|
570
|
-
if (this.rules.store.state.writeHistory) {
|
|
571
|
-
history.replaceState({}, "", url);
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
static async *generatorForPaginationStrategy(pstrategy) {
|
|
575
|
-
const _offset = pstrategy.getPaginationOffset();
|
|
576
|
-
const end = pstrategy.getPaginationLast();
|
|
577
|
-
const urlGenerator = pstrategy.getPaginationUrlGenerator();
|
|
578
|
-
for (let offset = _offset; offset <= end; offset++) {
|
|
579
|
-
const url = await urlGenerator(offset);
|
|
580
|
-
yield { url, offset };
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
static create(rules) {
|
|
584
|
-
const enabled = rules.store.state.infiniteScrollEnabled;
|
|
585
|
-
rules.store.state.$paginationLast = rules.paginationStrategy.getPaginationLast();
|
|
586
|
-
const infiniteScroller = new InfiniteScroller({
|
|
587
|
-
enabled,
|
|
588
|
-
parseData: rules.dataManager.parseData,
|
|
589
|
-
rules
|
|
590
|
-
}).onScroll(({ paginationOffset }) => {
|
|
591
|
-
rules.store.state.$paginationOffset = paginationOffset;
|
|
592
|
-
}, true);
|
|
593
|
-
rules.store.stateSubject.subscribe(() => {
|
|
594
|
-
infiniteScroller.enabled = rules.store.state.infiniteScrollEnabled;
|
|
595
|
-
});
|
|
596
|
-
return infiniteScroller;
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
var Pe=Object.defineProperty;var a=(e,t)=>Pe(e,"name",{value:t,configurable:true});var P=class{type=3;name="";prefix="";value="";suffix="";modifier=3;constructor(t,r,n,c,l,f){this.type=t,this.name=r,this.prefix=n,this.value=c,this.suffix=l,this.modifier=f;}hasCustomName(){return this.name!==""&&typeof this.name!="number"}};a(P,"Part");var Re=/[$_\p{ID_Start}]/u,Ee=/[$_\u200C\u200D\p{ID_Continue}]/u,v=".*";function Oe(e,t){return (t?/^[\x00-\xFF]*$/:/^[\x00-\x7F]*$/).test(e)}a(Oe,"isASCII");function D(e,t=false){let r=[],n=0;for(;n<e.length;){let c=e[n],l=a(function(f){if(!t)throw new TypeError(f);r.push({type:"INVALID_CHAR",index:n,value:e[n++]});},"ErrorOrInvalid");if(c==="*"){r.push({type:"ASTERISK",index:n,value:e[n++]});continue}if(c==="+"||c==="?"){r.push({type:"OTHER_MODIFIER",index:n,value:e[n++]});continue}if(c==="\\"){r.push({type:"ESCAPED_CHAR",index:n++,value:e[n++]});continue}if(c==="{"){r.push({type:"OPEN",index:n,value:e[n++]});continue}if(c==="}"){r.push({type:"CLOSE",index:n,value:e[n++]});continue}if(c===":"){let f="",s=n+1;for(;s<e.length;){let i=e.substr(s,1);if(s===n+1&&Re.test(i)||s!==n+1&&Ee.test(i)){f+=e[s++];continue}break}if(!f){l(`Missing parameter name at ${n}`);continue}r.push({type:"NAME",index:n,value:f}),n=s;continue}if(c==="("){let f=1,s="",i=n+1,o=false;if(e[i]==="?"){l(`Pattern cannot start with "?" at ${i}`);continue}for(;i<e.length;){if(!Oe(e[i],false)){l(`Invalid character '${e[i]}' at ${i}.`),o=true;break}if(e[i]==="\\"){s+=e[i++]+e[i++];continue}if(e[i]===")"){if(f--,f===0){i++;break}}else if(e[i]==="("&&(f++,e[i+1]!=="?")){l(`Capturing groups are not allowed at ${i}`),o=true;break}s+=e[i++];}if(o)continue;if(f){l(`Unbalanced pattern at ${n}`);continue}if(!s){l(`Missing pattern at ${n}`);continue}r.push({type:"REGEX",index:n,value:s}),n=i;continue}r.push({type:"CHAR",index:n,value:e[n++]});}return r.push({type:"END",index:n,value:""}),r}a(D,"lexer");function F(e,t={}){let r=D(e);t.delimiter??="/#?",t.prefixes??="./";let n=`[^${x(t.delimiter)}]+?`,c=[],l=0,f=0,i=new Set,o=a(u=>{if(f<r.length&&r[f].type===u)return r[f++].value},"tryConsume"),h=a(()=>o("OTHER_MODIFIER")??o("ASTERISK"),"tryConsumeModifier"),p=a(u=>{let d=o(u);if(d!==void 0)return d;let{type:g,index:y}=r[f];throw new TypeError(`Unexpected ${g} at ${y}, expected ${u}`)},"mustConsume"),A=a(()=>{let u="",d;for(;d=o("CHAR")??o("ESCAPED_CHAR");)u+=d;return u},"consumeText"),xe=a(u=>u,"DefaultEncodePart"),N=t.encodePart||xe,H="",$=a(u=>{H+=u;},"appendToPendingFixedValue"),M=a(()=>{H.length&&(c.push(new P(3,"","",N(H),"",3)),H="");},"maybeAddPartFromPendingFixedValue"),X=a((u,d,g,y,Z)=>{let m=3;switch(Z){case "?":m=1;break;case "*":m=0;break;case "+":m=2;break}if(!d&&!g&&m===3){$(u);return}if(M(),!d&&!g){if(!u)return;c.push(new P(3,"","",N(u),"",m));return}let S;g?g==="*"?S=v:S=g:S=n;let k=2;S===n?(k=1,S=""):S===v&&(k=0,S="");let E;if(d?E=d:g&&(E=l++),i.has(E))throw new TypeError(`Duplicate name '${E}'.`);i.add(E),c.push(new P(k,E,N(u),S,N(y),m));},"addPart");for(;f<r.length;){let u=o("CHAR"),d=o("NAME"),g=o("REGEX");if(!d&&!g&&(g=o("ASTERISK")),d||g){let m=u??"";t.prefixes.indexOf(m)===-1&&($(m),m=""),M();let S=h();X(m,d,g,"",S);continue}let y=u??o("ESCAPED_CHAR");if(y){$(y);continue}if(o("OPEN")){let m=A(),S=o("NAME"),k=o("REGEX");!S&&!k&&(k=o("ASTERISK"));let E=A();p("CLOSE");let be=h();X(m,S,k,E,be);continue}M(),p("END");}return c}a(F,"parse");function x(e){return e.replace(/([.+*?^${}()[\]|/\\])/g,"\\$1")}a(x,"escapeString");function B(e){return e&&e.ignoreCase?"ui":"u"}a(B,"flags");function q(e,t,r){return W(F(e,r),t,r)}a(q,"stringToRegexp");function T(e){switch(e){case 0:return "*";case 1:return "?";case 2:return "+";case 3:return ""}}a(T,"modifierToString");function W(e,t,r={}){r.delimiter??="/#?",r.prefixes??="./",r.sensitive??=false,r.strict??=false,r.end??=true,r.start??=true,r.endsWith="";let n=r.start?"^":"";for(let s of e){if(s.type===3){s.modifier===3?n+=x(s.value):n+=`(?:${x(s.value)})${T(s.modifier)}`;continue}t&&t.push(s.name);let i=`[^${x(r.delimiter)}]+?`,o=s.value;if(s.type===1?o=i:s.type===0&&(o=v),!s.prefix.length&&!s.suffix.length){s.modifier===3||s.modifier===1?n+=`(${o})${T(s.modifier)}`:n+=`((?:${o})${T(s.modifier)})`;continue}if(s.modifier===3||s.modifier===1){n+=`(?:${x(s.prefix)}(${o})${x(s.suffix)})`,n+=T(s.modifier);continue}n+=`(?:${x(s.prefix)}`,n+=`((?:${o})(?:`,n+=x(s.suffix),n+=x(s.prefix),n+=`(?:${o}))*)${x(s.suffix)})`,s.modifier===0&&(n+="?");}let c=`[${x(r.endsWith)}]|$`,l=`[${x(r.delimiter)}]`;if(r.end)return r.strict||(n+=`${l}?`),r.endsWith.length?n+=`(?=${c})`:n+="$",new RegExp(n,B(r));r.strict||(n+=`(?:${l}(?=${c}))?`);let f=false;if(e.length){let s=e[e.length-1];s.type===3&&s.modifier===3&&(f=r.delimiter.indexOf(s)>-1);}return f||(n+=`(?=${l}|${c})`),new RegExp(n,B(r))}a(W,"partsToRegexp");var b={delimiter:"",prefixes:"",sensitive:true,strict:true},J={delimiter:".",prefixes:"",sensitive:true,strict:true},Q={delimiter:"/",prefixes:"/",sensitive:true,strict:true};function ee(e,t){return e.length?e[0]==="/"?true:!t||e.length<2?false:(e[0]=="\\"||e[0]=="{")&&e[1]=="/":false}a(ee,"isAbsolutePathname");function te(e,t){return e.startsWith(t)?e.substring(t.length,e.length):e}a(te,"maybeStripPrefix");function ke(e,t){return e.endsWith(t)?e.substr(0,e.length-t.length):e}a(ke,"maybeStripSuffix");function _(e){return !e||e.length<2?false:e[0]==="["||(e[0]==="\\"||e[0]==="{")&&e[1]==="["}a(_,"treatAsIPv6Hostname");var re=["ftp","file","http","https","ws","wss"];function U(e){if(!e)return true;for(let t of re)if(e.test(t))return true;return false}a(U,"isSpecialScheme");function ne(e,t){if(e=te(e,"#"),t||e==="")return e;let r=new URL("https://example.com");return r.hash=e,r.hash?r.hash.substring(1,r.hash.length):""}a(ne,"canonicalizeHash");function se(e,t){if(e=te(e,"?"),t||e==="")return e;let r=new URL("https://example.com");return r.search=e,r.search?r.search.substring(1,r.search.length):""}a(se,"canonicalizeSearch");function ie(e,t){return t||e===""?e:_(e)?K(e):j(e)}a(ie,"canonicalizeHostname");function ae(e,t){if(t||e==="")return e;let r=new URL("https://example.com");return r.password=e,r.password}a(ae,"canonicalizePassword");function oe(e,t){if(t||e==="")return e;let r=new URL("https://example.com");return r.username=e,r.username}a(oe,"canonicalizeUsername");function ce(e,t,r){if(r||e==="")return e;if(t&&!re.includes(t))return new URL(`${t}:${e}`).pathname;let n=e[0]=="/";return e=new URL(n?e:"/-"+e,"https://example.com").pathname,n||(e=e.substring(2,e.length)),e}a(ce,"canonicalizePathname");function le(e,t,r){return z(t)===e&&(e=""),r||e===""?e:G(e)}a(le,"canonicalizePort");function fe(e,t){return e=ke(e,":"),t||e===""?e:w(e)}a(fe,"canonicalizeProtocol");function z(e){switch(e){case "ws":case "http":return "80";case "wws":case "https":return "443";case "ftp":return "21";default:return ""}}a(z,"defaultPortForProtocol");function w(e){if(e==="")return e;if(/^[-+.A-Za-z0-9]*$/.test(e))return e.toLowerCase();throw new TypeError(`Invalid protocol '${e}'.`)}a(w,"protocolEncodeCallback");function he(e){if(e==="")return e;let t=new URL("https://example.com");return t.username=e,t.username}a(he,"usernameEncodeCallback");function ue(e){if(e==="")return e;let t=new URL("https://example.com");return t.password=e,t.password}a(ue,"passwordEncodeCallback");function j(e){if(e==="")return e;if(/[\t\n\r #%/:<>?@[\]^\\|]/g.test(e))throw new TypeError(`Invalid hostname '${e}'`);let t=new URL("https://example.com");return t.hostname=e,t.hostname}a(j,"hostnameEncodeCallback");function K(e){if(e==="")return e;if(/[^0-9a-fA-F[\]:]/g.test(e))throw new TypeError(`Invalid IPv6 hostname '${e}'`);return e.toLowerCase()}a(K,"ipv6HostnameEncodeCallback");function G(e){if(e===""||/^[0-9]*$/.test(e)&&parseInt(e)<=65535)return e;throw new TypeError(`Invalid port '${e}'.`)}a(G,"portEncodeCallback");function de(e){if(e==="")return e;let t=new URL("https://example.com");return t.pathname=e[0]!=="/"?"/-"+e:e,e[0]!=="/"?t.pathname.substring(2,t.pathname.length):t.pathname}a(de,"standardURLPathnameEncodeCallback");function pe(e){return e===""?e:new URL(`data:${e}`).pathname}a(pe,"pathURLPathnameEncodeCallback");function ge(e){if(e==="")return e;let t=new URL("https://example.com");return t.search=e,t.search.substring(1,t.search.length)}a(ge,"searchEncodeCallback");function me(e){if(e==="")return e;let t=new URL("https://example.com");return t.hash=e,t.hash.substring(1,t.hash.length)}a(me,"hashEncodeCallback");var C=class{#i;#n=[];#t={};#e=0;#s=1;#l=0;#o=0;#d=0;#p=0;#g=false;constructor(t){this.#i=t;}get result(){return this.#t}parse(){for(this.#n=D(this.#i,true);this.#e<this.#n.length;this.#e+=this.#s){if(this.#s=1,this.#n[this.#e].type==="END"){if(this.#o===0){this.#b(),this.#f()?this.#r(9,1):this.#h()?this.#r(8,1):this.#r(7,0);continue}else if(this.#o===2){this.#u(5);continue}this.#r(10,0);break}if(this.#d>0)if(this.#A())this.#d-=1;else continue;if(this.#T()){this.#d+=1;continue}switch(this.#o){case 0:this.#P()&&this.#u(1);break;case 1:if(this.#P()){this.#C();let t=7,r=1;this.#E()?(t=2,r=3):this.#g&&(t=2),this.#r(t,r);}break;case 2:this.#S()?this.#u(3):(this.#x()||this.#h()||this.#f())&&this.#u(5);break;case 3:this.#O()?this.#r(4,1):this.#S()&&this.#r(5,1);break;case 4:this.#S()&&this.#r(5,1);break;case 5:this.#y()?this.#p+=1:this.#w()&&(this.#p-=1),this.#k()&&!this.#p?this.#r(6,1):this.#x()?this.#r(7,0):this.#h()?this.#r(8,1):this.#f()&&this.#r(9,1);break;case 6:this.#x()?this.#r(7,0):this.#h()?this.#r(8,1):this.#f()&&this.#r(9,1);break;case 7:this.#h()?this.#r(8,1):this.#f()&&this.#r(9,1);break;case 8:this.#f()&&this.#r(9,1);break;}}this.#t.hostname!==void 0&&this.#t.port===void 0&&(this.#t.port="");}#r(t,r){switch(this.#o){case 0:break;case 1:this.#t.protocol=this.#c();break;case 2:break;case 3:this.#t.username=this.#c();break;case 4:this.#t.password=this.#c();break;case 5:this.#t.hostname=this.#c();break;case 6:this.#t.port=this.#c();break;case 7:this.#t.pathname=this.#c();break;case 8:this.#t.search=this.#c();break;case 9:this.#t.hash=this.#c();break;}this.#o!==0&&t!==10&&([1,2,3,4].includes(this.#o)&&[6,7,8,9].includes(t)&&(this.#t.hostname??=""),[1,2,3,4,5,6].includes(this.#o)&&[8,9].includes(t)&&(this.#t.pathname??=this.#g?"/":""),[1,2,3,4,5,6,7].includes(this.#o)&&t===9&&(this.#t.search??="")),this.#R(t,r);}#R(t,r){this.#o=t,this.#l=this.#e+r,this.#e+=r,this.#s=0;}#b(){this.#e=this.#l,this.#s=0;}#u(t){this.#b(),this.#o=t;}#m(t){return t<0&&(t=this.#n.length-t),t<this.#n.length?this.#n[t]:this.#n[this.#n.length-1]}#a(t,r){let n=this.#m(t);return n.value===r&&(n.type==="CHAR"||n.type==="ESCAPED_CHAR"||n.type==="INVALID_CHAR")}#P(){return this.#a(this.#e,":")}#E(){return this.#a(this.#e+1,"/")&&this.#a(this.#e+2,"/")}#S(){return this.#a(this.#e,"@")}#O(){return this.#a(this.#e,":")}#k(){return this.#a(this.#e,":")}#x(){return this.#a(this.#e,"/")}#h(){if(this.#a(this.#e,"?"))return true;if(this.#n[this.#e].value!=="?")return false;let t=this.#m(this.#e-1);return t.type!=="NAME"&&t.type!=="REGEX"&&t.type!=="CLOSE"&&t.type!=="ASTERISK"}#f(){return this.#a(this.#e,"#")}#T(){return this.#n[this.#e].type=="OPEN"}#A(){return this.#n[this.#e].type=="CLOSE"}#y(){return this.#a(this.#e,"[")}#w(){return this.#a(this.#e,"]")}#c(){let t=this.#n[this.#e],r=this.#m(this.#l).index;return this.#i.substring(r,t.index)}#C(){let t={};Object.assign(t,b),t.encodePart=w;let r=q(this.#c(),void 0,t);this.#g=U(r);}};a(C,"Parser");var V=["protocol","username","password","hostname","port","pathname","search","hash"],O="*";function Se(e,t){if(typeof e!="string")throw new TypeError("parameter 1 is not of type 'string'.");let r=new URL(e,t);return {protocol:r.protocol.substring(0,r.protocol.length-1),username:r.username,password:r.password,hostname:r.hostname,port:r.port,pathname:r.pathname,search:r.search!==""?r.search.substring(1,r.search.length):void 0,hash:r.hash!==""?r.hash.substring(1,r.hash.length):void 0}}a(Se,"extractValues");function R(e,t){return t?I(e):e}a(R,"processBaseURLString");function L(e,t,r){let n;if(typeof t.baseURL=="string")try{n=new URL(t.baseURL),t.protocol===void 0&&(e.protocol=R(n.protocol.substring(0,n.protocol.length-1),r)),!r&&t.protocol===void 0&&t.hostname===void 0&&t.port===void 0&&t.username===void 0&&(e.username=R(n.username,r)),!r&&t.protocol===void 0&&t.hostname===void 0&&t.port===void 0&&t.username===void 0&&t.password===void 0&&(e.password=R(n.password,r)),t.protocol===void 0&&t.hostname===void 0&&(e.hostname=R(n.hostname,r)),t.protocol===void 0&&t.hostname===void 0&&t.port===void 0&&(e.port=R(n.port,r)),t.protocol===void 0&&t.hostname===void 0&&t.port===void 0&&t.pathname===void 0&&(e.pathname=R(n.pathname,r)),t.protocol===void 0&&t.hostname===void 0&&t.port===void 0&&t.pathname===void 0&&t.search===void 0&&(e.search=R(n.search.substring(1,n.search.length),r)),t.protocol===void 0&&t.hostname===void 0&&t.port===void 0&&t.pathname===void 0&&t.search===void 0&&t.hash===void 0&&(e.hash=R(n.hash.substring(1,n.hash.length),r));}catch{throw new TypeError(`invalid baseURL '${t.baseURL}'.`)}if(typeof t.protocol=="string"&&(e.protocol=fe(t.protocol,r)),typeof t.username=="string"&&(e.username=oe(t.username,r)),typeof t.password=="string"&&(e.password=ae(t.password,r)),typeof t.hostname=="string"&&(e.hostname=ie(t.hostname,r)),typeof t.port=="string"&&(e.port=le(t.port,e.protocol,r)),typeof t.pathname=="string"){if(e.pathname=t.pathname,n&&!ee(e.pathname,r)){let c=n.pathname.lastIndexOf("/");c>=0&&(e.pathname=R(n.pathname.substring(0,c+1),r)+e.pathname);}e.pathname=ce(e.pathname,e.protocol,r);}return typeof t.search=="string"&&(e.search=se(t.search,r)),typeof t.hash=="string"&&(e.hash=ne(t.hash,r)),e}a(L,"applyInit");function I(e){return e.replace(/([+*?:{}()\\])/g,"\\$1")}a(I,"escapePatternString");function Te(e){return e.replace(/([.+*?^${}()[\]|/\\])/g,"\\$1")}a(Te,"escapeRegexpString");function Ae(e,t){t.delimiter??="/#?",t.prefixes??="./",t.sensitive??=false,t.strict??=false,t.end??=true,t.start??=true,t.endsWith="";let r=".*",n=`[^${Te(t.delimiter)}]+?`,c=/[$_\u200C\u200D\p{ID_Continue}]/u,l="";for(let f=0;f<e.length;++f){let s=e[f];if(s.type===3){if(s.modifier===3){l+=I(s.value);continue}l+=`{${I(s.value)}}${T(s.modifier)}`;continue}let i=s.hasCustomName(),o=!!s.suffix.length||!!s.prefix.length&&(s.prefix.length!==1||!t.prefixes.includes(s.prefix)),h=f>0?e[f-1]:null,p=f<e.length-1?e[f+1]:null;if(!o&&i&&s.type===1&&s.modifier===3&&p&&!p.prefix.length&&!p.suffix.length)if(p.type===3){let A=p.value.length>0?p.value[0]:"";o=c.test(A);}else o=!p.hasCustomName();if(!o&&!s.prefix.length&&h&&h.type===3){let A=h.value[h.value.length-1];o=t.prefixes.includes(A);}o&&(l+="{"),l+=I(s.prefix),i&&(l+=`:${s.name}`),s.type===2?l+=`(${s.value})`:s.type===1?i||(l+=`(${n})`):s.type===0&&(!i&&(!h||h.type===3||h.modifier!==3||o||s.prefix!=="")?l+="*":l+=`(${r})`),s.type===1&&i&&s.suffix.length&&c.test(s.suffix[0])&&(l+="\\"),l+=I(s.suffix),o&&(l+="}"),s.modifier!==3&&(l+=T(s.modifier));}return l}a(Ae,"partsToPattern");var Y=class{#i;#n={};#t={};#e={};#s={};#l=false;constructor(t={},r,n){try{let c;if(typeof r=="string"?c=r:n=r,typeof t=="string"){let i=new C(t);if(i.parse(),t=i.result,c===void 0&&typeof t.protocol!="string")throw new TypeError("A base URL must be provided for a relative constructor string.");t.baseURL=c;}else {if(!t||typeof t!="object")throw new TypeError("parameter 1 is not of type 'string' and cannot convert to dictionary.");if(c)throw new TypeError("parameter 1 is not of type 'string'.")}typeof n>"u"&&(n={ignoreCase:!1});let l={ignoreCase:n.ignoreCase===!0},f={pathname:O,protocol:O,username:O,password:O,hostname:O,port:O,search:O,hash:O};this.#i=L(f,t,!0),z(this.#i.protocol)===this.#i.port&&(this.#i.port="");let s;for(s of V){if(!(s in this.#i))continue;let i={},o=this.#i[s];switch(this.#t[s]=[],s){case "protocol":Object.assign(i,b),i.encodePart=w;break;case "username":Object.assign(i,b),i.encodePart=he;break;case "password":Object.assign(i,b),i.encodePart=ue;break;case "hostname":Object.assign(i,J),_(o)?i.encodePart=K:i.encodePart=j;break;case "port":Object.assign(i,b),i.encodePart=G;break;case "pathname":U(this.#n.protocol)?(Object.assign(i,Q,l),i.encodePart=de):(Object.assign(i,b,l),i.encodePart=pe);break;case "search":Object.assign(i,b,l),i.encodePart=ge;break;case "hash":Object.assign(i,b,l),i.encodePart=me;break}try{this.#s[s]=F(o,i),this.#n[s]=W(this.#s[s],this.#t[s],i),this.#e[s]=Ae(this.#s[s],i),this.#l=this.#l||this.#s[s].some(h=>h.type===2);}catch{throw new TypeError(`invalid ${s} pattern '${this.#i[s]}'.`)}}}catch(c){throw new TypeError(`Failed to construct 'URLPattern': ${c.message}`)}}get[Symbol.toStringTag](){return "URLPattern"}test(t={},r){let n={pathname:"",protocol:"",username:"",password:"",hostname:"",port:"",search:"",hash:""};if(typeof t!="string"&&r)throw new TypeError("parameter 1 is not of type 'string'.");if(typeof t>"u")return false;try{typeof t=="object"?n=L(n,t,!1):n=L(n,Se(t,r),!1);}catch{return false}let c;for(c of V)if(!this.#n[c].exec(n[c]))return false;return true}exec(t={},r){let n={pathname:"",protocol:"",username:"",password:"",hostname:"",port:"",search:"",hash:""};if(typeof t!="string"&&r)throw new TypeError("parameter 1 is not of type 'string'.");if(typeof t>"u")return;try{typeof t=="object"?n=L(n,t,!1):n=L(n,Se(t,r),!1);}catch{return null}let c={};r?c.inputs=[t,r]:c.inputs=[t];let l;for(l of V){let f=this.#n[l].exec(n[l]);if(!f)return null;let s={};for(let[i,o]of this.#t[l].entries())if(typeof o=="string"||typeof o=="number"){let h=f[i+1];s[o]=h;}c[l]={input:n[l]??"",groups:s};}return c}static compareComponent(t,r,n){let c=a((i,o)=>{for(let h of ["type","modifier","prefix","value","suffix"]){if(i[h]<o[h])return -1;if(i[h]===o[h])continue;return 1}return 0},"comparePart"),l=new P(3,"","","","",3),f=new P(0,"","","","",3),s=a((i,o)=>{let h=0;for(;h<Math.min(i.length,o.length);++h){let p=c(i[h],o[h]);if(p)return p}return i.length===o.length?0:c(i[h]??l,o[h]??l)},"comparePartList");return !r.#e[t]&&!n.#e[t]?0:r.#e[t]&&!n.#e[t]?s(r.#s[t],[f]):!r.#e[t]&&n.#e[t]?s([f],n.#s[t]):s(r.#s[t],n.#s[t])}get protocol(){return this.#e.protocol}get username(){return this.#e.username}get password(){return this.#e.password}get hostname(){return this.#e.hostname}get port(){return this.#e.port}get pathname(){return this.#e.pathname}get search(){return this.#e.search}get hash(){return this.#e.hash}get hasRegExpGroups(){return this.#l}};a(Y,"URLPattern");
|
|
601
|
-
|
|
602
|
-
function parseUrl(s) {
|
|
603
|
-
return new URL(typeof s === "string" ? s : s.href);
|
|
604
|
-
}
|
|
605
|
-
function depaginatePathname(url, pathnamePaginationSelector = /\/(page\/)?\d+\/?$/) {
|
|
606
|
-
const newUrl = new URL(url.toString());
|
|
607
|
-
newUrl.pathname = newUrl.pathname.replace(pathnamePaginationSelector, "/");
|
|
608
|
-
return newUrl;
|
|
609
|
-
}
|
|
610
|
-
function getPaginationLinks(doc = document, url = location.href, pathnamePaginationSelector = /\/(page\/)?\d+\/?$/) {
|
|
611
|
-
const baseUrl = depaginatePathname(parseUrl(url), pathnamePaginationSelector);
|
|
612
|
-
const pathnameStrict = doc instanceof Document;
|
|
613
|
-
const host = doc.baseURI || baseUrl.origin;
|
|
614
|
-
const urlPattern = new Y({
|
|
615
|
-
pathname: pathnameStrict ? `${baseUrl.pathname}*` : "*",
|
|
616
|
-
hostname: baseUrl.hostname
|
|
617
|
-
});
|
|
618
|
-
const pageLinks = [...doc.querySelectorAll("a[href]")].map((a) => a.href).filter((h) => URL.canParse(h));
|
|
619
|
-
return pageLinks.filter((h) => {
|
|
620
|
-
return urlPattern.test(new URL(h, host));
|
|
621
|
-
});
|
|
622
|
-
}
|
|
623
|
-
function upgradePathname(curr, links, pathnamePaginationSelector = /\/(page\/)?\d+\/?$/) {
|
|
624
|
-
if (pathnamePaginationSelector.test(curr.pathname) || links.length < 1) return curr;
|
|
625
|
-
const linksDepaginated = links.map(
|
|
626
|
-
(l) => depaginatePathname(l, pathnamePaginationSelector)
|
|
627
|
-
);
|
|
628
|
-
if (linksDepaginated.some((l) => l.pathname === curr.pathname)) return curr;
|
|
629
|
-
const last = linksDepaginated.at(-1);
|
|
630
|
-
if (last.pathname !== curr.pathname) curr.pathname = last.pathname;
|
|
631
|
-
return curr;
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
class PaginationStrategy {
|
|
635
|
-
doc = document;
|
|
636
|
-
url;
|
|
637
|
-
paginationSelector = ".pagination";
|
|
638
|
-
searchParamSelector = "page";
|
|
639
|
-
static _pathnameSelector = /\/(page\/)?\d+\/?$/;
|
|
640
|
-
pathnameSelector = /\/(\d+)\/?$/;
|
|
641
|
-
dataparamSelector = "[data-parameters *= from]";
|
|
642
|
-
overwritePaginationLast;
|
|
643
|
-
offsetMin = 1;
|
|
644
|
-
constructor(options) {
|
|
645
|
-
if (options) {
|
|
646
|
-
Object.entries(options).forEach(([k, v]) => {
|
|
647
|
-
Object.assign(this, { [k]: v });
|
|
648
|
-
});
|
|
649
|
-
}
|
|
650
|
-
this.url = parseUrl(options?.url || this.doc.URL);
|
|
651
|
-
}
|
|
652
|
-
getPaginationElement() {
|
|
653
|
-
return this.doc.querySelector(this.paginationSelector);
|
|
654
|
-
}
|
|
655
|
-
get hasPagination() {
|
|
656
|
-
return !!this.getPaginationElement();
|
|
657
|
-
}
|
|
658
|
-
getPaginationOffset() {
|
|
659
|
-
return this.offsetMin;
|
|
660
|
-
}
|
|
661
|
-
getPaginationLast() {
|
|
662
|
-
if (this.overwritePaginationLast) return this.overwritePaginationLast(1);
|
|
663
|
-
return 1;
|
|
664
|
-
}
|
|
665
|
-
getPaginationUrlGenerator() {
|
|
666
|
-
return (_) => this.url.href;
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
function formatTimeToHHMMSS(timeStr) {
|
|
671
|
-
const pad = (num) => num.toString().padStart(2, "0");
|
|
672
|
-
const h = timeStr.match(/(\d+)\s*h/)?.[1] || "0";
|
|
673
|
-
const m = timeStr.match(/(\d+)\s*mi?n/)?.[1] || "0";
|
|
674
|
-
const s = timeStr.match(/(\d+)\s*sec/)?.[1] || "0";
|
|
675
|
-
return `${pad(+h)}:${pad(+m)}:${pad(+s)}`;
|
|
676
|
-
}
|
|
677
|
-
function timeToSeconds(timeStr) {
|
|
678
|
-
const normalized = /[a-zA-Z]/.test(timeStr) ? formatTimeToHHMMSS(timeStr) : timeStr;
|
|
679
|
-
return normalized.split(":").reverse().reduce((total, unit, index) => total + parseInt(unit, 10) * 60 ** index, 0);
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
function parseDataParams(str) {
|
|
683
|
-
const paramsStr = decodeURI(str.trim()).split(";");
|
|
684
|
-
return paramsStr.reduce(
|
|
685
|
-
(acc, s) => {
|
|
686
|
-
const parsed = s.match(/([+\w]+):([\w\- ]+)?/);
|
|
687
|
-
if (parsed) {
|
|
688
|
-
const [, key, value] = parsed;
|
|
689
|
-
if (value) {
|
|
690
|
-
key.split("+").forEach((p) => {
|
|
691
|
-
acc[p] = value;
|
|
692
|
-
});
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
return acc;
|
|
696
|
-
},
|
|
697
|
-
{}
|
|
698
|
-
);
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
class PaginationStrategyDataParams extends PaginationStrategy {
|
|
702
|
-
getPaginationLast() {
|
|
703
|
-
const links = this.getPaginationElement()?.querySelectorAll(this.dataparamSelector);
|
|
704
|
-
const pages = Array.from(links || [], (l) => {
|
|
705
|
-
const p = l.getAttribute("data-parameters");
|
|
706
|
-
const v = p?.match(/from\w*:(\d+)/)?.[1] || this.offsetMin.toString();
|
|
707
|
-
return parseInt(v);
|
|
708
|
-
});
|
|
709
|
-
const lastPage = Math.max(...pages, this.offsetMin);
|
|
710
|
-
if (this.overwritePaginationLast) return this.overwritePaginationLast(lastPage);
|
|
711
|
-
return lastPage;
|
|
712
|
-
}
|
|
713
|
-
getPaginationOffset() {
|
|
714
|
-
const link = this.getPaginationElement()?.querySelector(
|
|
715
|
-
".prev[data-parameters *= from], .prev [data-parameters *= from]"
|
|
716
|
-
);
|
|
717
|
-
if (!link) return this.offsetMin;
|
|
718
|
-
const p = link.getAttribute("data-parameters");
|
|
719
|
-
const v = p?.match(/from\w*:(\d+)/)?.[1] || this.offsetMin.toString();
|
|
720
|
-
return parseInt(v);
|
|
721
|
-
}
|
|
722
|
-
getPaginationUrlGenerator() {
|
|
723
|
-
const url = new URL(this.url.href);
|
|
724
|
-
const parametersElement = this.getPaginationElement()?.querySelector(
|
|
725
|
-
"a[data-block-id][data-parameters]"
|
|
726
|
-
);
|
|
727
|
-
const block_id = parametersElement?.getAttribute("data-block-id") || "";
|
|
728
|
-
const parameters = parseDataParams(
|
|
729
|
-
parametersElement?.getAttribute("data-parameters") || ""
|
|
730
|
-
);
|
|
731
|
-
const attrs = {
|
|
732
|
-
block_id,
|
|
733
|
-
function: "get_block",
|
|
734
|
-
mode: "async",
|
|
735
|
-
...parameters
|
|
736
|
-
};
|
|
737
|
-
Object.keys(attrs).forEach((k) => {
|
|
738
|
-
url.searchParams.set(k, attrs[k]);
|
|
739
|
-
});
|
|
740
|
-
const paginationUrlGenerator = (n) => {
|
|
741
|
-
Object.keys(attrs).forEach((k) => {
|
|
742
|
-
k.includes("from") && url.searchParams.set(k, n.toString());
|
|
743
|
-
});
|
|
744
|
-
url.searchParams.set("_", Date.now().toString());
|
|
745
|
-
return url.href;
|
|
746
|
-
};
|
|
747
|
-
return paginationUrlGenerator;
|
|
748
|
-
}
|
|
749
|
-
static testLinks(doc = document) {
|
|
750
|
-
const dataParamLinks = Array.from(
|
|
751
|
-
doc.querySelectorAll("[data-parameters *= from]")
|
|
752
|
-
);
|
|
753
|
-
return dataParamLinks.length > 0;
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
class PaginationStrategyPathnameParams extends PaginationStrategy {
|
|
758
|
-
extractPage = (a) => {
|
|
759
|
-
const href = typeof a === "string" ? a : a.href;
|
|
760
|
-
const { pathname } = new URL(href, this.doc.baseURI || this.url.origin);
|
|
761
|
-
return parseInt(
|
|
762
|
-
pathname.match(this.pathnameSelector)?.pop() || this.offsetMin.toString()
|
|
763
|
-
);
|
|
764
|
-
};
|
|
765
|
-
static checkLink(link, pathnameSelector = PaginationStrategy._pathnameSelector) {
|
|
766
|
-
return pathnameSelector.test(link.pathname);
|
|
767
|
-
}
|
|
768
|
-
static testLinks(links, options) {
|
|
769
|
-
const result = links.some(
|
|
770
|
-
(h) => PaginationStrategyPathnameParams.checkLink(h, options.pathnameSelector)
|
|
771
|
-
);
|
|
772
|
-
if (result) {
|
|
773
|
-
const pathnamesMatched = links.filter(
|
|
774
|
-
(h) => PaginationStrategyPathnameParams.checkLink(h, options.pathnameSelector)
|
|
775
|
-
);
|
|
776
|
-
options.url = upgradePathname(
|
|
777
|
-
parseUrl(options.url),
|
|
778
|
-
pathnamesMatched
|
|
779
|
-
);
|
|
780
|
-
}
|
|
781
|
-
return result;
|
|
782
|
-
}
|
|
783
|
-
getPaginationLast() {
|
|
784
|
-
const links = getPaginationLinks(
|
|
785
|
-
this.getPaginationElement() || document,
|
|
786
|
-
this.url.href,
|
|
787
|
-
this.pathnameSelector
|
|
788
|
-
);
|
|
789
|
-
const pages = Array.from(links, this.extractPage);
|
|
790
|
-
const lastPage = Math.max(...pages, this.offsetMin);
|
|
791
|
-
if (this.overwritePaginationLast) return this.overwritePaginationLast(lastPage);
|
|
792
|
-
return lastPage;
|
|
793
|
-
}
|
|
794
|
-
getPaginationOffset() {
|
|
795
|
-
return this.extractPage(this.url.href);
|
|
796
|
-
}
|
|
797
|
-
getPaginationUrlGenerator(url_ = this.url) {
|
|
798
|
-
const url = new URL(url_.href);
|
|
799
|
-
const pathnameSelectorPlaceholder = this.pathnameSelector.toString().replace(/[/|\\|$|?|(|)]+/g, "/");
|
|
800
|
-
if (!this.pathnameSelector.test(url.pathname)) {
|
|
801
|
-
url.pathname = url.pathname.concat(pathnameSelectorPlaceholder.replace(/d\+/, this.offsetMin.toString())).replace(/\/{2,}/g, "/");
|
|
802
|
-
}
|
|
803
|
-
const paginationUrlGenerator = (offset) => {
|
|
804
|
-
url.pathname = url.pathname.replace(
|
|
805
|
-
this.pathnameSelector,
|
|
806
|
-
pathnameSelectorPlaceholder.replace(/d\+/, offset.toString())
|
|
807
|
-
);
|
|
808
|
-
return url.href;
|
|
809
|
-
};
|
|
810
|
-
return paginationUrlGenerator;
|
|
811
|
-
}
|
|
812
|
-
}
|
|
813
|
-
|
|
814
|
-
class PaginationStrategySearchParams extends PaginationStrategy {
|
|
815
|
-
extractPage = (a) => {
|
|
816
|
-
const href = typeof a === "string" ? a : a.href;
|
|
817
|
-
const p = new URL(href).searchParams.get(this.searchParamSelector);
|
|
818
|
-
return parseInt(p) || this.offsetMin;
|
|
819
|
-
};
|
|
820
|
-
getPaginationLast() {
|
|
821
|
-
const links = getPaginationLinks(
|
|
822
|
-
this.getPaginationElement() || document,
|
|
823
|
-
this.url.href
|
|
824
|
-
).filter(
|
|
825
|
-
(h) => PaginationStrategySearchParams.checkLink(new URL(h), this.searchParamSelector)
|
|
826
|
-
);
|
|
827
|
-
const pages = links.map(this.extractPage);
|
|
828
|
-
const lastPage = Math.max(...pages, this.offsetMin);
|
|
829
|
-
if (this.overwritePaginationLast) return this.overwritePaginationLast(lastPage);
|
|
830
|
-
return lastPage;
|
|
831
|
-
}
|
|
832
|
-
getPaginationOffset() {
|
|
833
|
-
if (this.doc === document) {
|
|
834
|
-
return this.extractPage(this.url);
|
|
835
|
-
}
|
|
836
|
-
const link = this.getPaginationElement()?.querySelector(
|
|
837
|
-
`a.active[href *= "${this.searchParamSelector}="]`
|
|
838
|
-
);
|
|
839
|
-
return this.extractPage(link);
|
|
840
|
-
}
|
|
841
|
-
getPaginationUrlGenerator() {
|
|
842
|
-
const url = new URL(this.url.href);
|
|
843
|
-
const paginationUrlGenerator = (offset) => {
|
|
844
|
-
url.searchParams.set(this.searchParamSelector, offset.toString());
|
|
845
|
-
return url.href;
|
|
846
|
-
};
|
|
847
|
-
return paginationUrlGenerator;
|
|
848
|
-
}
|
|
849
|
-
static checkLink(link, searchParamSelector) {
|
|
850
|
-
const searchParamSelectors = ["page", "p"];
|
|
851
|
-
if (searchParamSelector) searchParamSelectors.push(searchParamSelector);
|
|
852
|
-
return searchParamSelectors.some((p) => link.searchParams.get(p) !== null);
|
|
853
|
-
}
|
|
854
|
-
static testLinks(links, searchParamSelector) {
|
|
855
|
-
return links.some(
|
|
856
|
-
(h) => PaginationStrategySearchParams.checkLink(h, searchParamSelector)
|
|
857
|
-
);
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
function getPaginationStrategy(options) {
|
|
862
|
-
const _paginationStrategy = new PaginationStrategy(options);
|
|
863
|
-
const pagination = _paginationStrategy.getPaginationElement();
|
|
864
|
-
Object.assign(options, { ..._paginationStrategy });
|
|
865
|
-
const { url, searchParamSelector } = options;
|
|
866
|
-
if (!pagination) {
|
|
867
|
-
return _paginationStrategy;
|
|
868
|
-
}
|
|
869
|
-
if (typeof options.getPaginationUrlGenerator === "function") {
|
|
870
|
-
return new PaginationStrategy(options);
|
|
871
|
-
}
|
|
872
|
-
const pageLinks = getPaginationLinks(pagination, url).map((l) => new URL(l));
|
|
873
|
-
const selectStrategy = () => {
|
|
874
|
-
if (PaginationStrategyDataParams.testLinks(pagination)) {
|
|
875
|
-
return PaginationStrategyDataParams;
|
|
876
|
-
}
|
|
877
|
-
if (PaginationStrategySearchParams.testLinks(pageLinks, searchParamSelector)) {
|
|
878
|
-
return PaginationStrategySearchParams;
|
|
879
|
-
}
|
|
880
|
-
if (PaginationStrategyPathnameParams.testLinks(pageLinks, options)) {
|
|
881
|
-
return PaginationStrategyPathnameParams;
|
|
882
|
-
}
|
|
883
|
-
console.error("Found No Strategy");
|
|
884
|
-
return PaginationStrategy;
|
|
885
|
-
};
|
|
886
|
-
const PaginationStrategyConstructor = selectStrategy();
|
|
887
|
-
const paginationStrategy = new PaginationStrategyConstructor(options);
|
|
888
|
-
return paginationStrategy;
|
|
889
|
-
}
|
|
890
|
-
|
|
891
|
-
const DefaultScheme = [
|
|
892
|
-
{
|
|
893
|
-
title: "Text Filter",
|
|
894
|
-
collapsed: true,
|
|
895
|
-
content: [
|
|
896
|
-
{ filterExclude: false, label: "exclude" },
|
|
897
|
-
{
|
|
898
|
-
filterExcludeWords: "",
|
|
899
|
-
label: "keywords",
|
|
900
|
-
watch: "filterExclude",
|
|
901
|
-
placeholder: "word, f:full_word, r:RegEx..."
|
|
902
|
-
},
|
|
903
|
-
{ filterInclude: false, label: "include" },
|
|
904
|
-
{
|
|
905
|
-
filterIncludeWords: "",
|
|
906
|
-
label: "keywords",
|
|
907
|
-
watch: "filterInclude",
|
|
908
|
-
placeholder: "word, f:full_word, r:RegEx..."
|
|
909
|
-
}
|
|
910
|
-
]
|
|
911
|
-
},
|
|
912
|
-
{
|
|
913
|
-
title: "Duration Filter",
|
|
914
|
-
collapsed: true,
|
|
915
|
-
content: [
|
|
916
|
-
{ filterDuration: false, label: "enable" },
|
|
917
|
-
{
|
|
918
|
-
filterDurationFrom: 0,
|
|
919
|
-
watch: "filterDuration",
|
|
920
|
-
label: "from",
|
|
921
|
-
type: "time"
|
|
922
|
-
},
|
|
923
|
-
{
|
|
924
|
-
filterDurationTo: 600,
|
|
925
|
-
watch: "filterDuration",
|
|
926
|
-
label: "to",
|
|
927
|
-
type: "time"
|
|
928
|
-
}
|
|
929
|
-
]
|
|
930
|
-
},
|
|
931
|
-
{
|
|
932
|
-
title: "Sort By",
|
|
933
|
-
content: [
|
|
934
|
-
{
|
|
935
|
-
"sort by views": () => {
|
|
936
|
-
}
|
|
937
|
-
},
|
|
938
|
-
{
|
|
939
|
-
"sort by duration": () => {
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
]
|
|
943
|
-
},
|
|
944
|
-
{
|
|
945
|
-
title: "Privacy Filter",
|
|
946
|
-
content: [
|
|
947
|
-
{ filterPrivate: false, label: "private" },
|
|
948
|
-
{ filterPublic: false, label: "public" },
|
|
949
|
-
{ "check access 🔓": () => {
|
|
950
|
-
} }
|
|
951
|
-
]
|
|
952
|
-
},
|
|
953
|
-
{
|
|
954
|
-
title: "Advanced",
|
|
955
|
-
content: [
|
|
956
|
-
{
|
|
957
|
-
infiniteScrollEnabled: true,
|
|
958
|
-
label: "infinite scroll"
|
|
959
|
-
},
|
|
960
|
-
{
|
|
961
|
-
autoScroll: false,
|
|
962
|
-
label: "auto scroll"
|
|
963
|
-
},
|
|
964
|
-
{
|
|
965
|
-
delay: 250,
|
|
966
|
-
label: "scroll delay"
|
|
967
|
-
},
|
|
968
|
-
{
|
|
969
|
-
writeHistory: false,
|
|
970
|
-
label: "write history"
|
|
971
|
-
}
|
|
972
|
-
]
|
|
973
|
-
},
|
|
974
|
-
{
|
|
975
|
-
title: "Badge",
|
|
976
|
-
content: [
|
|
977
|
-
{
|
|
978
|
-
text: "return `${state.$paginationOffset}/${state.$paginationLast}`",
|
|
979
|
-
vif: "return state.$paginationLast > 1"
|
|
980
|
-
}
|
|
981
|
-
]
|
|
982
|
-
}
|
|
983
|
-
];
|
|
984
|
-
|
|
985
|
-
const StoreStateDefault = {
|
|
986
|
-
enabled: true,
|
|
987
|
-
collapsed: false,
|
|
988
|
-
darkmode: true,
|
|
989
|
-
$paginationLast: 1,
|
|
990
|
-
$paginationOffset: 1
|
|
991
|
-
};
|
|
992
|
-
|
|
993
|
-
class RulesGlobal {
|
|
994
|
-
delay;
|
|
995
|
-
customGenerator;
|
|
996
|
-
getThumbUrl(thumb) {
|
|
997
|
-
return (thumb.querySelector("a[href]") || thumb).href;
|
|
998
|
-
}
|
|
999
|
-
titleSelector;
|
|
1000
|
-
uploaderSelector;
|
|
1001
|
-
durationSelector;
|
|
1002
|
-
customThumbDataSelectors;
|
|
1003
|
-
getThumbDataStrategy = "default";
|
|
1004
|
-
getThumbDataCallback;
|
|
1005
|
-
getThumbData(thumb) {
|
|
1006
|
-
let { titleSelector, uploaderSelector, durationSelector } = this;
|
|
1007
|
-
const thumbData = { title: "" };
|
|
1008
|
-
if (this.getThumbDataStrategy === "auto-text") {
|
|
1009
|
-
const text = sanitizeStr(thumb.innerText);
|
|
1010
|
-
thumbData.title = text;
|
|
1011
|
-
thumbData.duration = timeToSeconds(text.match(/\d+m|\d+:\d+/)?.[0] || "");
|
|
1012
|
-
return thumbData;
|
|
1013
|
-
}
|
|
1014
|
-
if (this.getThumbDataStrategy === "auto-select") {
|
|
1015
|
-
titleSelector = "[class *= title],[title]";
|
|
1016
|
-
durationSelector = "[class *= duration]";
|
|
1017
|
-
uploaderSelector = "[class *= uploader], [class *= user], [class *= name]";
|
|
1018
|
-
}
|
|
1019
|
-
if (this.getThumbDataStrategy === "auto-select") {
|
|
1020
|
-
const selected = querySelectorLast(thumb, titleSelector);
|
|
1021
|
-
if (selected) {
|
|
1022
|
-
thumbData.title = sanitizeStr(selected.innerText);
|
|
1023
|
-
} else {
|
|
1024
|
-
thumbData.title = sanitizeStr(thumb.innerText);
|
|
1025
|
-
}
|
|
1026
|
-
} else {
|
|
1027
|
-
thumbData.title = querySelectorText(thumb, titleSelector);
|
|
1028
|
-
}
|
|
1029
|
-
if (uploaderSelector) {
|
|
1030
|
-
const uploader = querySelectorText(thumb, uploaderSelector);
|
|
1031
|
-
thumbData.title = `${thumbData.title} user:${uploader}`;
|
|
1032
|
-
}
|
|
1033
|
-
if (durationSelector) {
|
|
1034
|
-
const duration = timeToSeconds(querySelectorText(thumb, durationSelector));
|
|
1035
|
-
thumbData.duration = duration;
|
|
1036
|
-
}
|
|
1037
|
-
this.getThumbDataCallback?.(thumb, thumbData);
|
|
1038
|
-
function getCustomThumbData(selector, type) {
|
|
1039
|
-
if (type === "boolean") {
|
|
1040
|
-
return !!thumb.querySelector(selector);
|
|
1041
|
-
}
|
|
1042
|
-
if (type === "string") {
|
|
1043
|
-
return querySelectorText(thumb, selector);
|
|
1044
|
-
}
|
|
1045
|
-
return Number.parseInt(querySelectorText(thumb, selector));
|
|
1046
|
-
}
|
|
1047
|
-
if (this.customThumbDataSelectors) {
|
|
1048
|
-
Object.entries(this.customThumbDataSelectors).forEach(([name, x]) => {
|
|
1049
|
-
const data = getCustomThumbData(x.selector, x.type);
|
|
1050
|
-
Object.assign(thumbData, { [name]: data });
|
|
1051
|
-
});
|
|
1052
|
-
}
|
|
1053
|
-
return thumbData;
|
|
1054
|
-
}
|
|
1055
|
-
getThumbImgDataAttrSelector;
|
|
1056
|
-
getThumbImgDataAttrDelete;
|
|
1057
|
-
getThumbImgDataStrategy = "default";
|
|
1058
|
-
getThumbImgData(thumb) {
|
|
1059
|
-
const result = {};
|
|
1060
|
-
if (this.getThumbImgDataStrategy === "auto") {
|
|
1061
|
-
const img = thumb.querySelector("img");
|
|
1062
|
-
if (!img) return {};
|
|
1063
|
-
result.img = img;
|
|
1064
|
-
if (typeof this.getThumbImgDataAttrSelector === "function") {
|
|
1065
|
-
result.imgSrc = this.getThumbImgDataAttrSelector(img);
|
|
1066
|
-
} else {
|
|
1067
|
-
const possibleAttrs = this.getThumbImgDataAttrSelector ? [this.getThumbImgDataAttrSelector].flat() : ["data-src", "src"];
|
|
1068
|
-
for (const attr of possibleAttrs) {
|
|
1069
|
-
const imgSrc = img.getAttribute(attr);
|
|
1070
|
-
if (imgSrc) {
|
|
1071
|
-
result.imgSrc = imgSrc;
|
|
1072
|
-
img.removeAttribute(attr);
|
|
1073
|
-
break;
|
|
1074
|
-
}
|
|
1075
|
-
}
|
|
1076
|
-
}
|
|
1077
|
-
if (this.getThumbImgDataAttrDelete) {
|
|
1078
|
-
if (this.getThumbImgDataAttrDelete === "auto") {
|
|
1079
|
-
removeClassesAndDataAttributes(img, "lazy");
|
|
1080
|
-
} else {
|
|
1081
|
-
if (this.getThumbImgDataAttrDelete.startsWith(".")) {
|
|
1082
|
-
img.classList.remove(this.getThumbImgDataAttrDelete.slice(1));
|
|
1083
|
-
} else {
|
|
1084
|
-
img.removeAttribute(this.getThumbImgDataAttrDelete);
|
|
1085
|
-
}
|
|
1086
|
-
}
|
|
1087
|
-
if (img.src.includes("data:image")) {
|
|
1088
|
-
result.img.src = "";
|
|
1089
|
-
}
|
|
1090
|
-
if (img.complete && img.naturalWidth > 0) {
|
|
1091
|
-
return {};
|
|
1092
|
-
}
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1095
|
-
return result;
|
|
1096
|
-
}
|
|
1097
|
-
containerSelector = ".container";
|
|
1098
|
-
containerSelectorLast;
|
|
1099
|
-
intersectionObservableSelector;
|
|
1100
|
-
get intersectionObservable() {
|
|
1101
|
-
return this.intersectionObservableSelector && document.querySelector(this.intersectionObservableSelector);
|
|
1102
|
-
}
|
|
1103
|
-
get observable() {
|
|
1104
|
-
return this.intersectionObservable || this.paginationStrategy.getPaginationElement();
|
|
1105
|
-
}
|
|
1106
|
-
get container() {
|
|
1107
|
-
if (typeof this.containerSelectorLast === "string") {
|
|
1108
|
-
return querySelectorLast(document, this.containerSelectorLast);
|
|
1109
|
-
}
|
|
1110
|
-
if (typeof this.containerSelector === "string") {
|
|
1111
|
-
return document.querySelector(this.containerSelector);
|
|
1112
|
-
}
|
|
1113
|
-
return this.containerSelector();
|
|
1114
|
-
}
|
|
1115
|
-
thumbsSelector = ".thumb";
|
|
1116
|
-
getThumbsStrategy = "default";
|
|
1117
|
-
getThumbsTransform;
|
|
1118
|
-
getThumbs(html) {
|
|
1119
|
-
if (!html) return [];
|
|
1120
|
-
let thumbs;
|
|
1121
|
-
if (this.getThumbsStrategy === "auto") {
|
|
1122
|
-
if (typeof this.containerSelector !== "string") return [];
|
|
1123
|
-
const container = html.querySelector(this.containerSelector);
|
|
1124
|
-
thumbs = [...container?.children || []];
|
|
1125
|
-
}
|
|
1126
|
-
thumbs = Array.from(html.querySelectorAll(this.thumbsSelector));
|
|
1127
|
-
if (typeof this.getThumbsTransform === "function") {
|
|
1128
|
-
thumbs.forEach(this.getThumbsTransform);
|
|
1129
|
-
}
|
|
1130
|
-
return thumbs;
|
|
1131
|
-
}
|
|
1132
|
-
paginationStrategyOptions = {};
|
|
1133
|
-
paginationStrategy;
|
|
1134
|
-
customDataSelectorFns = [
|
|
1135
|
-
"filterInclude",
|
|
1136
|
-
"filterExclude",
|
|
1137
|
-
"filterDuration"
|
|
1138
|
-
];
|
|
1139
|
-
animatePreview;
|
|
1140
|
-
storeOptions;
|
|
1141
|
-
createStore() {
|
|
1142
|
-
const config = { ...StoreStateDefault, ...this.storeOptions };
|
|
1143
|
-
this.store = new jabroniOutfit.JabronioStore(config);
|
|
1144
|
-
return this.store;
|
|
1145
|
-
}
|
|
1146
|
-
schemeOptions = [];
|
|
1147
|
-
createGui() {
|
|
1148
|
-
const scheme = jabroniOutfit.setupScheme(
|
|
1149
|
-
this.schemeOptions,
|
|
1150
|
-
DefaultScheme
|
|
1151
|
-
);
|
|
1152
|
-
this.gui = new jabroniOutfit.JabronioGUI(scheme, this.store);
|
|
1153
|
-
return this.gui;
|
|
1154
|
-
}
|
|
1155
|
-
store;
|
|
1156
|
-
gui;
|
|
1157
|
-
dataManager;
|
|
1158
|
-
infiniteScroller;
|
|
1159
|
-
getPaginationData;
|
|
1160
|
-
resetInfiniteScroller() {
|
|
1161
|
-
this.infiniteScroller?.dispose();
|
|
1162
|
-
if (!this.paginationStrategy.hasPagination) return;
|
|
1163
|
-
this.infiniteScroller = InfiniteScroller.create(this);
|
|
1164
|
-
}
|
|
1165
|
-
gropeStrategy = "all-in-one";
|
|
1166
|
-
gropeInit() {
|
|
1167
|
-
if (!this.gropeStrategy) return;
|
|
1168
|
-
if (this.gropeStrategy === "all-in-one") {
|
|
1169
|
-
this.dataManager?.parseData(this.container, this.container);
|
|
1170
|
-
}
|
|
1171
|
-
if (this.gropeStrategy === "all-in-all") {
|
|
1172
|
-
getCommonParents(this.getThumbs(document.body)).forEach((c) => {
|
|
1173
|
-
this.dataManager.parseData(c, c, true);
|
|
1174
|
-
});
|
|
1175
|
-
}
|
|
1176
|
-
}
|
|
1177
|
-
get isEmbedded() {
|
|
1178
|
-
return window.self !== window.top;
|
|
1179
|
-
}
|
|
1180
|
-
setupStoreListeners() {
|
|
1181
|
-
const eventsMap = {
|
|
1182
|
-
"sort by duration": {
|
|
1183
|
-
action: (direction2) => this.dataManager.sortBy("duration", direction2)
|
|
1184
|
-
}
|
|
1185
|
-
};
|
|
1186
|
-
let lastEvent;
|
|
1187
|
-
let direction = true;
|
|
1188
|
-
this.store.eventSubject.subscribe((event) => {
|
|
1189
|
-
if (event === lastEvent) {
|
|
1190
|
-
direction = !direction;
|
|
1191
|
-
} else {
|
|
1192
|
-
lastEvent = event;
|
|
1193
|
-
direction = true;
|
|
1194
|
-
}
|
|
1195
|
-
if (event in eventsMap) {
|
|
1196
|
-
const ev = eventsMap[event];
|
|
1197
|
-
ev?.action(direction);
|
|
1198
|
-
}
|
|
1199
|
-
});
|
|
1200
|
-
this.store.stateSubject.subscribe((a) => {
|
|
1201
|
-
this.dataManager.applyFilters(a);
|
|
1202
|
-
});
|
|
1203
|
-
}
|
|
1204
|
-
dataManagerOptions = {};
|
|
1205
|
-
setupDataManager() {
|
|
1206
|
-
this.dataManager = new DataManager(this);
|
|
1207
|
-
if (this.dataManagerOptions) {
|
|
1208
|
-
Object.assign(this.dataManager, this.dataManagerOptions);
|
|
1209
|
-
}
|
|
1210
|
-
return this.dataManager;
|
|
1211
|
-
}
|
|
1212
|
-
mutationObservers = [];
|
|
1213
|
-
resetOnPaginationOrContainerDeath = true;
|
|
1214
|
-
resetOn() {
|
|
1215
|
-
if (!this.resetOnPaginationOrContainerDeath) return;
|
|
1216
|
-
const observables = [
|
|
1217
|
-
this.container,
|
|
1218
|
-
this.intersectionObservable || this.paginationStrategy.getPaginationElement()
|
|
1219
|
-
].filter(Boolean);
|
|
1220
|
-
if (observables.length === 0) return;
|
|
1221
|
-
observables.forEach((o) => {
|
|
1222
|
-
const observer = waitForElementToDisappear(o, () => {
|
|
1223
|
-
this.reset();
|
|
1224
|
-
});
|
|
1225
|
-
this.mutationObservers.push(observer);
|
|
1226
|
-
});
|
|
1227
|
-
}
|
|
1228
|
-
onResetCallback;
|
|
1229
|
-
reset() {
|
|
1230
|
-
this.mutationObservers.forEach((o) => {
|
|
1231
|
-
o.disconnect();
|
|
1232
|
-
});
|
|
1233
|
-
this.mutationObservers = [];
|
|
1234
|
-
this.paginationStrategy = getPaginationStrategy(this.paginationStrategyOptions);
|
|
1235
|
-
this.setupDataManager();
|
|
1236
|
-
this.setupStoreListeners();
|
|
1237
|
-
this.resetInfiniteScroller();
|
|
1238
|
-
this.container && this.animatePreview?.(this.container);
|
|
1239
|
-
this.gropeInit();
|
|
1240
|
-
this.onResetCallback?.();
|
|
1241
|
-
this.resetOn();
|
|
1242
|
-
}
|
|
1243
|
-
constructor(options) {
|
|
1244
|
-
if (this.isEmbedded) throw Error("Embedded is not supported");
|
|
1245
|
-
Object.assign(this, options);
|
|
1246
|
-
this.paginationStrategy = getPaginationStrategy(this.paginationStrategyOptions);
|
|
1247
|
-
this.store = this.createStore();
|
|
1248
|
-
this.gui = this.createGui();
|
|
1249
|
-
this.dataManager = this.setupDataManager();
|
|
1250
|
-
this.reset();
|
|
1251
|
-
}
|
|
1252
|
-
}
|
|
1253
|
-
|
|
1254
|
-
function onPointerOverAndLeave(container, subjectSelector, onOver, onLeave) {
|
|
1255
|
-
let target;
|
|
1256
|
-
let onOverFinally;
|
|
1257
|
-
function handleLeaveEvent() {
|
|
1258
|
-
onLeave?.(target);
|
|
1259
|
-
onOverFinally?.();
|
|
1260
|
-
target = void 0;
|
|
1261
|
-
}
|
|
1262
|
-
function handleEvent(e) {
|
|
1263
|
-
const currentTarget = e.target;
|
|
1264
|
-
if (!subjectSelector(currentTarget) || target === currentTarget) return;
|
|
1265
|
-
target = currentTarget;
|
|
1266
|
-
const result = onOver(target);
|
|
1267
|
-
onOverFinally = result?.onOverCallback;
|
|
1268
|
-
const leaveSubject = result?.leaveTarget || target;
|
|
1269
|
-
leaveSubject.addEventListener("pointerleave", handleLeaveEvent, {
|
|
1270
|
-
once: true
|
|
1271
|
-
});
|
|
1272
|
-
}
|
|
1273
|
-
container.addEventListener("pointerover", handleEvent);
|
|
1274
|
-
}
|
|
1275
|
-
|
|
1276
|
-
class Tick {
|
|
1277
|
-
constructor(delay, startImmediate = true) {
|
|
1278
|
-
this.delay = delay;
|
|
1279
|
-
this.startImmediate = startImmediate;
|
|
1280
|
-
}
|
|
1281
|
-
tick;
|
|
1282
|
-
callbackFinal;
|
|
1283
|
-
start(callback, callbackFinal) {
|
|
1284
|
-
this.stop();
|
|
1285
|
-
this.callbackFinal = callbackFinal;
|
|
1286
|
-
if (this.startImmediate) callback();
|
|
1287
|
-
this.tick = window.setInterval(callback, this.delay);
|
|
1288
|
-
}
|
|
1289
|
-
stop() {
|
|
1290
|
-
if (this.tick !== void 0) {
|
|
1291
|
-
clearInterval(this.tick);
|
|
1292
|
-
this.tick = void 0;
|
|
1293
|
-
}
|
|
1294
|
-
if (this.callbackFinal) {
|
|
1295
|
-
this.callbackFinal();
|
|
1296
|
-
this.callbackFinal = void 0;
|
|
1297
|
-
}
|
|
1298
|
-
}
|
|
1299
|
-
}
|
|
1300
|
-
|
|
1301
|
-
function circularShift(n, c = 6, s = 1) {
|
|
1302
|
-
return (n + s) % c || c;
|
|
1303
|
-
}
|
|
1304
|
-
|
|
1305
82
|
const $ = _unsafeWindow.$;
|
|
1306
83
|
_GM_addStyle(`
|
|
1307
84
|
.item.private .thumb, .item .thumb.private { opacity: 1 !important; }
|
|
@@ -1314,7 +91,7 @@ async getPaginationData(url) {
|
|
|
1314
91
|
const IS_COMMUNITY_LIST = /\/members\/$/.test(location.pathname);
|
|
1315
92
|
const IS_VIDEO_PAGE = /^(\/videos)?\/\d+\//.test(location.pathname);
|
|
1316
93
|
const IS_LOGGED_IN = document.cookie.includes("kt_member");
|
|
1317
|
-
const rules = new RulesGlobal({
|
|
94
|
+
const rules = new core.RulesGlobal({
|
|
1318
95
|
containerSelector: '[id*="playlist"]:has(> .item .title),[id*="videos"]:has(> .item .title),form:has(>.item .title)',
|
|
1319
96
|
paginationStrategyOptions: {
|
|
1320
97
|
paginationSelector: ".pagination:not([id *= member])",
|
|
@@ -1357,7 +134,7 @@ async getPaginationData(url) {
|
|
|
1357
134
|
animatePreview
|
|
1358
135
|
});
|
|
1359
136
|
function animatePreview(container) {
|
|
1360
|
-
const tick = new Tick(500);
|
|
137
|
+
const tick = new utils.Tick(500);
|
|
1361
138
|
function killjquery(n = 10) {
|
|
1362
139
|
if (n > 0) {
|
|
1363
140
|
n--;
|
|
@@ -1367,9 +144,9 @@ async getPaginationData(url) {
|
|
|
1367
144
|
}
|
|
1368
145
|
killjquery();
|
|
1369
146
|
function rotateImg(src, count) {
|
|
1370
|
-
return src.replace(/(\d)(?=\.jpg$)/, (_, n) => `${circularShift(parseInt(n), count)}`);
|
|
147
|
+
return src.replace(/(\d)(?=\.jpg$)/, (_, n) => `${utils.circularShift(parseInt(n), count)}`);
|
|
1371
148
|
}
|
|
1372
|
-
onPointerOverAndLeave(
|
|
149
|
+
utils.onPointerOverAndLeave(
|
|
1373
150
|
container,
|
|
1374
151
|
(target) => target.tagName === "IMG" && target.classList.contains("thumb") && !!target.getAttribute("src") && !/data:image|avatar/.test(target.getAttribute("src")),
|
|
1375
152
|
(_target) => {
|
|
@@ -1391,13 +168,13 @@ async getPaginationData(url) {
|
|
|
1391
168
|
() => tick.stop()
|
|
1392
169
|
);
|
|
1393
170
|
}
|
|
1394
|
-
const createDownloadButton = () => downloader({
|
|
171
|
+
const createDownloadButton = () => utils.downloader({
|
|
1395
172
|
append: ".tabs-menu > ul",
|
|
1396
173
|
after: "",
|
|
1397
174
|
button: '<li><a href="#tab_comments" class="toggle-button" style="text-decoration: none;">download 📼</a></li>',
|
|
1398
175
|
cbBefore: () => $(".fp-ui").click()
|
|
1399
176
|
});
|
|
1400
|
-
const DEFAULT_FRIEND_REQUEST_FORMDATA = objectToFormData({
|
|
177
|
+
const DEFAULT_FRIEND_REQUEST_FORMDATA = utils.objectToFormData({
|
|
1401
178
|
message: "",
|
|
1402
179
|
action: "add_to_friends_complete",
|
|
1403
180
|
function: "get_block",
|
|
@@ -1421,15 +198,15 @@ async getPaginationData(url) {
|
|
|
1421
198
|
IS_COMMUNITY_LIST ? "/members/" : `/members/${id}/friends/`,
|
|
1422
199
|
location.origin
|
|
1423
200
|
);
|
|
1424
|
-
const doc = await fetchHtml(url.href);
|
|
1425
|
-
const paginationStrategy = getPaginationStrategy({
|
|
201
|
+
const doc = await utils.fetchHtml(url.href);
|
|
202
|
+
const paginationStrategy = core.getPaginationStrategy({
|
|
1426
203
|
doc,
|
|
1427
204
|
url,
|
|
1428
205
|
overwritePaginationLast: (x) => x === 9 ? 999 : x
|
|
1429
206
|
});
|
|
1430
|
-
const gen = InfiniteScroller.generatorForPaginationStrategy(paginationStrategy);
|
|
207
|
+
const gen = core.InfiniteScroller.generatorForPaginationStrategy(paginationStrategy);
|
|
1431
208
|
for (const url2 in gen) {
|
|
1432
|
-
const doc2 = await fetchHtml(url2);
|
|
209
|
+
const doc2 = await utils.fetchHtml(url2);
|
|
1433
210
|
getMemberLinks(doc2).forEach((a) => {
|
|
1434
211
|
const id2 = a.match(/\d+/)?.[0];
|
|
1435
212
|
lskdb.setKey(id2);
|
|
@@ -1449,7 +226,7 @@ async getPaginationData(url) {
|
|
|
1449
226
|
lskdb.lock(true);
|
|
1450
227
|
const urls = friendlist.map((id) => `${location.origin}/members/${id}/`);
|
|
1451
228
|
for (const url of urls) {
|
|
1452
|
-
await wait(interval);
|
|
229
|
+
await utils.wait(interval);
|
|
1453
230
|
await friendRequest(url);
|
|
1454
231
|
}
|
|
1455
232
|
lskdb.lock(false);
|
|
@@ -1458,14 +235,14 @@ async getPaginationData(url) {
|
|
|
1458
235
|
function createPrivateVideoFriendButton() {
|
|
1459
236
|
if (!document.querySelector(".no-player")) return;
|
|
1460
237
|
const member = document.querySelector(".no-player a")?.href;
|
|
1461
|
-
const button = parseHtml(
|
|
238
|
+
const button = utils.parseHtml(
|
|
1462
239
|
'<button class="friend-button"><span>Friend Request</span></button>'
|
|
1463
240
|
);
|
|
1464
241
|
document.querySelector(".no-player .message")?.append(button);
|
|
1465
242
|
button.addEventListener("click", () => friendRequest(member), { once: true });
|
|
1466
243
|
}
|
|
1467
244
|
function createFriendButton() {
|
|
1468
|
-
const button = parseHtml(
|
|
245
|
+
const button = utils.parseHtml(
|
|
1469
246
|
'<a href="#friend_everyone" class="button friend-button"><span>Friend Everyone</span></a>'
|
|
1470
247
|
);
|
|
1471
248
|
document.querySelector(".main-container-user > .headline, .headline")?.append(button);
|
|
@@ -1490,7 +267,7 @@ async getPaginationData(url) {
|
|
|
1490
267
|
async function checkPrivateVidsAccess() {
|
|
1491
268
|
const checkAccess = async (item) => {
|
|
1492
269
|
const videoURL = item.firstElementChild.href;
|
|
1493
|
-
const doc = await fetchHtml(videoURL);
|
|
270
|
+
const doc = await utils.fetchHtml(videoURL);
|
|
1494
271
|
if (!doc.querySelector(".player")) return;
|
|
1495
272
|
const haveAccess = !doc.querySelector(".no-player");
|
|
1496
273
|
if (!haveAccess && rules.store.state.autoRequestAccess) {
|
|
@@ -1508,8 +285,8 @@ async getPaginationData(url) {
|
|
|
1508
285
|
}
|
|
1509
286
|
}
|
|
1510
287
|
function getUserInfo(e) {
|
|
1511
|
-
const uploadedCount = querySelectorLastNumber("#list_videos_uploaded_videos strong", e);
|
|
1512
|
-
const friendsCount = querySelectorLastNumber("#list_members_friends .headline", e);
|
|
288
|
+
const uploadedCount = utils.querySelectorLastNumber("#list_videos_uploaded_videos strong", e);
|
|
289
|
+
const friendsCount = utils.querySelectorLastNumber("#list_members_friends .headline", e);
|
|
1513
290
|
return { uploadedCount, friendsCount };
|
|
1514
291
|
}
|
|
1515
292
|
async function acceptFriendRequest(id) {
|
|
@@ -1523,18 +300,18 @@ async getPaginationData(url) {
|
|
|
1523
300
|
body: `action=confirm_add_to_friends&message_from_user_id=${id}&function=get_block&block_id=list_messages_my_conversation_messages&confirm=Confirm&format=json&mode=async`,
|
|
1524
301
|
method: "POST"
|
|
1525
302
|
});
|
|
1526
|
-
await fetchHtml(memberUrl).then(
|
|
303
|
+
await utils.fetchHtml(memberUrl).then(
|
|
1527
304
|
(doc) => console.log("userInfo", memberUrl.href, getUserInfo(doc))
|
|
1528
305
|
);
|
|
1529
306
|
}
|
|
1530
307
|
async function clearMessages() {
|
|
1531
|
-
const pages = InfiniteScroller.generatorForPaginationStrategy(
|
|
1532
|
-
getPaginationStrategy({
|
|
308
|
+
const pages = core.InfiniteScroller.generatorForPaginationStrategy(
|
|
309
|
+
core.getPaginationStrategy({
|
|
1533
310
|
overwritePaginationLast: (x) => x === 9 ? 999 : x
|
|
1534
311
|
})
|
|
1535
312
|
);
|
|
1536
313
|
for await (const p of pages) {
|
|
1537
|
-
const doc = await fetchHtml(p.url);
|
|
314
|
+
const doc = await utils.fetchHtml(p.url);
|
|
1538
315
|
const messages = Array.from(
|
|
1539
316
|
doc.querySelectorAll(
|
|
1540
317
|
"#list_members_my_conversations_items .item > a"
|
|
@@ -1549,11 +326,11 @@ async getPaginationData(url) {
|
|
|
1549
326
|
await fetch(deleteURL);
|
|
1550
327
|
}
|
|
1551
328
|
async function getConversation(url) {
|
|
1552
|
-
const doc = await fetchHtml(url);
|
|
329
|
+
const doc = await utils.fetchHtml(url);
|
|
1553
330
|
const hasFriendRequest = !!doc.querySelector("input[value=confirm_add_to_friends]");
|
|
1554
|
-
const originalText = querySelectorText(doc, ".original-text");
|
|
331
|
+
const originalText = utils.querySelectorText(doc, ".original-text");
|
|
1555
332
|
const id = url.match(/\d+/)?.[0];
|
|
1556
|
-
const messages = querySelectorText(doc, ".list-messages");
|
|
333
|
+
const messages = utils.querySelectorText(doc, ".list-messages");
|
|
1557
334
|
return {
|
|
1558
335
|
id,
|
|
1559
336
|
hasFriendRequest,
|
|
@@ -1585,7 +362,7 @@ async getPaginationData(url) {
|
|
|
1585
362
|
createPrivateVideoFriendButton();
|
|
1586
363
|
}
|
|
1587
364
|
if (IS_MESSAGES) {
|
|
1588
|
-
const button = parseHtml("<button>clear messages</button>");
|
|
365
|
+
const button = utils.parseHtml("<button>clear messages</button>");
|
|
1589
366
|
document.querySelector(".headline")?.append(button);
|
|
1590
367
|
button.addEventListener("click", clearMessages);
|
|
1591
368
|
}
|
|
@@ -1595,4 +372,4 @@ async getPaginationData(url) {
|
|
|
1595
372
|
}
|
|
1596
373
|
});
|
|
1597
374
|
|
|
1598
|
-
})(
|
|
375
|
+
})(core, utils);
|