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/package.json CHANGED
@@ -1,37 +1,36 @@
1
- {
2
- "name": "perfectionist-plugins",
3
- "version": "2.0.0",
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
- "tools/betterclient-monitor.js"
26
- ],
27
- "repository": {
28
- "type": "git",
29
- "url": "git+https://github.com/SrKing-9812/Perfectionist-Plugins.git"
30
- },
31
- "keywords": [
32
- "pengu-loader",
33
- "league-of-legends",
34
- "plugin"
35
- ],
36
- "author": "Sr. King"
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
+ }
@@ -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.0.0";
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: CORE_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.2.0",
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.1",
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.4.0",
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
  }
@@ -1,4 +1,4 @@
1
- export const version = "1.2.1";
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
- if (node.ownership && typeof node.ownership === "object") {
200
- changed = unlockOwnership(node.ownership) || changed;
201
- } else if (typeof node.contentId === "string" && Array.isArray(node.overlays)) {
202
- node.ownership = synthesizedOwnership();
203
- changed = true;
204
- }
205
- if (node.owned === false) {
206
- node.owned = true;
207
- changed = true;
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) ? node : Object.values(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
- get(CURRENT_SUMMONER_URI, { ttl: SUMMONER_TTL })
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 target = isTargetUrl(url);
458
- const augment = !target && isAugmentUrl(url);
459
- if (filterActive && pathIdOf(url) !== null) maybeRefreshSummoner();
460
- if (filterActive && init && typeof init.body === "string") {
461
- const mapped = remapVariantIds(init.body);
462
- if (mapped !== init.body) init = { ...init, body: 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, init);
465
- if (filterActive && target && augmentIds.size === 0) {
466
- const latch = (async () => {
467
- try {
468
- const response = await promise;
469
- if (response && response.ok && augmentIds.size === 0) {
470
- const json = await response.clone().json().catch(() => null);
471
- if (json) harvestFromPayload(json);
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
- } catch {}
474
- pendingTargetLoads.delete(latch);
475
- })();
476
- pendingTargetLoads.add(latch);
477
- }
478
- if (!filterActive || (!target && !augment) || !isPickerOpen()) return promise;
479
- const ready = augment && augmentIds.size === 0 ? ensureAugmentIds() : Promise.resolve();
480
- return ready
481
- .then(() => promise)
482
- .then((response) => {
483
- if (!response || !response.ok) return response;
484
- return response
485
- .clone()
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 && (target || augment)) {
620
+ if (textDescriptor && textDescriptor.get && (pathIdOf(url) !== null || augment)) {
547
621
  const cache = { raw: null, gate: null, filtered: null };
548
- const gateOpen = () => filterActive && isPickerOpen();
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 === null || cache.raw !== raw || cache.gate !== gate) {
554
- cache.raw = raw;
555
- cache.gate = gate;
556
- cache.filtered = raw;
557
- if (gate) {
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
- const rewritten = rewriteBody(json) ? JSON.stringify(json) : null;
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 && isPickerOpen() && augmentIds.size === 0) {
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
- startTierGrouping();
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
  }