pervert-monkey 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -3
- package/dist/core/pervertmonkey.core.es.d.ts +4 -4
- package/dist/core/pervertmonkey.core.es.js +24 -1
- package/dist/core/pervertmonkey.core.es.js.map +1 -1
- package/dist/core/pervertmonkey.core.umd.js +24 -1
- package/dist/core/pervertmonkey.core.umd.js.map +1 -1
- package/dist/userscripts/3hentai.user.js +1045 -1049
- package/dist/userscripts/camgirlfinder.user.js +38 -42
- package/dist/userscripts/camwhores.user.js +1429 -1433
- package/dist/userscripts/e-hentai.user.js +1077 -1081
- package/dist/userscripts/ebalka.user.js +1092 -1096
- package/dist/userscripts/eporner.user.js +1129 -1133
- package/dist/userscripts/erome.user.js +1109 -1113
- package/dist/userscripts/eroprofile.user.js +1062 -1066
- package/dist/userscripts/javhdporn.user.js +1046 -1050
- package/dist/userscripts/missav.user.js +1047 -1051
- package/dist/userscripts/motherless.user.js +1223 -1227
- package/dist/userscripts/namethatporn.user.js +1083 -1087
- package/dist/userscripts/nhentai.user.js +1123 -1127
- package/dist/userscripts/pornhub.user.js +1065 -1069
- package/dist/userscripts/spankbang.user.js +1097 -1101
- package/dist/userscripts/thisvid.user.js +2660 -0
- package/dist/userscripts/xhamster.user.js +1224 -1228
- package/dist/userscripts/xvideos.user.js +1116 -1120
- package/package.json +9 -9
- package/src/core/index.ts +4 -0
- package/src/index.ts +2 -42
- package/src/userscripts/scripts/3hentai.ts +1 -1
- package/src/userscripts/scripts/camwhores.ts +8 -9
- package/src/userscripts/scripts/e-hentai.ts +2 -2
- package/src/userscripts/scripts/ebalka.ts +2 -3
- package/src/userscripts/scripts/eporner.ts +2 -2
- package/src/userscripts/scripts/erome.ts +1 -1
- package/src/userscripts/scripts/eroprofile.ts +1 -1
- package/src/userscripts/scripts/javhdporn.ts +1 -1
- package/src/userscripts/scripts/missav.ts +1 -1
- package/src/userscripts/scripts/motherless.ts +2 -4
- package/src/userscripts/scripts/namethatporn.ts +1 -1
- package/src/userscripts/scripts/nhentai.ts +2 -2
- package/src/userscripts/scripts/pornhub.ts +1 -1
- package/src/userscripts/scripts/spankbang.ts +4 -5
- package/src/userscripts/scripts/xhamster.ts +5 -5
- package/src/userscripts/scripts/xvideos.ts +2 -3
- package/src/utils/index.ts +39 -0
- package/src/vite-env.d.ts +1 -1
- package/src/userscripts/scripts/thisvid.ts +0 -716
|
@@ -17,1229 +17,1225 @@
|
|
|
17
17
|
// @run-at document-idle
|
|
18
18
|
// ==/UserScript==
|
|
19
19
|
|
|
20
|
-
(function () {
|
|
20
|
+
(function (jabroniOutfit) {
|
|
21
21
|
'use strict';
|
|
22
22
|
|
|
23
|
-
(
|
|
23
|
+
var _GM_addStyle = (() => typeof GM_addStyle != "undefined" ? GM_addStyle : undefined)();
|
|
24
|
+
var _unsafeWindow = (() => typeof unsafeWindow != "undefined" ? unsafeWindow : undefined)();
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
26
|
+
function memoize(fn) {
|
|
27
|
+
const cache = new Map();
|
|
28
|
+
const memoizedFunction = ((...args) => {
|
|
29
|
+
const key = JSON.stringify(args);
|
|
30
|
+
if (cache.has(key)) {
|
|
31
|
+
return cache.get(key);
|
|
32
|
+
}
|
|
33
|
+
const result = fn(...args);
|
|
34
|
+
cache.set(key, result);
|
|
35
|
+
return result;
|
|
36
|
+
});
|
|
37
|
+
return memoizedFunction;
|
|
38
|
+
}
|
|
34
39
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
});
|
|
42
|
-
observer.observe(document.body, { childList: true, subtree: true });
|
|
43
|
-
return observer;
|
|
44
|
-
}
|
|
40
|
+
function splitWith(s, c = ",") {
|
|
41
|
+
return s.split(c).map((s2) => s2.trim()).filter(Boolean);
|
|
42
|
+
}
|
|
43
|
+
function sanitizeStr(s) {
|
|
44
|
+
return s?.replace(/\n|\t/g, " ").replace(/ {2,}/g, " ").trim() || "";
|
|
45
|
+
}
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
function querySelectorText(e, selector) {
|
|
51
|
-
if (typeof selector !== "string") return "";
|
|
52
|
-
const text = e.querySelector(selector)?.innerText || "";
|
|
53
|
-
return sanitizeStr(text);
|
|
54
|
-
}
|
|
55
|
-
function parseHtml(html) {
|
|
56
|
-
const parsed = new DOMParser().parseFromString(html, "text/html").body;
|
|
57
|
-
if (parsed.children.length > 1) return parsed;
|
|
58
|
-
return parsed.firstElementChild;
|
|
59
|
-
}
|
|
60
|
-
function removeClassesAndDataAttributes(element, keyword) {
|
|
61
|
-
Array.from(element.classList).forEach((className) => {
|
|
62
|
-
if (className.includes(keyword)) {
|
|
63
|
-
element.classList.remove(className);
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
Array.from(element.attributes).forEach((attr) => {
|
|
67
|
-
if (attr.name.startsWith("data-") && attr.name.includes(keyword)) {
|
|
68
|
-
element.removeAttribute(attr.name);
|
|
69
|
-
}
|
|
70
|
-
});
|
|
47
|
+
class RegexFilter {
|
|
48
|
+
regexes;
|
|
49
|
+
constructor(str, flags = "gi") {
|
|
50
|
+
this.regexes = memoize(this.compileSearchRegex)(str, flags);
|
|
71
51
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (options.className) {
|
|
82
|
-
const ca = a.className;
|
|
83
|
-
const cb = b.className;
|
|
84
|
-
if (!(ca.length > cb.length ? ca.includes(cb) : cb.includes(ca))) {
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
52
|
+
compileSearchRegex(str, flags) {
|
|
53
|
+
try {
|
|
54
|
+
if (str.startsWith("r:")) return [new RegExp(str.slice(2), flags)];
|
|
55
|
+
const regexes = splitWith(str).map(
|
|
56
|
+
(s) => s.replace(/f:(\w+)/g, (_, w) => `(^|\\ |,)${w}($|\\ |,)`)
|
|
57
|
+
).map((_) => new RegExp(_, flags));
|
|
58
|
+
return regexes;
|
|
59
|
+
} catch (_) {
|
|
60
|
+
return [];
|
|
87
61
|
}
|
|
88
|
-
return true;
|
|
89
62
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const pad = (num) => num.toString().padStart(2, "0");
|
|
93
|
-
const h = timeStr.match(/(\d+)\s*h/)?.[1] || "0";
|
|
94
|
-
const m = timeStr.match(/(\d+)\s*mi?n/)?.[1] || "0";
|
|
95
|
-
const s = timeStr.match(/(\d+)\s*sec/)?.[1] || "0";
|
|
96
|
-
return `${pad(+h)}:${pad(+m)}:${pad(+s)}`;
|
|
63
|
+
hasEvery(str) {
|
|
64
|
+
return this.regexes.every((r) => r.test(str));
|
|
97
65
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
return normalized.split(":").reverse().reduce((total, unit, index) => total + parseInt(unit, 10) * 60 ** index, 0);
|
|
66
|
+
hasNone(str) {
|
|
67
|
+
return this.regexes.every((r) => !r.test(str));
|
|
101
68
|
}
|
|
69
|
+
}
|
|
102
70
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
if (parsed) {
|
|
109
|
-
const [, key, value] = parsed;
|
|
110
|
-
if (value) {
|
|
111
|
-
key.split("+").forEach((p) => {
|
|
112
|
-
acc[p] = value;
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
return acc;
|
|
117
|
-
},
|
|
118
|
-
{}
|
|
119
|
-
);
|
|
71
|
+
class DataFilter {
|
|
72
|
+
constructor(rules) {
|
|
73
|
+
this.rules = rules;
|
|
74
|
+
this.registerFilters(rules.customDataSelectorFns);
|
|
75
|
+
this.applyCSSFilters();
|
|
120
76
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const memoizedFunction = ((...args) => {
|
|
125
|
-
const key = JSON.stringify(args);
|
|
126
|
-
if (cache.has(key)) {
|
|
127
|
-
return cache.get(key);
|
|
128
|
-
}
|
|
129
|
-
const result = fn(...args);
|
|
130
|
-
cache.set(key, result);
|
|
131
|
-
return result;
|
|
132
|
-
});
|
|
133
|
-
return memoizedFunction;
|
|
77
|
+
filters = new Map();
|
|
78
|
+
static isFiltered(el) {
|
|
79
|
+
return el.className.includes("filter-");
|
|
134
80
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
try {
|
|
143
|
-
if (str.startsWith("r:")) return [new RegExp(str.slice(2), flags)];
|
|
144
|
-
const regexes = splitWith(str).map(
|
|
145
|
-
(s) => s.replace(/f:(\w+)/g, (_, w) => `(^|\\ |,)${w}($|\\ |,)`)
|
|
146
|
-
).map((_) => new RegExp(_, flags));
|
|
147
|
-
return regexes;
|
|
148
|
-
} catch (_) {
|
|
149
|
-
return [];
|
|
81
|
+
applyCSSFilters(wrapper) {
|
|
82
|
+
this.filters.forEach((_, name) => {
|
|
83
|
+
const cssRule = `.filter-${name} { display: none !important; }`;
|
|
84
|
+
if (wrapper) {
|
|
85
|
+
_GM_addStyle(wrapper(cssRule));
|
|
86
|
+
} else {
|
|
87
|
+
_GM_addStyle(cssRule);
|
|
150
88
|
}
|
|
151
|
-
}
|
|
152
|
-
hasEvery(str) {
|
|
153
|
-
return this.regexes.every((r) => r.test(str));
|
|
154
|
-
}
|
|
155
|
-
hasNone(str) {
|
|
156
|
-
return this.regexes.every((r) => !r.test(str));
|
|
157
|
-
}
|
|
89
|
+
});
|
|
158
90
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}
|
|
166
|
-
filters = new Map();
|
|
167
|
-
static isFiltered(el) {
|
|
168
|
-
return el.className.includes("filter-");
|
|
169
|
-
}
|
|
170
|
-
applyCSSFilters(wrapper) {
|
|
171
|
-
this.filters.forEach((_, name) => {
|
|
172
|
-
const cssRule = `.filter-${name} { display: none !important; }`;
|
|
173
|
-
if (wrapper) {
|
|
174
|
-
_GM_addStyle(wrapper(cssRule));
|
|
175
|
-
} else {
|
|
176
|
-
_GM_addStyle(cssRule);
|
|
177
|
-
}
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
customDataSelectorFns = {};
|
|
181
|
-
registerFilters(customFilters) {
|
|
182
|
-
customFilters.forEach((o) => {
|
|
183
|
-
if (typeof o === "string") {
|
|
184
|
-
this.customDataSelectorFns[o] = DataFilter.customDataSelectorFnsDefault[o];
|
|
185
|
-
this.registerFilter(o);
|
|
186
|
-
} else {
|
|
187
|
-
const k = Object.keys(o)[0];
|
|
188
|
-
this.customDataSelectorFns[k] = o[k];
|
|
189
|
-
this.registerFilter(k);
|
|
190
|
-
}
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
customSelectorParser(name, selector) {
|
|
194
|
-
if ("handle" in selector) {
|
|
195
|
-
return selector;
|
|
91
|
+
customDataSelectorFns = {};
|
|
92
|
+
registerFilters(customFilters) {
|
|
93
|
+
customFilters.forEach((o) => {
|
|
94
|
+
if (typeof o === "string") {
|
|
95
|
+
this.customDataSelectorFns[o] = DataFilter.customDataSelectorFnsDefault[o];
|
|
96
|
+
this.registerFilter(o);
|
|
196
97
|
} else {
|
|
197
|
-
|
|
98
|
+
const k = Object.keys(o)[0];
|
|
99
|
+
this.customDataSelectorFns[k] = o[k];
|
|
100
|
+
this.registerFilter(k);
|
|
198
101
|
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
customSelectorParser(name, selector) {
|
|
105
|
+
if ("handle" in selector) {
|
|
106
|
+
return selector;
|
|
107
|
+
} else {
|
|
108
|
+
return { handle: selector, deps: [name] };
|
|
199
109
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
110
|
+
}
|
|
111
|
+
registerFilter(customSelectorName) {
|
|
112
|
+
const handler = this.customSelectorParser(
|
|
113
|
+
customSelectorName,
|
|
114
|
+
this.customDataSelectorFns[customSelectorName]
|
|
115
|
+
);
|
|
116
|
+
const tag = `filter-${customSelectorName}`;
|
|
117
|
+
[customSelectorName, ...handler.deps || []]?.forEach((name) => {
|
|
118
|
+
Object.assign(this.filterMapping, { [name]: customSelectorName });
|
|
119
|
+
});
|
|
120
|
+
const fn = () => {
|
|
121
|
+
const preDefined = handler.$preDefine?.(this.rules.store.state);
|
|
122
|
+
return (v) => {
|
|
123
|
+
const condition = handler.handle(v, this.rules.store.state, preDefined);
|
|
124
|
+
return {
|
|
125
|
+
condition,
|
|
126
|
+
tag
|
|
217
127
|
};
|
|
218
128
|
};
|
|
219
|
-
this.filters.set(customSelectorName, fn);
|
|
220
|
-
}
|
|
221
|
-
filterMapping = {};
|
|
222
|
-
selectFilters(filters) {
|
|
223
|
-
const selectedFilters = Object.keys(filters).filter((k) => k in this.filterMapping).map((k) => this.filterMapping[k]).map((k) => this.filters.get(k));
|
|
224
|
-
return selectedFilters;
|
|
225
|
-
}
|
|
226
|
-
static customDataSelectorFnsDefault = {
|
|
227
|
-
filterDuration: {
|
|
228
|
-
handle(el, state, notInRange) {
|
|
229
|
-
return state.filterDuration && notInRange(el.duration);
|
|
230
|
-
},
|
|
231
|
-
$preDefine: (state) => {
|
|
232
|
-
const from = state.filterDurationFrom;
|
|
233
|
-
const to = state.filterDurationTo;
|
|
234
|
-
function notInRange(d) {
|
|
235
|
-
return d < from || d > to;
|
|
236
|
-
}
|
|
237
|
-
return notInRange;
|
|
238
|
-
},
|
|
239
|
-
deps: ["filterDurationFrom", "filterDurationTo"]
|
|
240
|
-
},
|
|
241
|
-
filterExclude: {
|
|
242
|
-
handle(el, state, searchFilter) {
|
|
243
|
-
if (!state.filterExclude) return false;
|
|
244
|
-
return !searchFilter.hasNone(el.title);
|
|
245
|
-
},
|
|
246
|
-
$preDefine: (state) => new RegexFilter(state.filterExcludeWords),
|
|
247
|
-
deps: ["filterExcludeWords"]
|
|
248
|
-
},
|
|
249
|
-
filterInclude: {
|
|
250
|
-
handle(el, state, searchFilter) {
|
|
251
|
-
if (!state.filterInclude) return false;
|
|
252
|
-
return !searchFilter.hasEvery(el.title);
|
|
253
|
-
},
|
|
254
|
-
$preDefine: (state) => new RegexFilter(state.filterIncludeWords),
|
|
255
|
-
deps: ["filterIncludeWords"]
|
|
256
|
-
}
|
|
257
129
|
};
|
|
130
|
+
this.filters.set(customSelectorName, fn);
|
|
258
131
|
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
132
|
+
filterMapping = {};
|
|
133
|
+
selectFilters(filters) {
|
|
134
|
+
const selectedFilters = Object.keys(filters).filter((k) => k in this.filterMapping).map((k) => this.filterMapping[k]).map((k) => this.filters.get(k));
|
|
135
|
+
return selectedFilters;
|
|
136
|
+
}
|
|
137
|
+
static customDataSelectorFnsDefault = {
|
|
138
|
+
filterDuration: {
|
|
139
|
+
handle(el, state, notInRange) {
|
|
140
|
+
return state.filterDuration && notInRange(el.duration);
|
|
141
|
+
},
|
|
142
|
+
$preDefine: (state) => {
|
|
143
|
+
const from = state.filterDurationFrom;
|
|
144
|
+
const to = state.filterDurationTo;
|
|
145
|
+
function notInRange(d) {
|
|
146
|
+
return d < from || d > to;
|
|
267
147
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
148
|
+
return notInRange;
|
|
149
|
+
},
|
|
150
|
+
deps: ["filterDurationFrom", "filterDurationTo"]
|
|
151
|
+
},
|
|
152
|
+
filterExclude: {
|
|
153
|
+
handle(el, state, searchFilter) {
|
|
154
|
+
if (!state.filterExclude) return false;
|
|
155
|
+
return !searchFilter.hasNone(el.title);
|
|
156
|
+
},
|
|
157
|
+
$preDefine: (state) => new RegexFilter(state.filterExcludeWords),
|
|
158
|
+
deps: ["filterExcludeWords"]
|
|
159
|
+
},
|
|
160
|
+
filterInclude: {
|
|
161
|
+
handle(el, state, searchFilter) {
|
|
162
|
+
if (!state.filterInclude) return false;
|
|
163
|
+
return !searchFilter.hasEvery(el.title);
|
|
164
|
+
},
|
|
165
|
+
$preDefine: (state) => new RegexFilter(state.filterIncludeWords),
|
|
166
|
+
deps: ["filterIncludeWords"]
|
|
275
167
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
target.src = target.getAttribute(this.attributeName);
|
|
279
|
-
target.removeAttribute(this.attributeName);
|
|
280
|
-
};
|
|
281
|
-
}
|
|
168
|
+
};
|
|
169
|
+
}
|
|
282
170
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
observer;
|
|
289
|
-
timeout;
|
|
290
|
-
observe(target) {
|
|
291
|
-
this.observer.observe(target);
|
|
292
|
-
}
|
|
293
|
-
throttle(target, throttleTime) {
|
|
294
|
-
this.observer.unobserve(target);
|
|
295
|
-
this.timeout = window.setTimeout(() => this.observer.observe(target), throttleTime);
|
|
171
|
+
function waitForElementToDisappear(observable, callback) {
|
|
172
|
+
const observer = new MutationObserver((_mutations) => {
|
|
173
|
+
if (!observable.isConnected) {
|
|
174
|
+
observer.disconnect();
|
|
175
|
+
callback();
|
|
296
176
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
177
|
+
});
|
|
178
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
179
|
+
return observer;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function querySelectorLast(root = document, selector) {
|
|
183
|
+
const nodes = root.querySelectorAll(selector);
|
|
184
|
+
return nodes.length > 0 ? nodes[nodes.length - 1] : void 0;
|
|
185
|
+
}
|
|
186
|
+
function querySelectorText(e, selector) {
|
|
187
|
+
if (typeof selector !== "string") return "";
|
|
188
|
+
const text = e.querySelector(selector)?.innerText || "";
|
|
189
|
+
return sanitizeStr(text);
|
|
190
|
+
}
|
|
191
|
+
function parseHtml(html) {
|
|
192
|
+
const parsed = new DOMParser().parseFromString(html, "text/html").body;
|
|
193
|
+
if (parsed.children.length > 1) return parsed;
|
|
194
|
+
return parsed.firstElementChild;
|
|
195
|
+
}
|
|
196
|
+
function removeClassesAndDataAttributes(element, keyword) {
|
|
197
|
+
Array.from(element.classList).forEach((className) => {
|
|
198
|
+
if (className.includes(keyword)) {
|
|
199
|
+
element.classList.remove(className);
|
|
303
200
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
201
|
+
});
|
|
202
|
+
Array.from(element.attributes).forEach((attr) => {
|
|
203
|
+
if (attr.name.startsWith("data-") && attr.name.includes(keyword)) {
|
|
204
|
+
element.removeAttribute(attr.name);
|
|
307
205
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
function getCommonParents(elements) {
|
|
209
|
+
const parents = Array.from(elements).map((el) => el.parentElement).filter((parent) => parent !== null);
|
|
210
|
+
return [...new Set(parents)];
|
|
211
|
+
}
|
|
212
|
+
function checkHomogenity(a, b, options) {
|
|
213
|
+
if (!a || !b) return false;
|
|
214
|
+
if (options.id) {
|
|
215
|
+
if (a.id !== b.id) return false;
|
|
216
|
+
}
|
|
217
|
+
if (options.className) {
|
|
218
|
+
const ca = a.className;
|
|
219
|
+
const cb = b.className;
|
|
220
|
+
if (!(ca.length > cb.length ? ca.includes(cb) : cb.includes(ca))) {
|
|
221
|
+
return false;
|
|
315
222
|
}
|
|
316
223
|
}
|
|
224
|
+
return true;
|
|
225
|
+
}
|
|
317
226
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
(target) => !DataFilter.isFiltered(target)
|
|
326
|
-
);
|
|
327
|
-
dataFilter;
|
|
328
|
-
applyFilters = async (filters = {}, offset = 0) => {
|
|
329
|
-
const filtersToApply = this.dataFilter.selectFilters(filters);
|
|
330
|
-
if (filtersToApply.length === 0) return;
|
|
331
|
-
const iterator = this.data.values().drop(offset);
|
|
332
|
-
let finished = false;
|
|
333
|
-
await new Promise((resolve) => {
|
|
334
|
-
function runBatch(deadline) {
|
|
335
|
-
const updates = [];
|
|
336
|
-
while (deadline.timeRemaining() > 0) {
|
|
337
|
-
const { value, done } = iterator.next();
|
|
338
|
-
finished = !!done;
|
|
339
|
-
if (done) break;
|
|
340
|
-
for (const f of filtersToApply) {
|
|
341
|
-
const { tag, condition } = f()(value);
|
|
342
|
-
updates.push({ e: value.element, tag, condition });
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
if (updates.length > 0) {
|
|
346
|
-
requestAnimationFrame(() => {
|
|
347
|
-
updates.forEach((u) => {
|
|
348
|
-
u.e.classList.toggle(u.tag, u.condition);
|
|
349
|
-
});
|
|
350
|
-
});
|
|
351
|
-
}
|
|
352
|
-
if (!finished) {
|
|
353
|
-
requestIdleCallback(runBatch);
|
|
354
|
-
} else {
|
|
355
|
-
resolve(true);
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
requestIdleCallback(runBatch);
|
|
359
|
-
});
|
|
360
|
-
};
|
|
361
|
-
filterAll = async (offset) => {
|
|
362
|
-
const keys = Array.from(this.dataFilter.filters.keys());
|
|
363
|
-
const filters = Object.fromEntries(
|
|
364
|
-
keys.map((k) => [k, this.rules.store.state[k]])
|
|
365
|
-
);
|
|
366
|
-
await this.applyFilters(filters, offset);
|
|
367
|
-
};
|
|
368
|
-
parseDataParentHomogenity;
|
|
369
|
-
parseData = (html, container, removeDuplicates = false, shouldLazify = true) => {
|
|
370
|
-
const thumbs = this.rules.getThumbs(html);
|
|
371
|
-
const dataOffset = this.data.size;
|
|
372
|
-
const fragment = document.createDocumentFragment();
|
|
373
|
-
const parent = container || this.rules.container;
|
|
374
|
-
const homogenity = !!this.parseDataParentHomogenity;
|
|
375
|
-
for (const thumbElement of thumbs) {
|
|
376
|
-
const url = this.rules.getThumbUrl(thumbElement);
|
|
377
|
-
if (!url || this.data.has(url) || parent !== container && parent?.contains(thumbElement) || homogenity && !checkHomogenity(
|
|
378
|
-
parent,
|
|
379
|
-
thumbElement.parentElement,
|
|
380
|
-
this.parseDataParentHomogenity
|
|
381
|
-
)) {
|
|
382
|
-
if (removeDuplicates) thumbElement.remove();
|
|
383
|
-
continue;
|
|
384
|
-
}
|
|
385
|
-
const data = this.rules.getThumbData(thumbElement);
|
|
386
|
-
this.data.set(url, { element: thumbElement, ...data });
|
|
387
|
-
if (shouldLazify) {
|
|
388
|
-
const { img, imgSrc } = this.rules.getThumbImgData(thumbElement);
|
|
389
|
-
this.lazyImgLoader.lazify(thumbElement, img, imgSrc);
|
|
390
|
-
}
|
|
391
|
-
fragment.append(thumbElement);
|
|
227
|
+
class LazyImgLoader {
|
|
228
|
+
lazyImgObserver;
|
|
229
|
+
attributeName = "data-lazy-load";
|
|
230
|
+
constructor(shouldDelazify) {
|
|
231
|
+
this.lazyImgObserver = new Observer((target) => {
|
|
232
|
+
if (shouldDelazify(target)) {
|
|
233
|
+
this.delazify(target);
|
|
392
234
|
}
|
|
393
|
-
|
|
394
|
-
requestAnimationFrame(() => {
|
|
395
|
-
parent.appendChild(fragment);
|
|
396
|
-
});
|
|
397
|
-
});
|
|
398
|
-
};
|
|
399
|
-
sortBy(key, direction = true) {
|
|
400
|
-
if (this.data.size < 2) return;
|
|
401
|
-
let sorted = this.data.values().toArray().sort((a, b) => {
|
|
402
|
-
return a[key] - b[key];
|
|
403
|
-
});
|
|
404
|
-
if (!direction) sorted = sorted.reverse();
|
|
405
|
-
const container = sorted[0].element.parentElement;
|
|
406
|
-
container.style.visibility = "hidden";
|
|
407
|
-
sorted.forEach((s) => {
|
|
408
|
-
container.append(s.element);
|
|
409
|
-
});
|
|
410
|
-
container.style.visibility = "visible";
|
|
411
|
-
}
|
|
235
|
+
});
|
|
412
236
|
}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
237
|
+
lazify(_target, img, imgSrc) {
|
|
238
|
+
if (!img || !imgSrc) return;
|
|
239
|
+
img.setAttribute(this.attributeName, imgSrc);
|
|
240
|
+
img.src = "";
|
|
241
|
+
this.lazyImgObserver.observe(img);
|
|
416
242
|
}
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
"AppleWebKit/537.36 (KHTML, like Gecko)",
|
|
422
|
-
"Chrome/114.0.0.0 Mobile Safari/537.36"
|
|
423
|
-
].join(" ")
|
|
243
|
+
delazify = (target) => {
|
|
244
|
+
this.lazyImgObserver.observer.unobserve(target);
|
|
245
|
+
target.src = target.getAttribute(this.attributeName);
|
|
246
|
+
target.removeAttribute(this.attributeName);
|
|
424
247
|
};
|
|
425
|
-
|
|
426
|
-
const requestInit = options.init || {};
|
|
427
|
-
if (options.mobile) {
|
|
428
|
-
Object.assign(requestInit, { headers: new Headers(MOBILE_UA) });
|
|
429
|
-
}
|
|
430
|
-
const r = await fetch(input, requestInit).then((r2) => r2);
|
|
431
|
-
return parseHtml(await r.text());
|
|
432
|
-
}
|
|
433
|
-
const fetchHtml = (input) => fetchWith(input, { });
|
|
248
|
+
}
|
|
434
249
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
250
|
+
class Observer {
|
|
251
|
+
constructor(callback) {
|
|
252
|
+
this.callback = callback;
|
|
253
|
+
this.observer = new IntersectionObserver(this.handleIntersection.bind(this));
|
|
254
|
+
}
|
|
255
|
+
observer;
|
|
256
|
+
timeout;
|
|
257
|
+
observe(target) {
|
|
258
|
+
this.observer.observe(target);
|
|
259
|
+
}
|
|
260
|
+
throttle(target, throttleTime) {
|
|
261
|
+
this.observer.unobserve(target);
|
|
262
|
+
this.timeout = window.setTimeout(() => this.observer.observe(target), throttleTime);
|
|
263
|
+
}
|
|
264
|
+
handleIntersection(entries) {
|
|
265
|
+
for (const entry of entries) {
|
|
266
|
+
if (entry.isIntersecting) {
|
|
267
|
+
this.callback(entry.target);
|
|
448
268
|
}
|
|
449
|
-
this.paginationGenerator = this.rules.customGenerator || InfiniteScroller.generatorForPaginationStrategy(this.rules.paginationStrategy);
|
|
450
|
-
this.setObserver(this.rules.observable);
|
|
451
|
-
this.setAutoScroll();
|
|
452
|
-
}
|
|
453
|
-
dispose() {
|
|
454
|
-
if (this.observer) this.observer.dispose();
|
|
455
269
|
}
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
270
|
+
}
|
|
271
|
+
dispose() {
|
|
272
|
+
if (this.timeout) clearTimeout(this.timeout);
|
|
273
|
+
this.observer.disconnect();
|
|
274
|
+
}
|
|
275
|
+
static observeWhile(target, callback, throttleTime) {
|
|
276
|
+
const observer_ = new Observer(async (target2) => {
|
|
277
|
+
const condition = await callback();
|
|
278
|
+
if (condition) observer_.throttle(target2, throttleTime);
|
|
279
|
+
});
|
|
280
|
+
observer_.observe(target);
|
|
281
|
+
return observer_;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
class DataManager {
|
|
286
|
+
constructor(rules) {
|
|
287
|
+
this.rules = rules;
|
|
288
|
+
this.dataFilter = new DataFilter(this.rules);
|
|
289
|
+
}
|
|
290
|
+
data = new Map();
|
|
291
|
+
lazyImgLoader = new LazyImgLoader(
|
|
292
|
+
(target) => !DataFilter.isFiltered(target)
|
|
293
|
+
);
|
|
294
|
+
dataFilter;
|
|
295
|
+
applyFilters = async (filters = {}, offset = 0) => {
|
|
296
|
+
const filtersToApply = this.dataFilter.selectFilters(filters);
|
|
297
|
+
if (filtersToApply.length === 0) return;
|
|
298
|
+
const iterator = this.data.values().drop(offset);
|
|
299
|
+
let finished = false;
|
|
300
|
+
await new Promise((resolve) => {
|
|
301
|
+
function runBatch(deadline) {
|
|
302
|
+
const updates = [];
|
|
303
|
+
while (deadline.timeRemaining() > 0) {
|
|
304
|
+
const { value, done } = iterator.next();
|
|
305
|
+
finished = !!done;
|
|
306
|
+
if (done) break;
|
|
307
|
+
for (const f of filtersToApply) {
|
|
308
|
+
const { tag, condition } = f()(value);
|
|
309
|
+
updates.push({ e: value.element, tag, condition });
|
|
310
|
+
}
|
|
482
311
|
}
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
312
|
+
if (updates.length > 0) {
|
|
313
|
+
requestAnimationFrame(() => {
|
|
314
|
+
updates.forEach((u) => {
|
|
315
|
+
u.e.classList.toggle(u.tag, u.condition);
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
if (!finished) {
|
|
320
|
+
requestIdleCallback(runBatch);
|
|
321
|
+
} else {
|
|
322
|
+
resolve(true);
|
|
488
323
|
}
|
|
489
|
-
});
|
|
490
|
-
}
|
|
491
|
-
generatorConsumer = async () => {
|
|
492
|
-
if (!this.enabled) return false;
|
|
493
|
-
const {
|
|
494
|
-
value: { url, offset },
|
|
495
|
-
done
|
|
496
|
-
} = await this.paginationGenerator.next();
|
|
497
|
-
if (!done && url) {
|
|
498
|
-
await this.doScroll(url, offset);
|
|
499
324
|
}
|
|
500
|
-
|
|
501
|
-
};
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
325
|
+
requestIdleCallback(runBatch);
|
|
326
|
+
});
|
|
327
|
+
};
|
|
328
|
+
filterAll = async (offset) => {
|
|
329
|
+
const keys = Array.from(this.dataFilter.filters.keys());
|
|
330
|
+
const filters = Object.fromEntries(
|
|
331
|
+
keys.map((k) => [k, this.rules.store.state[k]])
|
|
332
|
+
);
|
|
333
|
+
await this.applyFilters(filters, offset);
|
|
334
|
+
};
|
|
335
|
+
parseDataParentHomogenity;
|
|
336
|
+
parseData = (html, container, removeDuplicates = false, shouldLazify = true) => {
|
|
337
|
+
const thumbs = this.rules.getThumbs(html);
|
|
338
|
+
const dataOffset = this.data.size;
|
|
339
|
+
const fragment = document.createDocumentFragment();
|
|
340
|
+
const parent = container || this.rules.container;
|
|
341
|
+
const homogenity = !!this.parseDataParentHomogenity;
|
|
342
|
+
for (const thumbElement of thumbs) {
|
|
343
|
+
const url = this.rules.getThumbUrl(thumbElement);
|
|
344
|
+
if (!url || this.data.has(url) || parent !== container && parent?.contains(thumbElement) || homogenity && !checkHomogenity(
|
|
345
|
+
parent,
|
|
346
|
+
thumbElement.parentElement,
|
|
347
|
+
this.parseDataParentHomogenity
|
|
348
|
+
)) {
|
|
349
|
+
if (removeDuplicates) thumbElement.remove();
|
|
350
|
+
continue;
|
|
514
351
|
}
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
for (let offset = _offset; offset <= end; offset++) {
|
|
521
|
-
const url = await urlGenerator(offset);
|
|
522
|
-
yield { url, offset };
|
|
352
|
+
const data = this.rules.getThumbData(thumbElement);
|
|
353
|
+
this.data.set(url, { element: thumbElement, ...data });
|
|
354
|
+
if (shouldLazify) {
|
|
355
|
+
const { img, imgSrc } = this.rules.getThumbImgData(thumbElement);
|
|
356
|
+
this.lazyImgLoader.lazify(thumbElement, img, imgSrc);
|
|
523
357
|
}
|
|
358
|
+
fragment.append(thumbElement);
|
|
524
359
|
}
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
const infiniteScroller = new InfiniteScroller({
|
|
529
|
-
enabled,
|
|
530
|
-
parseData: rules.dataManager.parseData,
|
|
531
|
-
rules
|
|
532
|
-
}).onScroll(({ paginationOffset }) => {
|
|
533
|
-
rules.store.state.$paginationOffset = paginationOffset;
|
|
534
|
-
}, true);
|
|
535
|
-
rules.store.stateSubject.subscribe(() => {
|
|
536
|
-
infiniteScroller.enabled = rules.store.state.infiniteScrollEnabled;
|
|
360
|
+
this.filterAll(dataOffset).then(() => {
|
|
361
|
+
requestAnimationFrame(() => {
|
|
362
|
+
parent.appendChild(fragment);
|
|
537
363
|
});
|
|
538
|
-
|
|
539
|
-
|
|
364
|
+
});
|
|
365
|
+
};
|
|
366
|
+
sortBy(key, direction = true) {
|
|
367
|
+
if (this.data.size < 2) return;
|
|
368
|
+
let sorted = this.data.values().toArray().sort((a, b) => {
|
|
369
|
+
return a[key] - b[key];
|
|
370
|
+
});
|
|
371
|
+
if (!direction) sorted = sorted.reverse();
|
|
372
|
+
const container = sorted[0].element.parentElement;
|
|
373
|
+
container.style.visibility = "hidden";
|
|
374
|
+
sorted.forEach((s) => {
|
|
375
|
+
container.append(s.element);
|
|
376
|
+
});
|
|
377
|
+
container.style.visibility = "visible";
|
|
540
378
|
}
|
|
379
|
+
}
|
|
541
380
|
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
collapsed: true,
|
|
546
|
-
content: [
|
|
547
|
-
{ filterExclude: false, label: "exclude" },
|
|
548
|
-
{
|
|
549
|
-
filterExcludeWords: "",
|
|
550
|
-
label: "keywords",
|
|
551
|
-
watch: "filterExclude",
|
|
552
|
-
placeholder: "word, f:full_word, r:RegEx..."
|
|
553
|
-
},
|
|
554
|
-
{ filterInclude: false, label: "include" },
|
|
555
|
-
{
|
|
556
|
-
filterIncludeWords: "",
|
|
557
|
-
label: "keywords",
|
|
558
|
-
watch: "filterInclude",
|
|
559
|
-
placeholder: "word, f:full_word, r:RegEx..."
|
|
560
|
-
}
|
|
561
|
-
]
|
|
562
|
-
},
|
|
563
|
-
{
|
|
564
|
-
title: "Duration Filter",
|
|
565
|
-
collapsed: true,
|
|
566
|
-
content: [
|
|
567
|
-
{ filterDuration: false, label: "enable" },
|
|
568
|
-
{
|
|
569
|
-
filterDurationFrom: 0,
|
|
570
|
-
watch: "filterDuration",
|
|
571
|
-
label: "from",
|
|
572
|
-
type: "time"
|
|
573
|
-
},
|
|
574
|
-
{
|
|
575
|
-
filterDurationTo: 600,
|
|
576
|
-
watch: "filterDuration",
|
|
577
|
-
label: "to",
|
|
578
|
-
type: "time"
|
|
579
|
-
}
|
|
580
|
-
]
|
|
581
|
-
},
|
|
582
|
-
{
|
|
583
|
-
title: "Sort By",
|
|
584
|
-
content: [
|
|
585
|
-
{
|
|
586
|
-
"sort by views": () => {
|
|
587
|
-
}
|
|
588
|
-
},
|
|
589
|
-
{
|
|
590
|
-
"sort by duration": () => {
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
]
|
|
594
|
-
},
|
|
595
|
-
{
|
|
596
|
-
title: "Privacy Filter",
|
|
597
|
-
content: [
|
|
598
|
-
{ filterPrivate: false, label: "private" },
|
|
599
|
-
{ filterPublic: false, label: "public" },
|
|
600
|
-
{ "check access 🔓": () => {
|
|
601
|
-
} }
|
|
602
|
-
]
|
|
603
|
-
},
|
|
604
|
-
{
|
|
605
|
-
title: "Advanced",
|
|
606
|
-
content: [
|
|
607
|
-
{
|
|
608
|
-
infiniteScrollEnabled: true,
|
|
609
|
-
label: "infinite scroll"
|
|
610
|
-
},
|
|
611
|
-
{
|
|
612
|
-
autoScroll: false,
|
|
613
|
-
label: "auto scroll"
|
|
614
|
-
},
|
|
615
|
-
{
|
|
616
|
-
delay: 250,
|
|
617
|
-
label: "scroll delay"
|
|
618
|
-
},
|
|
619
|
-
{
|
|
620
|
-
writeHistory: false,
|
|
621
|
-
label: "write history"
|
|
622
|
-
}
|
|
623
|
-
]
|
|
624
|
-
},
|
|
625
|
-
{
|
|
626
|
-
title: "Badge",
|
|
627
|
-
content: [
|
|
628
|
-
{
|
|
629
|
-
text: "return `${state.$paginationOffset}/${state.$paginationLast}`",
|
|
630
|
-
vif: "return state.$paginationLast > 1"
|
|
631
|
-
}
|
|
632
|
-
]
|
|
633
|
-
}
|
|
634
|
-
];
|
|
635
|
-
|
|
636
|
-
const StoreStateDefault = {
|
|
637
|
-
enabled: true,
|
|
638
|
-
collapsed: false,
|
|
639
|
-
darkmode: true,
|
|
640
|
-
$paginationLast: 1,
|
|
641
|
-
$paginationOffset: 1
|
|
642
|
-
};
|
|
381
|
+
function wait(milliseconds) {
|
|
382
|
+
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
383
|
+
}
|
|
643
384
|
|
|
644
|
-
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");
|
|
385
|
+
const MOBILE_UA = {
|
|
386
|
+
"User-Agent": [
|
|
387
|
+
"Mozilla/5.0 (Linux; Android 10; K)",
|
|
388
|
+
"AppleWebKit/537.36 (KHTML, like Gecko)",
|
|
389
|
+
"Chrome/114.0.0.0 Mobile Safari/537.36"
|
|
390
|
+
].join(" ")
|
|
391
|
+
};
|
|
392
|
+
async function fetchWith(input, options) {
|
|
393
|
+
const requestInit = options.init || {};
|
|
394
|
+
if (options.mobile) {
|
|
395
|
+
Object.assign(requestInit, { headers: new Headers(MOBILE_UA) });
|
|
396
|
+
}
|
|
397
|
+
const r = await fetch(input, requestInit).then((r2) => r2);
|
|
398
|
+
return parseHtml(await r.text());
|
|
399
|
+
}
|
|
400
|
+
const fetchHtml = (input) => fetchWith(input, { });
|
|
645
401
|
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
402
|
+
class InfiniteScroller {
|
|
403
|
+
enabled = true;
|
|
404
|
+
paginationOffset = 1;
|
|
405
|
+
parseData;
|
|
406
|
+
rules;
|
|
407
|
+
observer;
|
|
408
|
+
paginationGenerator;
|
|
409
|
+
constructor(options) {
|
|
410
|
+
this.rules = options.rules;
|
|
411
|
+
this.paginationOffset = this.rules.paginationStrategy.getPaginationOffset();
|
|
412
|
+
Object.assign(this, options);
|
|
413
|
+
if (this.rules.getPaginationData) {
|
|
414
|
+
this.getPaginationData = this.rules.getPaginationData;
|
|
415
|
+
}
|
|
416
|
+
this.paginationGenerator = this.rules.customGenerator || InfiniteScroller.generatorForPaginationStrategy(this.rules.paginationStrategy);
|
|
417
|
+
this.setObserver(this.rules.observable);
|
|
418
|
+
this.setAutoScroll();
|
|
419
|
+
}
|
|
420
|
+
dispose() {
|
|
421
|
+
if (this.observer) this.observer.dispose();
|
|
666
422
|
}
|
|
667
|
-
|
|
668
|
-
if (
|
|
669
|
-
|
|
670
|
-
|
|
423
|
+
setObserver(observable) {
|
|
424
|
+
if (this.observer) this.observer.dispose();
|
|
425
|
+
this.observer = Observer.observeWhile(
|
|
426
|
+
observable,
|
|
427
|
+
this.generatorConsumer,
|
|
428
|
+
this.rules.store.state.delay
|
|
671
429
|
);
|
|
672
|
-
|
|
673
|
-
const last = linksDepaginated.at(-1);
|
|
674
|
-
if (last.pathname !== curr.pathname) curr.pathname = last.pathname;
|
|
675
|
-
return curr;
|
|
430
|
+
return this;
|
|
676
431
|
}
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
432
|
+
onScrollCBs = [];
|
|
433
|
+
onScroll(callback, initCall = false) {
|
|
434
|
+
if (initCall) callback(this);
|
|
435
|
+
this.onScrollCBs.push(callback);
|
|
436
|
+
return this;
|
|
437
|
+
}
|
|
438
|
+
_onScroll() {
|
|
439
|
+
this.onScrollCBs.forEach((cb) => {
|
|
440
|
+
cb(this);
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
setAutoScroll() {
|
|
444
|
+
const autoScrollWrapper = async () => {
|
|
445
|
+
if (this.rules.store.state.autoScroll) {
|
|
446
|
+
await wait(this.rules.store.state.delay);
|
|
447
|
+
await this.generatorConsumer();
|
|
448
|
+
await autoScrollWrapper();
|
|
693
449
|
}
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
450
|
+
};
|
|
451
|
+
autoScrollWrapper();
|
|
452
|
+
this.rules.store.stateSubject.subscribe((type) => {
|
|
453
|
+
if (type?.autoScroll) {
|
|
454
|
+
autoScrollWrapper();
|
|
455
|
+
}
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
generatorConsumer = async () => {
|
|
459
|
+
if (!this.enabled) return false;
|
|
460
|
+
const {
|
|
461
|
+
value: { url, offset },
|
|
462
|
+
done
|
|
463
|
+
} = await this.paginationGenerator.next();
|
|
464
|
+
if (!done && url) {
|
|
465
|
+
await this.doScroll(url, offset);
|
|
466
|
+
}
|
|
467
|
+
return !done;
|
|
468
|
+
};
|
|
469
|
+
async getPaginationData(url) {
|
|
470
|
+
return await fetchHtml(url);
|
|
471
|
+
}
|
|
472
|
+
async doScroll(url, offset) {
|
|
473
|
+
const nextPageHtml = await this.getPaginationData(url);
|
|
474
|
+
const prevScrollPos = document.documentElement.scrollTop;
|
|
475
|
+
this.paginationOffset = Math.max(this.paginationOffset, offset);
|
|
476
|
+
this.parseData?.(nextPageHtml);
|
|
477
|
+
this._onScroll();
|
|
478
|
+
window.scrollTo(0, prevScrollPos);
|
|
479
|
+
if (this.rules.store.state.writeHistory) {
|
|
480
|
+
history.replaceState({}, "", url);
|
|
708
481
|
}
|
|
709
|
-
|
|
710
|
-
|
|
482
|
+
}
|
|
483
|
+
static async *generatorForPaginationStrategy(pstrategy) {
|
|
484
|
+
const _offset = pstrategy.getPaginationOffset();
|
|
485
|
+
const end = pstrategy.getPaginationLast();
|
|
486
|
+
const urlGenerator = pstrategy.getPaginationUrlGenerator();
|
|
487
|
+
for (let offset = _offset; offset <= end; offset++) {
|
|
488
|
+
const url = await urlGenerator(offset);
|
|
489
|
+
yield { url, offset };
|
|
711
490
|
}
|
|
712
491
|
}
|
|
492
|
+
static create(rules) {
|
|
493
|
+
const enabled = rules.store.state.infiniteScrollEnabled;
|
|
494
|
+
rules.store.state.$paginationLast = rules.paginationStrategy.getPaginationLast();
|
|
495
|
+
const infiniteScroller = new InfiniteScroller({
|
|
496
|
+
enabled,
|
|
497
|
+
parseData: rules.dataManager.parseData,
|
|
498
|
+
rules
|
|
499
|
+
}).onScroll(({ paginationOffset }) => {
|
|
500
|
+
rules.store.state.$paginationOffset = paginationOffset;
|
|
501
|
+
}, true);
|
|
502
|
+
rules.store.stateSubject.subscribe(() => {
|
|
503
|
+
infiniteScroller.enabled = rules.store.state.infiniteScrollEnabled;
|
|
504
|
+
});
|
|
505
|
+
return infiniteScroller;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
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");
|
|
713
510
|
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
511
|
+
function parseUrl(s) {
|
|
512
|
+
return new URL(typeof s === "string" ? s : s.href);
|
|
513
|
+
}
|
|
514
|
+
function depaginatePathname(url, pathnamePaginationSelector = /\/(page\/)?\d+\/?$/) {
|
|
515
|
+
const newUrl = new URL(url.toString());
|
|
516
|
+
newUrl.pathname = newUrl.pathname.replace(pathnamePaginationSelector, "/");
|
|
517
|
+
return newUrl;
|
|
518
|
+
}
|
|
519
|
+
function getPaginationLinks(doc = document, url = location.href, pathnamePaginationSelector = /\/(page\/)?\d+\/?$/) {
|
|
520
|
+
const baseUrl = depaginatePathname(parseUrl(url), pathnamePaginationSelector);
|
|
521
|
+
const pathnameStrict = doc instanceof Document;
|
|
522
|
+
const host = doc.baseURI || baseUrl.origin;
|
|
523
|
+
const urlPattern = new Y({
|
|
524
|
+
pathname: pathnameStrict ? `${baseUrl.pathname}*` : "*",
|
|
525
|
+
hostname: baseUrl.hostname
|
|
526
|
+
});
|
|
527
|
+
const pageLinks = [...doc.querySelectorAll("a[href]")].map((a) => a.href).filter((h) => URL.canParse(h));
|
|
528
|
+
return pageLinks.filter((h) => {
|
|
529
|
+
return urlPattern.test(new URL(h, host));
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
function upgradePathname(curr, links, pathnamePaginationSelector = /\/(page\/)?\d+\/?$/) {
|
|
533
|
+
if (pathnamePaginationSelector.test(curr.pathname) || links.length < 1) return curr;
|
|
534
|
+
const linksDepaginated = links.map(
|
|
535
|
+
(l) => depaginatePathname(l, pathnamePaginationSelector)
|
|
536
|
+
);
|
|
537
|
+
if (linksDepaginated.some((l) => l.pathname === curr.pathname)) return curr;
|
|
538
|
+
const last = linksDepaginated.at(-1);
|
|
539
|
+
if (last.pathname !== curr.pathname) curr.pathname = last.pathname;
|
|
540
|
+
return curr;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
class PaginationStrategy {
|
|
544
|
+
doc = document;
|
|
545
|
+
url;
|
|
546
|
+
paginationSelector = ".pagination";
|
|
547
|
+
searchParamSelector = "page";
|
|
548
|
+
static _pathnameSelector = /\/(page\/)?\d+\/?$/;
|
|
549
|
+
pathnameSelector = /\/(\d+)\/?$/;
|
|
550
|
+
dataparamSelector = "[data-parameters *= from]";
|
|
551
|
+
overwritePaginationLast;
|
|
552
|
+
offsetMin = 1;
|
|
553
|
+
constructor(options) {
|
|
554
|
+
if (options) {
|
|
555
|
+
Object.entries(options).forEach(([k, v]) => {
|
|
556
|
+
Object.assign(this, { [k]: v });
|
|
721
557
|
});
|
|
722
|
-
const lastPage = Math.max(...pages, this.offsetMin);
|
|
723
|
-
if (this.overwritePaginationLast) return this.overwritePaginationLast(lastPage);
|
|
724
|
-
return lastPage;
|
|
725
558
|
}
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
559
|
+
this.url = parseUrl(options?.url || this.doc.URL);
|
|
560
|
+
}
|
|
561
|
+
getPaginationElement() {
|
|
562
|
+
return this.doc.querySelector(this.paginationSelector);
|
|
563
|
+
}
|
|
564
|
+
get hasPagination() {
|
|
565
|
+
return !!this.getPaginationElement();
|
|
566
|
+
}
|
|
567
|
+
getPaginationOffset() {
|
|
568
|
+
return this.offsetMin;
|
|
569
|
+
}
|
|
570
|
+
getPaginationLast() {
|
|
571
|
+
if (this.overwritePaginationLast) return this.overwritePaginationLast(1);
|
|
572
|
+
return 1;
|
|
573
|
+
}
|
|
574
|
+
getPaginationUrlGenerator() {
|
|
575
|
+
return (_) => this.url.href;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
function formatTimeToHHMMSS(timeStr) {
|
|
580
|
+
const pad = (num) => num.toString().padStart(2, "0");
|
|
581
|
+
const h = timeStr.match(/(\d+)\s*h/)?.[1] || "0";
|
|
582
|
+
const m = timeStr.match(/(\d+)\s*mi?n/)?.[1] || "0";
|
|
583
|
+
const s = timeStr.match(/(\d+)\s*sec/)?.[1] || "0";
|
|
584
|
+
return `${pad(+h)}:${pad(+m)}:${pad(+s)}`;
|
|
585
|
+
}
|
|
586
|
+
function timeToSeconds(timeStr) {
|
|
587
|
+
const normalized = /[a-zA-Z]/.test(timeStr) ? formatTimeToHHMMSS(timeStr) : timeStr;
|
|
588
|
+
return normalized.split(":").reverse().reduce((total, unit, index) => total + parseInt(unit, 10) * 60 ** index, 0);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
function parseDataParams(str) {
|
|
592
|
+
const paramsStr = decodeURI(str.trim()).split(";");
|
|
593
|
+
return paramsStr.reduce(
|
|
594
|
+
(acc, s) => {
|
|
595
|
+
const parsed = s.match(/([+\w]+):([\w\- ]+)?/);
|
|
596
|
+
if (parsed) {
|
|
597
|
+
const [, key, value] = parsed;
|
|
598
|
+
if (value) {
|
|
599
|
+
key.split("+").forEach((p) => {
|
|
600
|
+
acc[p] = value;
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
return acc;
|
|
605
|
+
},
|
|
606
|
+
{}
|
|
607
|
+
);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
class PaginationStrategyDataParams extends PaginationStrategy {
|
|
611
|
+
getPaginationLast() {
|
|
612
|
+
const links = this.getPaginationElement()?.querySelectorAll(this.dataparamSelector);
|
|
613
|
+
const pages = Array.from(links || [], (l) => {
|
|
614
|
+
const p = l.getAttribute("data-parameters");
|
|
732
615
|
const v = p?.match(/from\w*:(\d+)/)?.[1] || this.offsetMin.toString();
|
|
733
616
|
return parseInt(v);
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
617
|
+
});
|
|
618
|
+
const lastPage = Math.max(...pages, this.offsetMin);
|
|
619
|
+
if (this.overwritePaginationLast) return this.overwritePaginationLast(lastPage);
|
|
620
|
+
return lastPage;
|
|
621
|
+
}
|
|
622
|
+
getPaginationOffset() {
|
|
623
|
+
const link = this.getPaginationElement()?.querySelector(
|
|
624
|
+
".prev[data-parameters *= from], .prev [data-parameters *= from]"
|
|
625
|
+
);
|
|
626
|
+
if (!link) return this.offsetMin;
|
|
627
|
+
const p = link.getAttribute("data-parameters");
|
|
628
|
+
const v = p?.match(/from\w*:(\d+)/)?.[1] || this.offsetMin.toString();
|
|
629
|
+
return parseInt(v);
|
|
630
|
+
}
|
|
631
|
+
getPaginationUrlGenerator() {
|
|
632
|
+
const url = new URL(this.url.href);
|
|
633
|
+
const parametersElement = this.getPaginationElement()?.querySelector(
|
|
634
|
+
"a[data-block-id][data-parameters]"
|
|
635
|
+
);
|
|
636
|
+
const block_id = parametersElement?.getAttribute("data-block-id") || "";
|
|
637
|
+
const parameters = parseDataParams(
|
|
638
|
+
parametersElement?.getAttribute("data-parameters") || ""
|
|
639
|
+
);
|
|
640
|
+
const attrs = {
|
|
641
|
+
block_id,
|
|
642
|
+
function: "get_block",
|
|
643
|
+
mode: "async",
|
|
644
|
+
...parameters
|
|
645
|
+
};
|
|
646
|
+
Object.keys(attrs).forEach((k) => {
|
|
647
|
+
url.searchParams.set(k, attrs[k]);
|
|
648
|
+
});
|
|
649
|
+
const paginationUrlGenerator = (n) => {
|
|
750
650
|
Object.keys(attrs).forEach((k) => {
|
|
751
|
-
url.searchParams.set(k,
|
|
651
|
+
k.includes("from") && url.searchParams.set(k, n.toString());
|
|
752
652
|
});
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
url.searchParams.set("_", Date.now().toString());
|
|
758
|
-
return url.href;
|
|
759
|
-
};
|
|
760
|
-
return paginationUrlGenerator;
|
|
761
|
-
}
|
|
762
|
-
static testLinks(doc = document) {
|
|
763
|
-
const dataParamLinks = Array.from(
|
|
764
|
-
doc.querySelectorAll("[data-parameters *= from]")
|
|
765
|
-
);
|
|
766
|
-
return dataParamLinks.length > 0;
|
|
767
|
-
}
|
|
653
|
+
url.searchParams.set("_", Date.now().toString());
|
|
654
|
+
return url.href;
|
|
655
|
+
};
|
|
656
|
+
return paginationUrlGenerator;
|
|
768
657
|
}
|
|
658
|
+
static testLinks(doc = document) {
|
|
659
|
+
const dataParamLinks = Array.from(
|
|
660
|
+
doc.querySelectorAll("[data-parameters *= from]")
|
|
661
|
+
);
|
|
662
|
+
return dataParamLinks.length > 0;
|
|
663
|
+
}
|
|
664
|
+
}
|
|
769
665
|
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
666
|
+
class PaginationStrategyPathnameParams extends PaginationStrategy {
|
|
667
|
+
extractPage = (a) => {
|
|
668
|
+
const href = typeof a === "string" ? a : a.href;
|
|
669
|
+
const { pathname } = new URL(href, this.doc.baseURI || this.url.origin);
|
|
670
|
+
return parseInt(
|
|
671
|
+
pathname.match(this.pathnameSelector)?.pop() || this.offsetMin.toString()
|
|
672
|
+
);
|
|
673
|
+
};
|
|
674
|
+
static checkLink(link, pathnameSelector = PaginationStrategy._pathnameSelector) {
|
|
675
|
+
return pathnameSelector.test(link.pathname);
|
|
676
|
+
}
|
|
677
|
+
static testLinks(links, options) {
|
|
678
|
+
const result = links.some(
|
|
679
|
+
(h) => PaginationStrategyPathnameParams.checkLink(h, options.pathnameSelector)
|
|
680
|
+
);
|
|
681
|
+
if (result) {
|
|
682
|
+
const pathnamesMatched = links.filter(
|
|
783
683
|
(h) => PaginationStrategyPathnameParams.checkLink(h, options.pathnameSelector)
|
|
784
684
|
);
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
);
|
|
789
|
-
options.url = upgradePathname(
|
|
790
|
-
parseUrl(options.url),
|
|
791
|
-
pathnamesMatched
|
|
792
|
-
);
|
|
793
|
-
}
|
|
794
|
-
return result;
|
|
795
|
-
}
|
|
796
|
-
getPaginationLast() {
|
|
797
|
-
const links = getPaginationLinks(
|
|
798
|
-
this.getPaginationElement() || document,
|
|
799
|
-
this.url.href,
|
|
800
|
-
this.pathnameSelector
|
|
685
|
+
options.url = upgradePathname(
|
|
686
|
+
parseUrl(options.url),
|
|
687
|
+
pathnamesMatched
|
|
801
688
|
);
|
|
802
|
-
const pages = Array.from(links, this.extractPage);
|
|
803
|
-
const lastPage = Math.max(...pages, this.offsetMin);
|
|
804
|
-
if (this.overwritePaginationLast) return this.overwritePaginationLast(lastPage);
|
|
805
|
-
return lastPage;
|
|
806
|
-
}
|
|
807
|
-
getPaginationOffset() {
|
|
808
|
-
return this.extractPage(this.url.href);
|
|
809
|
-
}
|
|
810
|
-
getPaginationUrlGenerator(url_ = this.url) {
|
|
811
|
-
const url = new URL(url_.href);
|
|
812
|
-
const pathnameSelectorPlaceholder = this.pathnameSelector.toString().replace(/[/|\\|$|?|(|)]+/g, "/");
|
|
813
|
-
if (!this.pathnameSelector.test(url.pathname)) {
|
|
814
|
-
url.pathname = url.pathname.concat(pathnameSelectorPlaceholder.replace(/d\+/, this.offsetMin.toString())).replace(/\/{2,}/g, "/");
|
|
815
|
-
}
|
|
816
|
-
const paginationUrlGenerator = (offset) => {
|
|
817
|
-
url.pathname = url.pathname.replace(
|
|
818
|
-
this.pathnameSelector,
|
|
819
|
-
pathnameSelectorPlaceholder.replace(/d\+/, offset.toString())
|
|
820
|
-
);
|
|
821
|
-
return url.href;
|
|
822
|
-
};
|
|
823
|
-
return paginationUrlGenerator;
|
|
824
689
|
}
|
|
690
|
+
return result;
|
|
825
691
|
}
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
`a.active[href *= "${this.searchParamSelector}="]`
|
|
851
|
-
);
|
|
852
|
-
return this.extractPage(link);
|
|
853
|
-
}
|
|
854
|
-
getPaginationUrlGenerator() {
|
|
855
|
-
const url = new URL(this.url.href);
|
|
856
|
-
const paginationUrlGenerator = (offset) => {
|
|
857
|
-
url.searchParams.set(this.searchParamSelector, offset.toString());
|
|
858
|
-
return url.href;
|
|
859
|
-
};
|
|
860
|
-
return paginationUrlGenerator;
|
|
861
|
-
}
|
|
862
|
-
static checkLink(link, searchParamSelector) {
|
|
863
|
-
const searchParamSelectors = ["page", "p"];
|
|
864
|
-
if (searchParamSelector) searchParamSelectors.push(searchParamSelector);
|
|
865
|
-
return searchParamSelectors.some((p) => link.searchParams.get(p) !== null);
|
|
866
|
-
}
|
|
867
|
-
static testLinks(links, searchParamSelector) {
|
|
868
|
-
return links.some(
|
|
869
|
-
(h) => PaginationStrategySearchParams.checkLink(h, searchParamSelector)
|
|
692
|
+
getPaginationLast() {
|
|
693
|
+
const links = getPaginationLinks(
|
|
694
|
+
this.getPaginationElement() || document,
|
|
695
|
+
this.url.href,
|
|
696
|
+
this.pathnameSelector
|
|
697
|
+
);
|
|
698
|
+
const pages = Array.from(links, this.extractPage);
|
|
699
|
+
const lastPage = Math.max(...pages, this.offsetMin);
|
|
700
|
+
if (this.overwritePaginationLast) return this.overwritePaginationLast(lastPage);
|
|
701
|
+
return lastPage;
|
|
702
|
+
}
|
|
703
|
+
getPaginationOffset() {
|
|
704
|
+
return this.extractPage(this.url.href);
|
|
705
|
+
}
|
|
706
|
+
getPaginationUrlGenerator(url_ = this.url) {
|
|
707
|
+
const url = new URL(url_.href);
|
|
708
|
+
const pathnameSelectorPlaceholder = this.pathnameSelector.toString().replace(/[/|\\|$|?|(|)]+/g, "/");
|
|
709
|
+
if (!this.pathnameSelector.test(url.pathname)) {
|
|
710
|
+
url.pathname = url.pathname.concat(pathnameSelectorPlaceholder.replace(/d\+/, this.offsetMin.toString())).replace(/\/{2,}/g, "/");
|
|
711
|
+
}
|
|
712
|
+
const paginationUrlGenerator = (offset) => {
|
|
713
|
+
url.pathname = url.pathname.replace(
|
|
714
|
+
this.pathnameSelector,
|
|
715
|
+
pathnameSelectorPlaceholder.replace(/d\+/, offset.toString())
|
|
870
716
|
);
|
|
871
|
-
|
|
717
|
+
return url.href;
|
|
718
|
+
};
|
|
719
|
+
return paginationUrlGenerator;
|
|
872
720
|
}
|
|
721
|
+
}
|
|
873
722
|
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
const
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
723
|
+
class PaginationStrategySearchParams extends PaginationStrategy {
|
|
724
|
+
extractPage = (a) => {
|
|
725
|
+
const href = typeof a === "string" ? a : a.href;
|
|
726
|
+
const p = new URL(href).searchParams.get(this.searchParamSelector);
|
|
727
|
+
return parseInt(p) || this.offsetMin;
|
|
728
|
+
};
|
|
729
|
+
getPaginationLast() {
|
|
730
|
+
const links = getPaginationLinks(
|
|
731
|
+
this.getPaginationElement() || document,
|
|
732
|
+
this.url.href
|
|
733
|
+
).filter(
|
|
734
|
+
(h) => PaginationStrategySearchParams.checkLink(new URL(h), this.searchParamSelector)
|
|
735
|
+
);
|
|
736
|
+
const pages = links.map(this.extractPage);
|
|
737
|
+
const lastPage = Math.max(...pages, this.offsetMin);
|
|
738
|
+
if (this.overwritePaginationLast) return this.overwritePaginationLast(lastPage);
|
|
739
|
+
return lastPage;
|
|
740
|
+
}
|
|
741
|
+
getPaginationOffset() {
|
|
742
|
+
if (this.doc === document) {
|
|
743
|
+
return this.extractPage(this.url);
|
|
884
744
|
}
|
|
885
|
-
const
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
}
|
|
896
|
-
console.error("Found No Strategy");
|
|
897
|
-
return PaginationStrategy;
|
|
745
|
+
const link = this.getPaginationElement()?.querySelector(
|
|
746
|
+
`a.active[href *= "${this.searchParamSelector}="]`
|
|
747
|
+
);
|
|
748
|
+
return this.extractPage(link);
|
|
749
|
+
}
|
|
750
|
+
getPaginationUrlGenerator() {
|
|
751
|
+
const url = new URL(this.url.href);
|
|
752
|
+
const paginationUrlGenerator = (offset) => {
|
|
753
|
+
url.searchParams.set(this.searchParamSelector, offset.toString());
|
|
754
|
+
return url.href;
|
|
898
755
|
};
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
756
|
+
return paginationUrlGenerator;
|
|
757
|
+
}
|
|
758
|
+
static checkLink(link, searchParamSelector) {
|
|
759
|
+
const searchParamSelectors = ["page", "p"];
|
|
760
|
+
if (searchParamSelector) searchParamSelectors.push(searchParamSelector);
|
|
761
|
+
return searchParamSelectors.some((p) => link.searchParams.get(p) !== null);
|
|
902
762
|
}
|
|
763
|
+
static testLinks(links, searchParamSelector) {
|
|
764
|
+
return links.some(
|
|
765
|
+
(h) => PaginationStrategySearchParams.checkLink(h, searchParamSelector)
|
|
766
|
+
);
|
|
767
|
+
}
|
|
768
|
+
}
|
|
903
769
|
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
770
|
+
function getPaginationStrategy(options) {
|
|
771
|
+
const _paginationStrategy = new PaginationStrategy(options);
|
|
772
|
+
const pagination = _paginationStrategy.getPaginationElement();
|
|
773
|
+
Object.assign(options, { ..._paginationStrategy });
|
|
774
|
+
const { url, searchParamSelector } = options;
|
|
775
|
+
if (!pagination) {
|
|
776
|
+
return _paginationStrategy;
|
|
777
|
+
}
|
|
778
|
+
if (typeof options.getPaginationUrlGenerator === "function") {
|
|
779
|
+
return new PaginationStrategy(options);
|
|
780
|
+
}
|
|
781
|
+
const pageLinks = getPaginationLinks(pagination, url).map((l) => new URL(l));
|
|
782
|
+
const selectStrategy = () => {
|
|
783
|
+
if (PaginationStrategyDataParams.testLinks(pagination)) {
|
|
784
|
+
return PaginationStrategyDataParams;
|
|
909
785
|
}
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
}
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
thumbData.title = `${thumbData.title} user:${uploader}`;
|
|
786
|
+
if (PaginationStrategySearchParams.testLinks(pageLinks, searchParamSelector)) {
|
|
787
|
+
return PaginationStrategySearchParams;
|
|
788
|
+
}
|
|
789
|
+
if (PaginationStrategyPathnameParams.testLinks(pageLinks, options)) {
|
|
790
|
+
return PaginationStrategyPathnameParams;
|
|
791
|
+
}
|
|
792
|
+
console.error("Found No Strategy");
|
|
793
|
+
return PaginationStrategy;
|
|
794
|
+
};
|
|
795
|
+
const PaginationStrategyConstructor = selectStrategy();
|
|
796
|
+
const paginationStrategy = new PaginationStrategyConstructor(options);
|
|
797
|
+
return paginationStrategy;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
const DefaultScheme = [
|
|
801
|
+
{
|
|
802
|
+
title: "Text Filter",
|
|
803
|
+
collapsed: true,
|
|
804
|
+
content: [
|
|
805
|
+
{ filterExclude: false, label: "exclude" },
|
|
806
|
+
{
|
|
807
|
+
filterExcludeWords: "",
|
|
808
|
+
label: "keywords",
|
|
809
|
+
watch: "filterExclude",
|
|
810
|
+
placeholder: "word, f:full_word, r:RegEx..."
|
|
811
|
+
},
|
|
812
|
+
{ filterInclude: false, label: "include" },
|
|
813
|
+
{
|
|
814
|
+
filterIncludeWords: "",
|
|
815
|
+
label: "keywords",
|
|
816
|
+
watch: "filterInclude",
|
|
817
|
+
placeholder: "word, f:full_word, r:RegEx..."
|
|
943
818
|
}
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
819
|
+
]
|
|
820
|
+
},
|
|
821
|
+
{
|
|
822
|
+
title: "Duration Filter",
|
|
823
|
+
collapsed: true,
|
|
824
|
+
content: [
|
|
825
|
+
{ filterDuration: false, label: "enable" },
|
|
826
|
+
{
|
|
827
|
+
filterDurationFrom: 0,
|
|
828
|
+
watch: "filterDuration",
|
|
829
|
+
label: "from",
|
|
830
|
+
type: "time"
|
|
831
|
+
},
|
|
832
|
+
{
|
|
833
|
+
filterDurationTo: 600,
|
|
834
|
+
watch: "filterDuration",
|
|
835
|
+
label: "to",
|
|
836
|
+
type: "time"
|
|
947
837
|
}
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
838
|
+
]
|
|
839
|
+
},
|
|
840
|
+
{
|
|
841
|
+
title: "Sort By",
|
|
842
|
+
content: [
|
|
843
|
+
{
|
|
844
|
+
"sort by views": () => {
|
|
952
845
|
}
|
|
953
|
-
|
|
954
|
-
|
|
846
|
+
},
|
|
847
|
+
{
|
|
848
|
+
"sort by duration": () => {
|
|
955
849
|
}
|
|
956
|
-
return Number.parseInt(querySelectorText(thumb, selector));
|
|
957
850
|
}
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
851
|
+
]
|
|
852
|
+
},
|
|
853
|
+
{
|
|
854
|
+
title: "Privacy Filter",
|
|
855
|
+
content: [
|
|
856
|
+
{ filterPrivate: false, label: "private" },
|
|
857
|
+
{ filterPublic: false, label: "public" },
|
|
858
|
+
{ "check access 🔓": () => {
|
|
859
|
+
} }
|
|
860
|
+
]
|
|
861
|
+
},
|
|
862
|
+
{
|
|
863
|
+
title: "Advanced",
|
|
864
|
+
content: [
|
|
865
|
+
{
|
|
866
|
+
infiniteScrollEnabled: true,
|
|
867
|
+
label: "infinite scroll"
|
|
868
|
+
},
|
|
869
|
+
{
|
|
870
|
+
autoScroll: false,
|
|
871
|
+
label: "auto scroll"
|
|
872
|
+
},
|
|
873
|
+
{
|
|
874
|
+
delay: 250,
|
|
875
|
+
label: "scroll delay"
|
|
876
|
+
},
|
|
877
|
+
{
|
|
878
|
+
writeHistory: false,
|
|
879
|
+
label: "write history"
|
|
963
880
|
}
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
const img = thumb.querySelector("img");
|
|
973
|
-
if (!img) return {};
|
|
974
|
-
result.img = img;
|
|
975
|
-
if (typeof this.getThumbImgDataAttrSelector === "function") {
|
|
976
|
-
result.imgSrc = this.getThumbImgDataAttrSelector(img);
|
|
977
|
-
} else {
|
|
978
|
-
const possibleAttrs = this.getThumbImgDataAttrSelector ? [this.getThumbImgDataAttrSelector].flat() : ["data-src", "src"];
|
|
979
|
-
for (const attr of possibleAttrs) {
|
|
980
|
-
const imgSrc = img.getAttribute(attr);
|
|
981
|
-
if (imgSrc) {
|
|
982
|
-
result.imgSrc = imgSrc;
|
|
983
|
-
img.removeAttribute(attr);
|
|
984
|
-
break;
|
|
985
|
-
}
|
|
986
|
-
}
|
|
987
|
-
}
|
|
988
|
-
if (this.getThumbImgDataAttrDelete) {
|
|
989
|
-
if (this.getThumbImgDataAttrDelete === "auto") {
|
|
990
|
-
removeClassesAndDataAttributes(img, "lazy");
|
|
991
|
-
} else {
|
|
992
|
-
if (this.getThumbImgDataAttrDelete.startsWith(".")) {
|
|
993
|
-
img.classList.remove(this.getThumbImgDataAttrDelete.slice(1));
|
|
994
|
-
} else {
|
|
995
|
-
img.removeAttribute(this.getThumbImgDataAttrDelete);
|
|
996
|
-
}
|
|
997
|
-
}
|
|
998
|
-
if (img.src.includes("data:image")) {
|
|
999
|
-
result.img.src = "";
|
|
1000
|
-
}
|
|
1001
|
-
if (img.complete && img.naturalWidth > 0) {
|
|
1002
|
-
return {};
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
881
|
+
]
|
|
882
|
+
},
|
|
883
|
+
{
|
|
884
|
+
title: "Badge",
|
|
885
|
+
content: [
|
|
886
|
+
{
|
|
887
|
+
text: "return `${state.$paginationOffset}/${state.$paginationLast}`",
|
|
888
|
+
vif: "return state.$paginationLast > 1"
|
|
1005
889
|
}
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
890
|
+
]
|
|
891
|
+
}
|
|
892
|
+
];
|
|
893
|
+
|
|
894
|
+
const StoreStateDefault = {
|
|
895
|
+
enabled: true,
|
|
896
|
+
collapsed: false,
|
|
897
|
+
darkmode: true,
|
|
898
|
+
$paginationLast: 1,
|
|
899
|
+
$paginationOffset: 1
|
|
900
|
+
};
|
|
901
|
+
|
|
902
|
+
class RulesGlobal {
|
|
903
|
+
delay;
|
|
904
|
+
customGenerator;
|
|
905
|
+
getThumbUrl(thumb) {
|
|
906
|
+
return (thumb.querySelector("a[href]") || thumb).href;
|
|
907
|
+
}
|
|
908
|
+
titleSelector;
|
|
909
|
+
uploaderSelector;
|
|
910
|
+
durationSelector;
|
|
911
|
+
customThumbDataSelectors;
|
|
912
|
+
getThumbDataStrategy = "default";
|
|
913
|
+
getThumbDataCallback;
|
|
914
|
+
getThumbData(thumb) {
|
|
915
|
+
let { titleSelector, uploaderSelector, durationSelector } = this;
|
|
916
|
+
const thumbData = { title: "" };
|
|
917
|
+
if (this.getThumbDataStrategy === "auto-text") {
|
|
918
|
+
const text = sanitizeStr(thumb.innerText);
|
|
919
|
+
thumbData.title = text;
|
|
920
|
+
thumbData.duration = timeToSeconds(text.match(/\d+m|\d+:\d+/)?.[0] || "");
|
|
921
|
+
return thumbData;
|
|
1016
922
|
}
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
if (typeof this.containerSelector === "string") {
|
|
1022
|
-
return document.querySelector(this.containerSelector);
|
|
1023
|
-
}
|
|
1024
|
-
return this.containerSelector();
|
|
923
|
+
if (this.getThumbDataStrategy === "auto-select") {
|
|
924
|
+
titleSelector = "[class *= title],[title]";
|
|
925
|
+
durationSelector = "[class *= duration]";
|
|
926
|
+
uploaderSelector = "[class *= uploader], [class *= user], [class *= name]";
|
|
1025
927
|
}
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
if (this.getThumbsStrategy === "auto") {
|
|
1033
|
-
if (typeof this.containerSelector !== "string") return [];
|
|
1034
|
-
const container = html.querySelector(this.containerSelector);
|
|
1035
|
-
thumbs = [...container?.children || []];
|
|
1036
|
-
}
|
|
1037
|
-
thumbs = Array.from(html.querySelectorAll(this.thumbsSelector));
|
|
1038
|
-
if (typeof this.getThumbsTransform === "function") {
|
|
1039
|
-
thumbs.forEach(this.getThumbsTransform);
|
|
928
|
+
if (this.getThumbDataStrategy === "auto-select") {
|
|
929
|
+
const selected = querySelectorLast(thumb, titleSelector);
|
|
930
|
+
if (selected) {
|
|
931
|
+
thumbData.title = sanitizeStr(selected.innerText);
|
|
932
|
+
} else {
|
|
933
|
+
thumbData.title = sanitizeStr(thumb.innerText);
|
|
1040
934
|
}
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
paginationStrategyOptions = {};
|
|
1044
|
-
paginationStrategy;
|
|
1045
|
-
customDataSelectorFns = [
|
|
1046
|
-
"filterInclude",
|
|
1047
|
-
"filterExclude",
|
|
1048
|
-
"filterDuration"
|
|
1049
|
-
];
|
|
1050
|
-
animatePreview;
|
|
1051
|
-
storeOptions;
|
|
1052
|
-
createStore() {
|
|
1053
|
-
const config = { ...StoreStateDefault, ...this.storeOptions };
|
|
1054
|
-
this.store = new jabroniOutfit.JabronioStore(config);
|
|
1055
|
-
return this.store;
|
|
935
|
+
} else {
|
|
936
|
+
thumbData.title = querySelectorText(thumb, titleSelector);
|
|
1056
937
|
}
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
this.schemeOptions,
|
|
1061
|
-
DefaultScheme
|
|
1062
|
-
);
|
|
1063
|
-
this.gui = new jabroniOutfit.JabronioGUI(scheme, this.store);
|
|
1064
|
-
return this.gui;
|
|
938
|
+
if (uploaderSelector) {
|
|
939
|
+
const uploader = querySelectorText(thumb, uploaderSelector);
|
|
940
|
+
thumbData.title = `${thumbData.title} user:${uploader}`;
|
|
1065
941
|
}
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
infiniteScroller;
|
|
1070
|
-
getPaginationData;
|
|
1071
|
-
resetInfiniteScroller() {
|
|
1072
|
-
this.infiniteScroller?.dispose();
|
|
1073
|
-
if (!this.paginationStrategy.hasPagination) return;
|
|
1074
|
-
this.infiniteScroller = InfiniteScroller.create(this);
|
|
942
|
+
if (durationSelector) {
|
|
943
|
+
const duration = timeToSeconds(querySelectorText(thumb, durationSelector));
|
|
944
|
+
thumbData.duration = duration;
|
|
1075
945
|
}
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
if (
|
|
1079
|
-
|
|
1080
|
-
this.dataManager?.parseData(this.container, this.container);
|
|
946
|
+
this.getThumbDataCallback?.(thumb, thumbData);
|
|
947
|
+
function getCustomThumbData(selector, type) {
|
|
948
|
+
if (type === "boolean") {
|
|
949
|
+
return !!thumb.querySelector(selector);
|
|
1081
950
|
}
|
|
1082
|
-
if (
|
|
1083
|
-
|
|
1084
|
-
this.dataManager.parseData(c, c, true);
|
|
1085
|
-
});
|
|
951
|
+
if (type === "string") {
|
|
952
|
+
return querySelectorText(thumb, selector);
|
|
1086
953
|
}
|
|
954
|
+
return Number.parseInt(querySelectorText(thumb, selector));
|
|
1087
955
|
}
|
|
1088
|
-
|
|
1089
|
-
|
|
956
|
+
if (this.customThumbDataSelectors) {
|
|
957
|
+
Object.entries(this.customThumbDataSelectors).forEach(([name, x]) => {
|
|
958
|
+
const data = getCustomThumbData(x.selector, x.type);
|
|
959
|
+
Object.assign(thumbData, { [name]: data });
|
|
960
|
+
});
|
|
1090
961
|
}
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
962
|
+
return thumbData;
|
|
963
|
+
}
|
|
964
|
+
getThumbImgDataAttrSelector;
|
|
965
|
+
getThumbImgDataAttrDelete;
|
|
966
|
+
getThumbImgDataStrategy = "default";
|
|
967
|
+
getThumbImgData(thumb) {
|
|
968
|
+
const result = {};
|
|
969
|
+
if (this.getThumbImgDataStrategy === "auto") {
|
|
970
|
+
const img = thumb.querySelector("img");
|
|
971
|
+
if (!img) return {};
|
|
972
|
+
result.img = img;
|
|
973
|
+
if (typeof this.getThumbImgDataAttrSelector === "function") {
|
|
974
|
+
result.imgSrc = this.getThumbImgDataAttrSelector(img);
|
|
975
|
+
} else {
|
|
976
|
+
const possibleAttrs = this.getThumbImgDataAttrSelector ? [this.getThumbImgDataAttrSelector].flat() : ["data-src", "src"];
|
|
977
|
+
for (const attr of possibleAttrs) {
|
|
978
|
+
const imgSrc = img.getAttribute(attr);
|
|
979
|
+
if (imgSrc) {
|
|
980
|
+
result.imgSrc = imgSrc;
|
|
981
|
+
img.removeAttribute(attr);
|
|
982
|
+
break;
|
|
983
|
+
}
|
|
1095
984
|
}
|
|
1096
|
-
}
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
if (event === lastEvent) {
|
|
1101
|
-
direction = !direction;
|
|
985
|
+
}
|
|
986
|
+
if (this.getThumbImgDataAttrDelete) {
|
|
987
|
+
if (this.getThumbImgDataAttrDelete === "auto") {
|
|
988
|
+
removeClassesAndDataAttributes(img, "lazy");
|
|
1102
989
|
} else {
|
|
1103
|
-
|
|
1104
|
-
|
|
990
|
+
if (this.getThumbImgDataAttrDelete.startsWith(".")) {
|
|
991
|
+
img.classList.remove(this.getThumbImgDataAttrDelete.slice(1));
|
|
992
|
+
} else {
|
|
993
|
+
img.removeAttribute(this.getThumbImgDataAttrDelete);
|
|
994
|
+
}
|
|
1105
995
|
}
|
|
1106
|
-
if (
|
|
1107
|
-
|
|
1108
|
-
|
|
996
|
+
if (img.src.includes("data:image")) {
|
|
997
|
+
result.img.src = "";
|
|
998
|
+
}
|
|
999
|
+
if (img.complete && img.naturalWidth > 0) {
|
|
1000
|
+
return {};
|
|
1109
1001
|
}
|
|
1110
|
-
});
|
|
1111
|
-
this.store.stateSubject.subscribe((a) => {
|
|
1112
|
-
this.dataManager.applyFilters(a);
|
|
1113
|
-
});
|
|
1114
|
-
}
|
|
1115
|
-
dataManagerOptions = {};
|
|
1116
|
-
setupDataManager() {
|
|
1117
|
-
this.dataManager = new DataManager(this);
|
|
1118
|
-
if (this.dataManagerOptions) {
|
|
1119
|
-
Object.assign(this.dataManager, this.dataManagerOptions);
|
|
1120
1002
|
}
|
|
1121
|
-
return this.dataManager;
|
|
1122
1003
|
}
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
});
|
|
1004
|
+
return result;
|
|
1005
|
+
}
|
|
1006
|
+
containerSelector = ".container";
|
|
1007
|
+
containerSelectorLast;
|
|
1008
|
+
intersectionObservableSelector;
|
|
1009
|
+
get intersectionObservable() {
|
|
1010
|
+
return this.intersectionObservableSelector && document.querySelector(this.intersectionObservableSelector);
|
|
1011
|
+
}
|
|
1012
|
+
get observable() {
|
|
1013
|
+
return this.intersectionObservable || this.paginationStrategy.getPaginationElement();
|
|
1014
|
+
}
|
|
1015
|
+
get container() {
|
|
1016
|
+
if (typeof this.containerSelectorLast === "string") {
|
|
1017
|
+
return querySelectorLast(document, this.containerSelectorLast);
|
|
1138
1018
|
}
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
this.mutationObservers.forEach((o) => {
|
|
1142
|
-
o.disconnect();
|
|
1143
|
-
});
|
|
1144
|
-
this.mutationObservers = [];
|
|
1145
|
-
this.paginationStrategy = getPaginationStrategy(this.paginationStrategyOptions);
|
|
1146
|
-
this.setupDataManager();
|
|
1147
|
-
this.setupStoreListeners();
|
|
1148
|
-
this.resetInfiniteScroller();
|
|
1149
|
-
this.container && this.animatePreview?.(this.container);
|
|
1150
|
-
this.gropeInit();
|
|
1151
|
-
this.onResetCallback?.();
|
|
1152
|
-
this.resetOn();
|
|
1019
|
+
if (typeof this.containerSelector === "string") {
|
|
1020
|
+
return document.querySelector(this.containerSelector);
|
|
1153
1021
|
}
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1022
|
+
return this.containerSelector();
|
|
1023
|
+
}
|
|
1024
|
+
thumbsSelector = ".thumb";
|
|
1025
|
+
getThumbsStrategy = "default";
|
|
1026
|
+
getThumbsTransform;
|
|
1027
|
+
getThumbs(html) {
|
|
1028
|
+
if (!html) return [];
|
|
1029
|
+
let thumbs;
|
|
1030
|
+
if (this.getThumbsStrategy === "auto") {
|
|
1031
|
+
if (typeof this.containerSelector !== "string") return [];
|
|
1032
|
+
const container = html.querySelector(this.containerSelector);
|
|
1033
|
+
thumbs = [...container?.children || []];
|
|
1034
|
+
}
|
|
1035
|
+
thumbs = Array.from(html.querySelectorAll(this.thumbsSelector));
|
|
1036
|
+
if (typeof this.getThumbsTransform === "function") {
|
|
1037
|
+
thumbs.forEach(this.getThumbsTransform);
|
|
1038
|
+
}
|
|
1039
|
+
return thumbs;
|
|
1040
|
+
}
|
|
1041
|
+
paginationStrategyOptions = {};
|
|
1042
|
+
paginationStrategy;
|
|
1043
|
+
customDataSelectorFns = [
|
|
1044
|
+
"filterInclude",
|
|
1045
|
+
"filterExclude",
|
|
1046
|
+
"filterDuration"
|
|
1047
|
+
];
|
|
1048
|
+
animatePreview;
|
|
1049
|
+
storeOptions;
|
|
1050
|
+
createStore() {
|
|
1051
|
+
const config = { ...StoreStateDefault, ...this.storeOptions };
|
|
1052
|
+
this.store = new jabroniOutfit.JabronioStore(config);
|
|
1053
|
+
return this.store;
|
|
1054
|
+
}
|
|
1055
|
+
schemeOptions = [];
|
|
1056
|
+
createGui() {
|
|
1057
|
+
const scheme = jabroniOutfit.setupScheme(
|
|
1058
|
+
this.schemeOptions,
|
|
1059
|
+
DefaultScheme
|
|
1060
|
+
);
|
|
1061
|
+
this.gui = new jabroniOutfit.JabronioGUI(scheme, this.store);
|
|
1062
|
+
return this.gui;
|
|
1063
|
+
}
|
|
1064
|
+
store;
|
|
1065
|
+
gui;
|
|
1066
|
+
dataManager;
|
|
1067
|
+
infiniteScroller;
|
|
1068
|
+
getPaginationData;
|
|
1069
|
+
resetInfiniteScroller() {
|
|
1070
|
+
this.infiniteScroller?.dispose();
|
|
1071
|
+
if (!this.paginationStrategy.hasPagination) return;
|
|
1072
|
+
this.infiniteScroller = InfiniteScroller.create(this);
|
|
1073
|
+
}
|
|
1074
|
+
gropeStrategy = "all-in-one";
|
|
1075
|
+
gropeInit() {
|
|
1076
|
+
if (!this.gropeStrategy) return;
|
|
1077
|
+
if (this.gropeStrategy === "all-in-one") {
|
|
1078
|
+
this.dataManager?.parseData(this.container, this.container);
|
|
1079
|
+
}
|
|
1080
|
+
if (this.gropeStrategy === "all-in-all") {
|
|
1081
|
+
getCommonParents(this.getThumbs(document.body)).forEach((c) => {
|
|
1082
|
+
this.dataManager.parseData(c, c, true);
|
|
1083
|
+
});
|
|
1162
1084
|
}
|
|
1163
1085
|
}
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
gropeStrategy: "all-in-one",
|
|
1172
|
-
customThumbDataSelectors: {
|
|
1173
|
-
videoAlbum: {
|
|
1174
|
-
type: "boolean",
|
|
1175
|
-
selector: ".album-videos"
|
|
1086
|
+
get isEmbedded() {
|
|
1087
|
+
return window.self !== window.top;
|
|
1088
|
+
}
|
|
1089
|
+
setupStoreListeners() {
|
|
1090
|
+
const eventsMap = {
|
|
1091
|
+
"sort by duration": {
|
|
1092
|
+
action: (direction2) => this.dataManager.sortBy("duration", direction2)
|
|
1176
1093
|
}
|
|
1177
|
-
}
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1094
|
+
};
|
|
1095
|
+
let lastEvent;
|
|
1096
|
+
let direction = true;
|
|
1097
|
+
this.store.eventSubject.subscribe((event) => {
|
|
1098
|
+
if (event === lastEvent) {
|
|
1099
|
+
direction = !direction;
|
|
1100
|
+
} else {
|
|
1101
|
+
lastEvent = event;
|
|
1102
|
+
direction = true;
|
|
1103
|
+
}
|
|
1104
|
+
if (event in eventsMap) {
|
|
1105
|
+
const ev = eventsMap[event];
|
|
1106
|
+
ev?.action(direction);
|
|
1187
1107
|
}
|
|
1188
|
-
],
|
|
1189
|
-
schemeOptions: [
|
|
1190
|
-
"Text Filter",
|
|
1191
|
-
{
|
|
1192
|
-
title: "Filter Albums",
|
|
1193
|
-
content: [
|
|
1194
|
-
{
|
|
1195
|
-
filterVideoAlbums: true,
|
|
1196
|
-
label: "video albums"
|
|
1197
|
-
},
|
|
1198
|
-
{
|
|
1199
|
-
filterPhotoAlbums: true,
|
|
1200
|
-
label: "photo albums"
|
|
1201
|
-
}
|
|
1202
|
-
]
|
|
1203
|
-
},
|
|
1204
|
-
"Badge",
|
|
1205
|
-
"Advanced"
|
|
1206
|
-
]
|
|
1207
|
-
});
|
|
1208
|
-
rules.infiniteScroller?.onScroll(() => {
|
|
1209
|
-
setTimeout(() => new LazyLoad(), 100);
|
|
1210
|
-
});
|
|
1211
|
-
_GM_addStyle(`
|
|
1212
|
-
.inactive-gm { background: #a09f9d; }
|
|
1213
|
-
.active-gm { background: #eb6395 !important; }
|
|
1214
|
-
`);
|
|
1215
|
-
(function disableDisclaimer() {
|
|
1216
|
-
if (!$("#disclaimer").length) return;
|
|
1217
|
-
$.ajax({ type: "POST", url: "/user/disclaimer", async: true });
|
|
1218
|
-
$("#disclaimer").remove();
|
|
1219
|
-
$("body").css("overflow", "visible");
|
|
1220
|
-
})();
|
|
1221
|
-
const IS_ALBUM_PAGE = /^\/a\//.test(window.location.pathname);
|
|
1222
|
-
function togglePhotoElements() {
|
|
1223
|
-
$(".media-group > div:last-child:not(.video)").toggle(rules.store.state.showPhotos);
|
|
1224
|
-
$("#togglePhotos").toggleClass("active-gm", rules.store.state.showPhotos);
|
|
1225
|
-
$("#togglePhotos").text(!rules.store.state.showPhotos ? "show photos" : "hide photos");
|
|
1226
|
-
}
|
|
1227
|
-
function setupAlbumPage() {
|
|
1228
|
-
$("#user_name").parent().append(
|
|
1229
|
-
'<button id="togglePhotos" class="btn btn-pink inactive-gm">show/hide photos</button>'
|
|
1230
|
-
);
|
|
1231
|
-
$("#togglePhotos").on("click", () => {
|
|
1232
|
-
rules.store.state.showPhotos = !rules.store.state.showPhotos;
|
|
1233
1108
|
});
|
|
1234
|
-
|
|
1235
|
-
|
|
1109
|
+
this.store.stateSubject.subscribe((a) => {
|
|
1110
|
+
this.dataManager.applyFilters(a);
|
|
1236
1111
|
});
|
|
1237
|
-
togglePhotoElements();
|
|
1238
1112
|
}
|
|
1239
|
-
|
|
1240
|
-
|
|
1113
|
+
dataManagerOptions = {};
|
|
1114
|
+
setupDataManager() {
|
|
1115
|
+
this.dataManager = new DataManager(this);
|
|
1116
|
+
if (this.dataManagerOptions) {
|
|
1117
|
+
Object.assign(this.dataManager, this.dataManagerOptions);
|
|
1118
|
+
}
|
|
1119
|
+
return this.dataManager;
|
|
1120
|
+
}
|
|
1121
|
+
mutationObservers = [];
|
|
1122
|
+
resetOnPaginationOrContainerDeath = true;
|
|
1123
|
+
resetOn() {
|
|
1124
|
+
if (!this.resetOnPaginationOrContainerDeath) return;
|
|
1125
|
+
const observables = [
|
|
1126
|
+
this.container,
|
|
1127
|
+
this.intersectionObservable || this.paginationStrategy.getPaginationElement()
|
|
1128
|
+
].filter(Boolean);
|
|
1129
|
+
if (observables.length === 0) return;
|
|
1130
|
+
observables.forEach((o) => {
|
|
1131
|
+
const observer = waitForElementToDisappear(o, () => {
|
|
1132
|
+
this.reset();
|
|
1133
|
+
});
|
|
1134
|
+
this.mutationObservers.push(observer);
|
|
1135
|
+
});
|
|
1136
|
+
}
|
|
1137
|
+
onResetCallback;
|
|
1138
|
+
reset() {
|
|
1139
|
+
this.mutationObservers.forEach((o) => {
|
|
1140
|
+
o.disconnect();
|
|
1141
|
+
});
|
|
1142
|
+
this.mutationObservers = [];
|
|
1143
|
+
this.paginationStrategy = getPaginationStrategy(this.paginationStrategyOptions);
|
|
1144
|
+
this.setupDataManager();
|
|
1145
|
+
this.setupStoreListeners();
|
|
1146
|
+
this.resetInfiniteScroller();
|
|
1147
|
+
this.container && this.animatePreview?.(this.container);
|
|
1148
|
+
this.gropeInit();
|
|
1149
|
+
this.onResetCallback?.();
|
|
1150
|
+
this.resetOn();
|
|
1241
1151
|
}
|
|
1152
|
+
constructor(options) {
|
|
1153
|
+
if (this.isEmbedded) throw Error("Embedded is not supported");
|
|
1154
|
+
Object.assign(this, options);
|
|
1155
|
+
this.paginationStrategy = getPaginationStrategy(this.paginationStrategyOptions);
|
|
1156
|
+
this.store = this.createStore();
|
|
1157
|
+
this.gui = this.createGui();
|
|
1158
|
+
this.dataManager = this.setupDataManager();
|
|
1159
|
+
this.reset();
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1242
1162
|
|
|
1243
|
-
|
|
1163
|
+
const $ = _unsafeWindow.$;
|
|
1164
|
+
const rules = new RulesGlobal({
|
|
1165
|
+
containerSelector: "#albums",
|
|
1166
|
+
thumbsSelector: "div[id^=album-]",
|
|
1167
|
+
titleSelector: ".album-title",
|
|
1168
|
+
uploaderSelector: ".album-user",
|
|
1169
|
+
gropeStrategy: "all-in-one",
|
|
1170
|
+
customThumbDataSelectors: {
|
|
1171
|
+
videoAlbum: {
|
|
1172
|
+
type: "boolean",
|
|
1173
|
+
selector: ".album-videos"
|
|
1174
|
+
}
|
|
1175
|
+
},
|
|
1176
|
+
storeOptions: { showPhotos: true },
|
|
1177
|
+
customDataSelectorFns: [
|
|
1178
|
+
"filterInclude",
|
|
1179
|
+
"filterExclude",
|
|
1180
|
+
{
|
|
1181
|
+
filterPhotoAlbums: (el, state) => state.filterPhotoAlbums && !el.videoAlbum
|
|
1182
|
+
},
|
|
1183
|
+
{
|
|
1184
|
+
filterVideoAlbums: (el, state) => state.filterVideoAlbums && el.videoAlbum
|
|
1185
|
+
}
|
|
1186
|
+
],
|
|
1187
|
+
schemeOptions: [
|
|
1188
|
+
"Text Filter",
|
|
1189
|
+
{
|
|
1190
|
+
title: "Filter Albums",
|
|
1191
|
+
content: [
|
|
1192
|
+
{
|
|
1193
|
+
filterVideoAlbums: true,
|
|
1194
|
+
label: "video albums"
|
|
1195
|
+
},
|
|
1196
|
+
{
|
|
1197
|
+
filterPhotoAlbums: true,
|
|
1198
|
+
label: "photo albums"
|
|
1199
|
+
}
|
|
1200
|
+
]
|
|
1201
|
+
},
|
|
1202
|
+
"Badge",
|
|
1203
|
+
"Advanced"
|
|
1204
|
+
]
|
|
1205
|
+
});
|
|
1206
|
+
rules.infiniteScroller?.onScroll(() => {
|
|
1207
|
+
setTimeout(() => new LazyLoad(), 100);
|
|
1208
|
+
});
|
|
1209
|
+
_GM_addStyle(`
|
|
1210
|
+
.inactive-gm { background: #a09f9d; }
|
|
1211
|
+
.active-gm { background: #eb6395 !important; }
|
|
1212
|
+
`);
|
|
1213
|
+
(function disableDisclaimer() {
|
|
1214
|
+
if (!$("#disclaimer").length) return;
|
|
1215
|
+
$.ajax({ type: "POST", url: "/user/disclaimer", async: true });
|
|
1216
|
+
$("#disclaimer").remove();
|
|
1217
|
+
$("body").css("overflow", "visible");
|
|
1218
|
+
})();
|
|
1219
|
+
const IS_ALBUM_PAGE = /^\/a\//.test(window.location.pathname);
|
|
1220
|
+
function togglePhotoElements() {
|
|
1221
|
+
$(".media-group > div:last-child:not(.video)").toggle(rules.store.state.showPhotos);
|
|
1222
|
+
$("#togglePhotos").toggleClass("active-gm", rules.store.state.showPhotos);
|
|
1223
|
+
$("#togglePhotos").text(!rules.store.state.showPhotos ? "show photos" : "hide photos");
|
|
1224
|
+
}
|
|
1225
|
+
function setupAlbumPage() {
|
|
1226
|
+
$("#user_name").parent().append(
|
|
1227
|
+
'<button id="togglePhotos" class="btn btn-pink inactive-gm">show/hide photos</button>'
|
|
1228
|
+
);
|
|
1229
|
+
$("#togglePhotos").on("click", () => {
|
|
1230
|
+
rules.store.state.showPhotos = !rules.store.state.showPhotos;
|
|
1231
|
+
});
|
|
1232
|
+
rules.store.stateSubject.subscribe(() => {
|
|
1233
|
+
togglePhotoElements();
|
|
1234
|
+
});
|
|
1235
|
+
togglePhotoElements();
|
|
1236
|
+
}
|
|
1237
|
+
if (IS_ALBUM_PAGE) {
|
|
1238
|
+
setupAlbumPage();
|
|
1239
|
+
}
|
|
1244
1240
|
|
|
1245
|
-
})();
|
|
1241
|
+
})(jabronioutfit);
|