perfectionist-plugins 2.0.0 → 2.4.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 +123 -121
- package/better-client.js +370 -86
- package/hide-unowned-skins.js +194 -225
- package/package.json +36 -37
- package/perfectionist-utils.js +11 -131
- package/unlock-profile-skins.js +153 -67
- package/tools/betterclient-monitor.js +0 -269
package/package.json
CHANGED
|
@@ -1,37 +1,36 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "perfectionist-plugins",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "Small plugins that fix the annoying parts of League of Legends champ select. Built for Pengu Loader.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "perfectionist-utils.js",
|
|
7
|
-
"exports": {
|
|
8
|
-
".": "./perfectionist-utils.js",
|
|
9
|
-
"./perfectionist-utils.js": "./perfectionist-utils.js",
|
|
10
|
-
"./ban-blocker.js": "./ban-blocker.js",
|
|
11
|
-
"./hide-unowned-skins.js": "./hide-unowned-skins.js",
|
|
12
|
-
"./unlock-profile-skins.js": "./unlock-profile-skins.js",
|
|
13
|
-
"./auto-claimer.js": "./auto-claimer.js",
|
|
14
|
-
"./auto-read.js": "./auto-read.js",
|
|
15
|
-
"./better-client.js": "./better-client.js"
|
|
16
|
-
},
|
|
17
|
-
"files": [
|
|
18
|
-
"perfectionist-utils.js",
|
|
19
|
-
"ban-blocker.js",
|
|
20
|
-
"hide-unowned-skins.js",
|
|
21
|
-
"unlock-profile-skins.js",
|
|
22
|
-
"auto-claimer.js",
|
|
23
|
-
"auto-read.js",
|
|
24
|
-
"better-client.js"
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "perfectionist-plugins",
|
|
3
|
+
"version": "2.4.1",
|
|
4
|
+
"description": "Small plugins that fix the annoying parts of League of Legends champ select. Built for Pengu Loader.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "perfectionist-utils.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./perfectionist-utils.js",
|
|
9
|
+
"./perfectionist-utils.js": "./perfectionist-utils.js",
|
|
10
|
+
"./ban-blocker.js": "./ban-blocker.js",
|
|
11
|
+
"./hide-unowned-skins.js": "./hide-unowned-skins.js",
|
|
12
|
+
"./unlock-profile-skins.js": "./unlock-profile-skins.js",
|
|
13
|
+
"./auto-claimer.js": "./auto-claimer.js",
|
|
14
|
+
"./auto-read.js": "./auto-read.js",
|
|
15
|
+
"./better-client.js": "./better-client.js"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"perfectionist-utils.js",
|
|
19
|
+
"ban-blocker.js",
|
|
20
|
+
"hide-unowned-skins.js",
|
|
21
|
+
"unlock-profile-skins.js",
|
|
22
|
+
"auto-claimer.js",
|
|
23
|
+
"auto-read.js",
|
|
24
|
+
"better-client.js"
|
|
25
|
+
],
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://github.com/SrKing-9812/Perfectionist-Plugins.git"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"pengu-loader",
|
|
32
|
+
"league-of-legends",
|
|
33
|
+
"plugin"
|
|
34
|
+
],
|
|
35
|
+
"author": "Sr. King"
|
|
36
|
+
}
|
package/perfectionist-utils.js
CHANGED
|
@@ -1,22 +1,19 @@
|
|
|
1
1
|
const READY_EVENT = "perfectionist:utils-ready";
|
|
2
2
|
const STATE_KEY = "perfectionist-plugins:state";
|
|
3
|
-
const CACHE_KEY = "perfectionist-plugins:cache";
|
|
4
3
|
const NAV_ID = "perfectionist-plugins-nav";
|
|
5
4
|
const PANEL_ID = "perfectionist-plugins-panel";
|
|
6
5
|
const STYLE_ID = "perfectionist-plugins-style";
|
|
7
6
|
const TAB_TITLE = "Perfectionism";
|
|
8
7
|
|
|
9
|
-
export const version = "2.
|
|
8
|
+
export const version = "2.4.0";
|
|
10
9
|
|
|
11
10
|
const PKG = "perfectionist-plugins";
|
|
12
11
|
const CDN = "https://cdn.jsdelivr.net/npm";
|
|
13
|
-
const REGISTRY_URL = `https://registry.npmjs.org/${PKG}/latest`;
|
|
14
|
-
const CORE_FILE = "perfectionist-utils.js";
|
|
15
12
|
|
|
16
13
|
const BUNDLED_MODULES = [
|
|
17
14
|
{
|
|
18
15
|
id: "perfectionist-utils",
|
|
19
|
-
file:
|
|
16
|
+
file: "perfectionist-utils.js",
|
|
20
17
|
name: "Perfectionism Core",
|
|
21
18
|
version,
|
|
22
19
|
description: "Shared core for the Perfectionism plugins.",
|
|
@@ -26,7 +23,7 @@ const BUNDLED_MODULES = [
|
|
|
26
23
|
id: "better-client",
|
|
27
24
|
file: "better-client.js",
|
|
28
25
|
name: "BetterClient",
|
|
29
|
-
version: "1.
|
|
26
|
+
version: "1.7.0",
|
|
30
27
|
description: "Debloats the client: blocks telemetry, merges duplicate requests, caches immutable data, decodes images asynchronously and fixes several bugs.",
|
|
31
28
|
},
|
|
32
29
|
{
|
|
@@ -40,14 +37,14 @@ const BUNDLED_MODULES = [
|
|
|
40
37
|
id: "unlock-profile-skins",
|
|
41
38
|
file: "unlock-profile-skins.js",
|
|
42
39
|
name: "Unlock Profile Skins",
|
|
43
|
-
version: "1.2.
|
|
40
|
+
version: "1.2.4",
|
|
44
41
|
description: "Unlocks every skin in the Set profile background window.",
|
|
45
42
|
},
|
|
46
43
|
{
|
|
47
44
|
id: "hide-unowned-skins",
|
|
48
45
|
file: "hide-unowned-skins.js",
|
|
49
46
|
name: "Hide Unowned Skins",
|
|
50
|
-
version: "2.
|
|
47
|
+
version: "2.5.1",
|
|
51
48
|
description: "In champion select, only shows the skins you own for the picked champion.",
|
|
52
49
|
},
|
|
53
50
|
{
|
|
@@ -127,7 +124,6 @@ const STYLE_CSS = `
|
|
|
127
124
|
#${PANEL_ID} .perf-chip:hover { color: #f0e6d2; border-color: #c89b3c; }
|
|
128
125
|
#${PANEL_ID} .perf-chip--on { color: #010a13; background: #c89b3c; border-color: #c89b3c; }
|
|
129
126
|
#${PANEL_ID} .perf-chip--on:hover { background: #f0e6d2; }
|
|
130
|
-
|
|
131
127
|
#${PANEL_ID} .perf-tools { display: flex; align-items: center; gap: 10px; flex: 0 0 auto; margin-bottom: 14px; }
|
|
132
128
|
#${PANEL_ID} .perf-search { flex: 1 1 auto; min-width: 0; box-sizing: border-box;
|
|
133
129
|
font-family: "LoL Body", Arial, "Helvetica Neue", Helvetica, sans-serif; font-size: 12px; letter-spacing: 0.3px;
|
|
@@ -142,18 +138,6 @@ const STYLE_CSS = `
|
|
|
142
138
|
#${PANEL_ID} .perf-chip:disabled { opacity: 0.45; cursor: default; }
|
|
143
139
|
#${PANEL_ID} .perf-chip:disabled:hover { color: #a09b8c; border-color: #785a28; background: #0a1428; }
|
|
144
140
|
#${PANEL_ID} .perf-chip--on:disabled:hover { color: #010a13; border-color: #c89b3c; background: #c89b3c; }
|
|
145
|
-
|
|
146
|
-
.perf-update { position: fixed; inset: 0; z-index: 100000; display: flex; align-items: center;
|
|
147
|
-
justify-content: center; background: rgba(1, 10, 19, 0.72); }
|
|
148
|
-
.perf-update-box { width: 430px; box-sizing: border-box; padding: 22px 26px;
|
|
149
|
-
background: #010a13; border: 1px solid #785a28; box-shadow: 0 0 32px rgba(0, 0, 0, 0.8); }
|
|
150
|
-
.perf-update-title { font-family: "LoL Display", "Times New Roman", Times, Baskerville, Georgia, serif;
|
|
151
|
-
font-size: 15px; font-weight: 700; letter-spacing: 1.05px; text-transform: uppercase; color: #f0e6d2; }
|
|
152
|
-
.perf-update-status { font-family: "LoL Body", Arial, sans-serif; font-size: 12px; letter-spacing: 0.3px;
|
|
153
|
-
color: #a09b8c; margin-top: 12px; line-height: 1.5; }
|
|
154
|
-
.perf-update-track { height: 6px; margin-top: 16px; background: #0a1428; border: 1px solid #785a28; }
|
|
155
|
-
.perf-update-fill { height: 100%; width: 0; background: #c89b3c; transition: width 0.25s; }
|
|
156
|
-
.perf-update-close { margin-top: 18px; }
|
|
157
141
|
`;
|
|
158
142
|
|
|
159
143
|
const registry = new Map();
|
|
@@ -167,8 +151,10 @@ let coords = null;
|
|
|
167
151
|
const resolved = new Map();
|
|
168
152
|
let availableModules = BUNDLED_MODULES;
|
|
169
153
|
let pendingReload = false;
|
|
154
|
+
let modulesLoaded = false;
|
|
170
155
|
let searchQuery = "";
|
|
171
156
|
let runningVersion = version;
|
|
157
|
+
let coreStarted = false;
|
|
172
158
|
|
|
173
159
|
let state = { installed: {}, enabled: {}, options: {}, masterLocked: false };
|
|
174
160
|
|
|
@@ -319,20 +305,6 @@ function isInstalled(mod) {
|
|
|
319
305
|
return installed === undefined ? registry.has(mod.id) : Boolean(installed);
|
|
320
306
|
}
|
|
321
307
|
|
|
322
|
-
function newerVersion(a, b) {
|
|
323
|
-
const pa = String(a ?? "0")
|
|
324
|
-
.split(".")
|
|
325
|
-
.map(Number);
|
|
326
|
-
const pb = String(b ?? "0")
|
|
327
|
-
.split(".")
|
|
328
|
-
.map(Number);
|
|
329
|
-
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
330
|
-
const diff = (pa[i] || 0) - (pb[i] || 0);
|
|
331
|
-
if (diff !== 0) return diff > 0;
|
|
332
|
-
}
|
|
333
|
-
return false;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
308
|
function moduleUrl(file) {
|
|
337
309
|
return `${CDN}/${PKG}@${runningVersion}/${file}`;
|
|
338
310
|
}
|
|
@@ -357,105 +329,14 @@ async function uninstallModule(mod) {
|
|
|
357
329
|
refreshPanel();
|
|
358
330
|
}
|
|
359
331
|
|
|
360
|
-
const SAFE_PHASES = new Set(["None", "Lobby", "EndOfGame"]);
|
|
361
|
-
|
|
362
332
|
function reloadClientNow() {
|
|
363
333
|
if (typeof window.reloadClient === "function") window.reloadClient();
|
|
364
334
|
else window.location.reload();
|
|
365
335
|
}
|
|
366
336
|
|
|
367
|
-
async function reloadWhenSafe() {
|
|
368
|
-
for (;;) {
|
|
369
|
-
let phase = null;
|
|
370
|
-
try {
|
|
371
|
-
phase = await apiGet("/lol-gameflow/v1/gameflow-phase");
|
|
372
|
-
} catch {
|
|
373
|
-
phase = null;
|
|
374
|
-
}
|
|
375
|
-
if (phase == null || SAFE_PHASES.has(phase)) break;
|
|
376
|
-
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
377
|
-
}
|
|
378
|
-
reloadClientNow();
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
function apiGet(path) {
|
|
382
|
-
return fetch(path, { headers: { Accept: "application/json" } }).then((response) => {
|
|
383
|
-
if (!response.ok) throw new Error(`${path} responded ${response.status}`);
|
|
384
|
-
return response.status === 204 ? null : response.json();
|
|
385
|
-
});
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
function buildUpdateWindow() {
|
|
389
|
-
const root = el("div", "perf-update");
|
|
390
|
-
const box = el("div", "perf-update-box");
|
|
391
|
-
box.append(el("div", "perf-update-title", "Installing Update"));
|
|
392
|
-
const status = el("div", "perf-update-status", "Downloading...");
|
|
393
|
-
const track = el("div", "perf-update-track");
|
|
394
|
-
const fill = el("div", "perf-update-fill");
|
|
395
|
-
track.append(fill);
|
|
396
|
-
box.append(status, track);
|
|
397
|
-
root.append(box);
|
|
398
|
-
return {
|
|
399
|
-
root,
|
|
400
|
-
setStatus: (text) => {
|
|
401
|
-
status.textContent = text;
|
|
402
|
-
},
|
|
403
|
-
setProgress: (fraction) => {
|
|
404
|
-
fill.style.width = `${Math.round(Math.max(0, Math.min(1, fraction)) * 100)}%`;
|
|
405
|
-
},
|
|
406
|
-
fail: (text) => {
|
|
407
|
-
status.textContent = text;
|
|
408
|
-
const close = el("button", "perf-btn perf-update-close", "Close");
|
|
409
|
-
close.addEventListener("click", () => root.remove());
|
|
410
|
-
box.append(close);
|
|
411
|
-
},
|
|
412
|
-
};
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
async function runUpdate(target) {
|
|
416
|
-
const win = buildUpdateWindow();
|
|
417
|
-
(document.body ?? document.documentElement).append(win.root);
|
|
418
|
-
const files = [{ name: "Perfectionism Core", file: CORE_FILE }, ...BUNDLED_MODULES.filter((m) => !m.core)];
|
|
419
|
-
const sources = {};
|
|
420
|
-
for (let i = 0; i < files.length; i++) {
|
|
421
|
-
win.setStatus(`Downloading ${files[i].name}...`);
|
|
422
|
-
win.setProgress(i / files.length);
|
|
423
|
-
try {
|
|
424
|
-
const response = await fetch(`${CDN}/${PKG}@${target}/${files[i].file}`);
|
|
425
|
-
if (response.status === 404 && files[i].id) continue;
|
|
426
|
-
if (!response.ok) throw new Error(`download failed (${response.status})`);
|
|
427
|
-
const text = await response.text();
|
|
428
|
-
if (!text || !/export/.test(text)) throw new Error("the downloaded file looks invalid");
|
|
429
|
-
if (files[i].id) sources[files[i].id] = text;
|
|
430
|
-
} catch (error) {
|
|
431
|
-
logError(`could not update to ${target}.`, error);
|
|
432
|
-
win.fail(`Could not update to ${target}. It will be retried on the next client start.`);
|
|
433
|
-
return;
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
try {
|
|
437
|
-
localStorage.setItem(CACHE_KEY, JSON.stringify({ version: target, files: sources }));
|
|
438
|
-
} catch {}
|
|
439
|
-
win.setProgress(1);
|
|
440
|
-
runningVersion = target;
|
|
441
|
-
saveState();
|
|
442
|
-
win.setStatus("Update installed. Restarting the client...");
|
|
443
|
-
reloadWhenSafe();
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
async function checkForUpdates() {
|
|
447
|
-
if (!/^\d+\.\d+\.\d+$/.test(runningVersion)) return;
|
|
448
|
-
let target = null;
|
|
449
|
-
try {
|
|
450
|
-
const response = await fetch(REGISTRY_URL, { headers: { Accept: "application/json" }, cache: "no-store" });
|
|
451
|
-
if (response.ok) target = (await response.json())?.version ?? null;
|
|
452
|
-
} catch {
|
|
453
|
-
return;
|
|
454
|
-
}
|
|
455
|
-
if (target && newerVersion(target, runningVersion)) runUpdate(target);
|
|
456
|
-
}
|
|
457
|
-
|
|
458
337
|
async function loadModules() {
|
|
338
|
+
if (modulesLoaded) return;
|
|
339
|
+
modulesLoaded = true;
|
|
459
340
|
for (const mod of BUNDLED_MODULES) {
|
|
460
341
|
if (mod.core || resolved.has(mod.id) || registry.has(mod.id) || !isInstalled(mod)) continue;
|
|
461
342
|
try {
|
|
@@ -1020,7 +901,6 @@ const utils = {
|
|
|
1020
901
|
getAvailableModules,
|
|
1021
902
|
installModule,
|
|
1022
903
|
uninstallModule,
|
|
1023
|
-
checkForUpdates,
|
|
1024
904
|
watch,
|
|
1025
905
|
waitFor,
|
|
1026
906
|
addStyle,
|
|
@@ -1030,7 +910,8 @@ const utils = {
|
|
|
1030
910
|
};
|
|
1031
911
|
|
|
1032
912
|
export async function init(context, coordsProvided) {
|
|
1033
|
-
if (window.PerfectionistUtils) return;
|
|
913
|
+
if (coreStarted || window.PerfectionistUtils) return;
|
|
914
|
+
coreStarted = true;
|
|
1034
915
|
coords = coordsProvided ?? null;
|
|
1035
916
|
runningVersion = coords?.version || version;
|
|
1036
917
|
|
|
@@ -1044,7 +925,6 @@ export async function init(context, coordsProvided) {
|
|
|
1044
925
|
|
|
1045
926
|
try {
|
|
1046
927
|
await loadModules();
|
|
1047
|
-
checkForUpdates();
|
|
1048
928
|
} catch (error) {
|
|
1049
929
|
logError("startup failed.", error);
|
|
1050
930
|
}
|
package/unlock-profile-skins.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const version = "1.2.
|
|
1
|
+
export const version = "1.2.4";
|
|
2
2
|
|
|
3
3
|
const PLUGIN_ID = "unlock-profile-skins";
|
|
4
4
|
const PICKER_BUTTON_SELECTOR = ".style-profile-skin-picker-button";
|
|
@@ -6,12 +6,14 @@ const CURRENT_SUMMONER_URI = "/lol-summoner/v1/current-summoner";
|
|
|
6
6
|
const INVENTORY_PATH = /^\/lol-champions\/v1\/inventories\/(\d+)\/champions$/;
|
|
7
7
|
const AUGMENT_INVENTORY_PATH = /^\/lol-inventory\/v2\/inventory\/SKIN_AUGMENT$/i;
|
|
8
8
|
const SUMMONER_TTL = 10 * 60 * 1000;
|
|
9
|
+
const SUMMONER_WAIT_MS = 1200;
|
|
9
10
|
const STATE_KEY = "perfectionist-plugins:state";
|
|
10
11
|
const FAKE_PURCHASE_DATE = 1577836800000;
|
|
11
12
|
const FAKE_RENTAL_END = 4102444800000;
|
|
12
13
|
const TIER_LABEL = "tier";
|
|
13
14
|
const GROUPING_OPTIONS = "lol-uikit-dropdown-option";
|
|
14
15
|
const HARVEST_WAIT_MS = 2000;
|
|
16
|
+
const INVENTORY_TEXT_CACHE_LIMIT = 2;
|
|
15
17
|
|
|
16
18
|
let filterActive = true;
|
|
17
19
|
let api = null;
|
|
@@ -22,6 +24,7 @@ let harvestPromise = null;
|
|
|
22
24
|
const augmentIds = new Set();
|
|
23
25
|
const pendingTargetLoads = new Set();
|
|
24
26
|
const variantIdRemap = new Map();
|
|
27
|
+
const inventoryTextCache = new Map();
|
|
25
28
|
|
|
26
29
|
function readDefaultEnabled() {
|
|
27
30
|
try {
|
|
@@ -196,17 +199,24 @@ function unlockDeep(node) {
|
|
|
196
199
|
}
|
|
197
200
|
}
|
|
198
201
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
202
|
+
const championNode = Array.isArray(node.skins);
|
|
203
|
+
if (!championNode) {
|
|
204
|
+
if (node.ownership && typeof node.ownership === "object") {
|
|
205
|
+
changed = unlockOwnership(node.ownership) || changed;
|
|
206
|
+
} else if (typeof node.contentId === "string" && Array.isArray(node.overlays)) {
|
|
207
|
+
node.ownership = synthesizedOwnership();
|
|
208
|
+
changed = true;
|
|
209
|
+
}
|
|
210
|
+
if (node.owned === false) {
|
|
211
|
+
node.owned = true;
|
|
212
|
+
changed = true;
|
|
213
|
+
}
|
|
208
214
|
}
|
|
209
|
-
const values = Array.isArray(node)
|
|
215
|
+
const values = Array.isArray(node)
|
|
216
|
+
? node
|
|
217
|
+
: Object.keys(node)
|
|
218
|
+
.filter((key) => key !== "ownership")
|
|
219
|
+
.map((key) => node[key]);
|
|
210
220
|
for (const value of values) {
|
|
211
221
|
if (value && typeof value === "object") changed = unlockDeep(value) || changed;
|
|
212
222
|
}
|
|
@@ -279,6 +289,7 @@ function ensureAugmentIds() {
|
|
|
279
289
|
let tierObserver = null;
|
|
280
290
|
let tierAppliedForOpen = false;
|
|
281
291
|
let tierDropdown = null;
|
|
292
|
+
let tierArmListener = null;
|
|
282
293
|
|
|
283
294
|
function findGroupingDropdown() {
|
|
284
295
|
for (const dd of document.querySelectorAll("lol-uikit-framed-dropdown")) {
|
|
@@ -312,6 +323,10 @@ function applyTierGrouping() {
|
|
|
312
323
|
function startTierGrouping() {
|
|
313
324
|
if (tierObserver) return;
|
|
314
325
|
tierObserver = new MutationObserver(() => {
|
|
326
|
+
if (!isPickerOpen()) {
|
|
327
|
+
stopTierGrouping();
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
315
330
|
try {
|
|
316
331
|
applyTierGrouping();
|
|
317
332
|
} catch (error) {
|
|
@@ -334,12 +349,34 @@ function maybeRefreshSummoner() {
|
|
|
334
349
|
ensureSummonerId();
|
|
335
350
|
}
|
|
336
351
|
|
|
352
|
+
function whenSummonerKnown(timeout) {
|
|
353
|
+
if (summonerId !== null) return Promise.resolve(true);
|
|
354
|
+
ensureSummonerId();
|
|
355
|
+
const deadline = Date.now() + timeout;
|
|
356
|
+
return new Promise((resolve) => {
|
|
357
|
+
const step = () => {
|
|
358
|
+
if (summonerId !== null) return resolve(true);
|
|
359
|
+
if (Date.now() >= deadline) return resolve(false);
|
|
360
|
+
setTimeout(step, 40);
|
|
361
|
+
};
|
|
362
|
+
setTimeout(step, 0);
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
|
|
337
366
|
function ensureSummonerId() {
|
|
338
367
|
if (summonerId !== null || summonerPending) return;
|
|
339
|
-
const get = api?.lcu?.get;
|
|
340
|
-
if (!get) return;
|
|
341
368
|
summonerPending = true;
|
|
342
|
-
|
|
369
|
+
let request;
|
|
370
|
+
try {
|
|
371
|
+
const get = api?.lcu?.get;
|
|
372
|
+
request = get
|
|
373
|
+
? get(CURRENT_SUMMONER_URI, { ttl: SUMMONER_TTL })
|
|
374
|
+
: (rawFetch || window.fetch)(CURRENT_SUMMONER_URI).then((response) => response.json());
|
|
375
|
+
} catch {
|
|
376
|
+
summonerPending = false;
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
Promise.resolve(request)
|
|
343
380
|
.then((summoner) => {
|
|
344
381
|
summonerId = typeof summoner?.summonerId === "number" ? summoner.summonerId : null;
|
|
345
382
|
})
|
|
@@ -348,13 +385,31 @@ function ensureSummonerId() {
|
|
|
348
385
|
summonerPending = false;
|
|
349
386
|
});
|
|
350
387
|
}
|
|
388
|
+
function rewriteInventoryText(raw) {
|
|
389
|
+
if (typeof raw !== "string") return raw;
|
|
390
|
+
if (inventoryTextCache.has(raw)) {
|
|
391
|
+
const cached = inventoryTextCache.get(raw);
|
|
392
|
+
inventoryTextCache.delete(raw);
|
|
393
|
+
inventoryTextCache.set(raw, cached);
|
|
394
|
+
return cached;
|
|
395
|
+
}
|
|
396
|
+
let rewritten = raw;
|
|
397
|
+
try {
|
|
398
|
+
const json = JSON.parse(raw);
|
|
399
|
+
if (unlockDeep(json)) rewritten = JSON.stringify(json);
|
|
400
|
+
} catch {}
|
|
401
|
+
inventoryTextCache.set(raw, rewritten);
|
|
402
|
+
while (inventoryTextCache.size > INVENTORY_TEXT_CACHE_LIMIT) {
|
|
403
|
+
inventoryTextCache.delete(inventoryTextCache.keys().next().value);
|
|
404
|
+
}
|
|
405
|
+
return rewritten;
|
|
406
|
+
}
|
|
351
407
|
|
|
352
408
|
function rewriteWebSocketFrame(text) {
|
|
353
409
|
if (!filterActive || typeof text !== "string") return null;
|
|
354
410
|
const targetFrame = text.indexOf("lol-champions/v1/inventories") !== -1;
|
|
355
411
|
const augmentFrame = text.indexOf("SKIN_AUGMENT") !== -1;
|
|
356
412
|
if (!targetFrame && !augmentFrame) return null;
|
|
357
|
-
if (!isPickerOpen()) return null;
|
|
358
413
|
let frame;
|
|
359
414
|
try {
|
|
360
415
|
frame = JSON.parse(text);
|
|
@@ -454,53 +509,72 @@ function installFetchFilter() {
|
|
|
454
509
|
|
|
455
510
|
const wrapped = function (input, init) {
|
|
456
511
|
const url = typeof input === "string" ? input : (input && input.url) || "";
|
|
457
|
-
const
|
|
458
|
-
const
|
|
459
|
-
|
|
460
|
-
if (filterActive &&
|
|
461
|
-
const mapped = remapVariantIds(
|
|
462
|
-
if (mapped !==
|
|
512
|
+
const inventory = pathIdOf(url) !== null;
|
|
513
|
+
const augmentRequest = isAugmentUrl(url);
|
|
514
|
+
let options = init;
|
|
515
|
+
if (filterActive && options && typeof options.body === "string") {
|
|
516
|
+
const mapped = remapVariantIds(options.body);
|
|
517
|
+
if (mapped !== options.body) options = { ...options, body: mapped };
|
|
463
518
|
}
|
|
464
|
-
const promise = original.call(this, input,
|
|
465
|
-
if (filterActive
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
519
|
+
const promise = original.call(this, input, options);
|
|
520
|
+
if (!filterActive || (!inventory && !augmentRequest)) return promise;
|
|
521
|
+
if (inventory) maybeRefreshSummoner();
|
|
522
|
+
|
|
523
|
+
return whenSummonerKnown(SUMMONER_WAIT_MS).then(() => {
|
|
524
|
+
const target = isTargetUrl(url);
|
|
525
|
+
if (!augmentRequest && !target) return promise;
|
|
526
|
+
if (target && augmentIds.size === 0) {
|
|
527
|
+
const latch = (async () => {
|
|
528
|
+
try {
|
|
529
|
+
const response = await promise;
|
|
530
|
+
if (response && response.ok && augmentIds.size === 0) {
|
|
531
|
+
const json = await response.clone().json().catch(() => null);
|
|
532
|
+
if (json) harvestFromPayload(json);
|
|
533
|
+
}
|
|
534
|
+
} catch {}
|
|
535
|
+
pendingTargetLoads.delete(latch);
|
|
536
|
+
})();
|
|
537
|
+
pendingTargetLoads.add(latch);
|
|
538
|
+
}
|
|
539
|
+
const ready = augmentRequest && augmentIds.size === 0 ? ensureAugmentIds() : Promise.resolve();
|
|
540
|
+
return ready
|
|
541
|
+
.then(() => promise)
|
|
542
|
+
.then((response) => {
|
|
543
|
+
if (!response || !response.ok) return response;
|
|
544
|
+
if (augmentRequest) {
|
|
545
|
+
return response
|
|
546
|
+
.clone()
|
|
547
|
+
.json()
|
|
548
|
+
.catch(() => null)
|
|
549
|
+
.then((json) => {
|
|
550
|
+
if (!json || !unlockAugmentInventory(json)) return response;
|
|
551
|
+
return new Response(JSON.stringify(json), {
|
|
552
|
+
status: response.status,
|
|
553
|
+
statusText: response.statusText,
|
|
554
|
+
headers: response.headers,
|
|
555
|
+
});
|
|
556
|
+
});
|
|
472
557
|
}
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
.json()
|
|
487
|
-
.catch(() => null)
|
|
488
|
-
.then((json) => {
|
|
489
|
-
if (!json) return response;
|
|
490
|
-
const changed = augment ? unlockAugmentInventory(json) : unlockDeep(json);
|
|
491
|
-
if (!changed) return response;
|
|
492
|
-
return new Response(JSON.stringify(json), {
|
|
493
|
-
status: response.status,
|
|
494
|
-
statusText: response.statusText,
|
|
495
|
-
headers: response.headers,
|
|
558
|
+
return response
|
|
559
|
+
.clone()
|
|
560
|
+
.text()
|
|
561
|
+
.catch(() => null)
|
|
562
|
+
.then((text) => {
|
|
563
|
+
if (text === null) return response;
|
|
564
|
+
const rewritten = rewriteInventoryText(text);
|
|
565
|
+
if (rewritten === text) return response;
|
|
566
|
+
return new Response(rewritten, {
|
|
567
|
+
status: response.status,
|
|
568
|
+
statusText: response.statusText,
|
|
569
|
+
headers: response.headers,
|
|
570
|
+
});
|
|
496
571
|
});
|
|
497
|
-
|
|
498
|
-
|
|
572
|
+
});
|
|
573
|
+
});
|
|
499
574
|
};
|
|
500
575
|
wrapped.__perfProfileFilter = true;
|
|
501
576
|
window.fetch = wrapped;
|
|
502
577
|
}
|
|
503
|
-
|
|
504
578
|
function installXhrFilter() {
|
|
505
579
|
const proto = window.XMLHttpRequest && window.XMLHttpRequest.prototype;
|
|
506
580
|
if (!proto || proto.open.__perfProfileFilter) return;
|
|
@@ -543,23 +617,24 @@ function installXhrFilter() {
|
|
|
543
617
|
});
|
|
544
618
|
pendingTargetLoads.add(latch);
|
|
545
619
|
}
|
|
546
|
-
if (textDescriptor && textDescriptor.get && (
|
|
620
|
+
if (textDescriptor && textDescriptor.get && (pathIdOf(url) !== null || augment)) {
|
|
547
621
|
const cache = { raw: null, gate: null, filtered: null };
|
|
548
|
-
const gateOpen = () => filterActive &&
|
|
622
|
+
const gateOpen = () => filterActive && (augment || isTargetUrl(url));
|
|
549
623
|
const rewriteBody = (json) => (augment ? unlockAugmentInventory(json) : unlockDeep(json));
|
|
550
624
|
const filteredText = () => {
|
|
551
|
-
const raw = textDescriptor.get.call(xhr);
|
|
552
625
|
const gate = gateOpen();
|
|
553
|
-
if (cache.filtered
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
626
|
+
if (cache.filtered !== null && cache.gate === gate) return cache.filtered;
|
|
627
|
+
const raw = textDescriptor.get.call(xhr);
|
|
628
|
+
cache.gate = gate;
|
|
629
|
+
cache.filtered = raw;
|
|
630
|
+
if (gate) {
|
|
631
|
+
if (augment) {
|
|
558
632
|
try {
|
|
559
633
|
const json = JSON.parse(raw);
|
|
560
|
-
|
|
561
|
-
if (rewritten !== null) cache.filtered = rewritten;
|
|
634
|
+
if (rewriteBody(json)) cache.filtered = JSON.stringify(json);
|
|
562
635
|
} catch {}
|
|
636
|
+
} else {
|
|
637
|
+
cache.filtered = rewriteInventoryText(raw);
|
|
563
638
|
}
|
|
564
639
|
}
|
|
565
640
|
return cache.filtered;
|
|
@@ -578,7 +653,7 @@ function installXhrFilter() {
|
|
|
578
653
|
});
|
|
579
654
|
}
|
|
580
655
|
}
|
|
581
|
-
if (augment && filterActive &&
|
|
656
|
+
if (augment && filterActive && augmentIds.size === 0) {
|
|
582
657
|
const sendArgs = args;
|
|
583
658
|
ensureAugmentIds().finally(() => {
|
|
584
659
|
try {
|
|
@@ -597,6 +672,7 @@ function installSourceFilter() {
|
|
|
597
672
|
installWebSocketFilter();
|
|
598
673
|
installFetchFilter();
|
|
599
674
|
installXhrFilter();
|
|
675
|
+
ensureSummonerId();
|
|
600
676
|
} catch (error) {
|
|
601
677
|
logError("could not install the source filter.", error);
|
|
602
678
|
}
|
|
@@ -617,11 +693,21 @@ function onEnable(utils) {
|
|
|
617
693
|
filterActive = true;
|
|
618
694
|
ensureSourceFilter();
|
|
619
695
|
ensureSummonerId();
|
|
620
|
-
|
|
696
|
+
tierArmListener = () => {
|
|
697
|
+
if (tierObserver) return;
|
|
698
|
+
setTimeout(() => {
|
|
699
|
+
if (tierArmListener && isPickerOpen()) startTierGrouping();
|
|
700
|
+
}, 0);
|
|
701
|
+
};
|
|
702
|
+
document.addEventListener("click", tierArmListener, true);
|
|
703
|
+
if (isPickerOpen()) startTierGrouping();
|
|
621
704
|
}
|
|
622
705
|
|
|
623
706
|
function onDisable() {
|
|
624
707
|
filterActive = false;
|
|
708
|
+
inventoryTextCache.clear();
|
|
709
|
+
if (tierArmListener) document.removeEventListener("click", tierArmListener, true);
|
|
710
|
+
tierArmListener = null;
|
|
625
711
|
stopTierGrouping();
|
|
626
712
|
api = null;
|
|
627
713
|
}
|