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.
@@ -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/jabroni-outfit@2.1.1/dist/jabroni-outfit.umd.js
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 (jabroniOutfit) {
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
- })(jabronioutfit);
375
+ })(core, utils);