perfectionist-plugins 2.4.7 → 2.4.8
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/ban-blocker.js +89 -34
- package/dodge-helper.js +66 -28
- package/hide-unowned-skins.js +8 -7
- package/package.json +1 -1
- package/perfectionist-utils.js +5 -4
- package/unlock-profile-skins.js +49 -16
package/ban-blocker.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const version = "3.6.
|
|
1
|
+
export const version = "3.6.6";
|
|
2
2
|
|
|
3
3
|
const PLUGIN_ID = "ban-blocker";
|
|
4
4
|
const STYLE_ID = "perfectionist-ban-blocker-style";
|
|
@@ -28,7 +28,8 @@ const CSS = `
|
|
|
28
28
|
right: -2px !important;
|
|
29
29
|
left: auto !important;
|
|
30
30
|
bottom: auto !important;
|
|
31
|
-
z-index:
|
|
31
|
+
z-index: 50 !important;
|
|
32
|
+
pointer-events: auto !important;
|
|
32
33
|
}
|
|
33
34
|
.swap-button-component.${BTN_CLASS} .icon {
|
|
34
35
|
-webkit-mask-image: url("${BAN_GLYPH}") !important;
|
|
@@ -65,6 +66,7 @@ let uiScheduled = false;
|
|
|
65
66
|
let lastDetect = -Infinity;
|
|
66
67
|
|
|
67
68
|
const enabled = new Map();
|
|
69
|
+
const blockedCellIds = new Set();
|
|
68
70
|
const alias = new Map();
|
|
69
71
|
const fetchedNames = new Set();
|
|
70
72
|
const playerNames = new Map();
|
|
@@ -232,7 +234,9 @@ function decide(s) {
|
|
|
232
234
|
}
|
|
233
235
|
myActionId = myPick ? myPick.id : null;
|
|
234
236
|
|
|
235
|
-
const blockedCells = new Set(
|
|
237
|
+
const blockedCells = new Set(
|
|
238
|
+
m.filter((p) => blockedCellIds.has(p.cellId) || isBlocked(cellToPlayer.get(p.cellId))).map((p) => p.cellId),
|
|
239
|
+
);
|
|
236
240
|
|
|
237
241
|
let threat = 0;
|
|
238
242
|
for (const a of actions) {
|
|
@@ -264,6 +268,7 @@ function onSessionGone() {
|
|
|
264
268
|
lastSession = null;
|
|
265
269
|
goneAway = true;
|
|
266
270
|
uiVisible = false;
|
|
271
|
+
blockedCellIds.clear();
|
|
267
272
|
swapSeen.clear();
|
|
268
273
|
removeButtons();
|
|
269
274
|
if (!goneTimer) {
|
|
@@ -378,22 +383,29 @@ function bindRowsToTeam(session) {
|
|
|
378
383
|
const selfIdx = list.findIndex((r) => isSelfRow(r));
|
|
379
384
|
const selfCellIdx =
|
|
380
385
|
session?.localPlayerCellId != null ? cells.findIndex((c) => c.cellId === session.localPlayerCellId) : -1;
|
|
386
|
+
|
|
387
|
+
// The DOM can label allied rows 0-4 while the session uses cell IDs 5-9 (red side).
|
|
388
|
+
// If every row still has a unique matching cell, slot IDs are reliable; otherwise
|
|
389
|
+
// align by the local row's position in myTeam, then fall back to row order.
|
|
390
|
+
const bySlot = list.map((r) =>
|
|
391
|
+
r.slotId != null ? cells.find((c) => c.cellId === r.slotId) ?? null : null,
|
|
392
|
+
);
|
|
393
|
+
const slotMapComplete =
|
|
394
|
+
bySlot.every(Boolean) && new Set(bySlot.map((c) => c.cellId)).size === list.length;
|
|
381
395
|
let pick;
|
|
382
|
-
if (
|
|
383
|
-
|
|
384
|
-
if (selfSlot != null && selfSlot === cells[selfCellIdx].cellId) {
|
|
385
|
-
pick = (r) => (r.slotId != null ? cells.find((c) => c.cellId === r.slotId) : null);
|
|
386
|
-
} else if (selfIdx === selfCellIdx) {
|
|
387
|
-
pick = (r) => (r.slotId != null ? cells[r.slotId] : null) ?? cells[r.index];
|
|
388
|
-
} else {
|
|
389
|
-
pick = () => null;
|
|
390
|
-
}
|
|
396
|
+
if (slotMapComplete) {
|
|
397
|
+
pick = (r) => bySlot[r.index] ?? null;
|
|
391
398
|
} else {
|
|
392
|
-
|
|
399
|
+
const shift = selfIdx >= 0 && selfCellIdx >= 0 ? selfCellIdx - selfIdx : 0;
|
|
400
|
+
pick = (r) => cells[r.index + shift] ?? null;
|
|
393
401
|
}
|
|
394
402
|
|
|
395
403
|
for (const r of list) {
|
|
396
|
-
const
|
|
404
|
+
const rowName = norm(r.name);
|
|
405
|
+
const cell =
|
|
406
|
+
pick(r) ??
|
|
407
|
+
cells.find((c) => rowName && (norm(c.summonerName) === rowName || payloadName(c) === rowName)) ??
|
|
408
|
+
cells.find((c) => nameMatches(r.name, keyOf(c)));
|
|
397
409
|
if (cell) {
|
|
398
410
|
r.cell = cell.cellId;
|
|
399
411
|
r.player = linkPlayer(cell, r.name, cell.cellId);
|
|
@@ -410,23 +422,56 @@ function stopEvent(e) {
|
|
|
410
422
|
e.preventDefault();
|
|
411
423
|
}
|
|
412
424
|
|
|
425
|
+
function cellForRow(r) {
|
|
426
|
+
if (!r) return null;
|
|
427
|
+
if (r.cell != null) return r.cell;
|
|
428
|
+
const cells = lastSession?.myTeam ?? [];
|
|
429
|
+
if (!cells.length) return r.slotId ?? null;
|
|
430
|
+
const direct = r.slotId != null ? cells.find((c) => c.cellId === r.slotId) : null;
|
|
431
|
+
if (direct) return direct.cellId;
|
|
432
|
+
const selfIdx = rows.findIndex((x) => isSelfRow(x));
|
|
433
|
+
const selfCellIdx =
|
|
434
|
+
lastSession?.localPlayerCellId != null
|
|
435
|
+
? cells.findIndex((c) => c.cellId === lastSession.localPlayerCellId)
|
|
436
|
+
: -1;
|
|
437
|
+
const shift = selfIdx >= 0 && selfCellIdx >= 0 ? selfCellIdx - selfIdx : 0;
|
|
438
|
+
return cells[r.index + shift]?.cellId ?? cells[r.index]?.cellId ?? null;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
function badgeCell(btn) {
|
|
442
|
+
const rowEl = btn.closest(".summoner-object");
|
|
443
|
+
const r = rowEl ? rows.find((x) => x.el === rowEl) : rows[Number(btn.dataset.slot)];
|
|
444
|
+
const cell = cellForRow(r) ?? (btn.dataset.cell ? Number(btn.dataset.cell) : null);
|
|
445
|
+
return cell == null ? null : Number(cell);
|
|
446
|
+
}
|
|
447
|
+
|
|
413
448
|
function playerForBadge(btn) {
|
|
414
449
|
const rowEl = btn.closest(".summoner-object");
|
|
415
450
|
const r = rowEl ? rows.find((x) => x.el === rowEl) : rows[Number(btn.dataset.slot)];
|
|
416
|
-
const
|
|
451
|
+
const cell = badgeCell(btn);
|
|
452
|
+
const member = cell == null ? null : (lastSession?.myTeam ?? []).find((p) => p.cellId === cell);
|
|
453
|
+
if (member) {
|
|
454
|
+
const id = linkPlayer(member, r?.name, cell);
|
|
455
|
+
cellToPlayer.set(cell, id);
|
|
456
|
+
return canonOf(id);
|
|
457
|
+
}
|
|
458
|
+
const byCell = cell == null ? null : cellToPlayer.get(cell) ?? null;
|
|
417
459
|
return canonOf(byCell ?? r?.player ?? null);
|
|
418
460
|
}
|
|
419
461
|
|
|
420
462
|
function toggle(btn) {
|
|
421
|
-
|
|
422
|
-
if (id == null && lastSession) {
|
|
463
|
+
if (lastSession) {
|
|
423
464
|
bindRowsToTeam(lastSession);
|
|
424
|
-
|
|
465
|
+
decide(lastSession);
|
|
425
466
|
}
|
|
426
|
-
|
|
467
|
+
const cell = badgeCell(btn);
|
|
427
468
|
const myCell = lastSession?.localPlayerCellId;
|
|
428
|
-
if (myCell != null &&
|
|
429
|
-
|
|
469
|
+
if (cell == null || (myCell != null && cell === myCell)) return;
|
|
470
|
+
const next = !blockedCellIds.has(cell);
|
|
471
|
+
if (next) blockedCellIds.add(cell);
|
|
472
|
+
else blockedCellIds.delete(cell);
|
|
473
|
+
const id = playerForBadge(btn);
|
|
474
|
+
if (id != null) enabled.set(id, next);
|
|
430
475
|
renderButtons();
|
|
431
476
|
if (lastSession) {
|
|
432
477
|
decide(lastSession);
|
|
@@ -461,7 +506,12 @@ function isSelfRow(r) {
|
|
|
461
506
|
}
|
|
462
507
|
|
|
463
508
|
function rowKey(r) {
|
|
464
|
-
return String(r.
|
|
509
|
+
return String(r.cell ?? r.slotId ?? r.index);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
function buttonKey(r) {
|
|
513
|
+
const cell = r.cell ?? r.slotId;
|
|
514
|
+
return cell == null ? `row:${r.index}` : `cell:${cell}`;
|
|
465
515
|
}
|
|
466
516
|
|
|
467
517
|
function nativeSwapIn(circle) {
|
|
@@ -471,23 +521,25 @@ function nativeSwapIn(circle) {
|
|
|
471
521
|
|
|
472
522
|
function ensureButtons() {
|
|
473
523
|
const list = getRows();
|
|
524
|
+
const active = new Set();
|
|
474
525
|
for (const r of list) {
|
|
475
526
|
if (!r.circle || !r.circle.isConnected) r.circle = r.el.querySelector(".champion-icon-container");
|
|
476
527
|
if (!r.circle || !r.circle.isConnected) continue;
|
|
477
|
-
const
|
|
478
|
-
|
|
528
|
+
const swapKey = rowKey(r);
|
|
529
|
+
const key = buttonKey(r);
|
|
530
|
+
let btn = buttons.get(key);
|
|
479
531
|
if (isSelfRow(r)) {
|
|
480
532
|
if (btn) {
|
|
481
533
|
btn.remove();
|
|
482
|
-
buttons.delete(
|
|
534
|
+
buttons.delete(key);
|
|
483
535
|
}
|
|
484
536
|
continue;
|
|
485
537
|
}
|
|
486
|
-
if (nativeSwapIn(r.circle)) swapSeen.add(
|
|
487
|
-
if (!swapSeen.has(
|
|
538
|
+
if (nativeSwapIn(r.circle)) swapSeen.add(swapKey);
|
|
539
|
+
if (!swapSeen.has(swapKey)) {
|
|
488
540
|
if (btn) {
|
|
489
541
|
btn.remove();
|
|
490
|
-
buttons.delete(
|
|
542
|
+
buttons.delete(key);
|
|
491
543
|
}
|
|
492
544
|
continue;
|
|
493
545
|
}
|
|
@@ -496,16 +548,17 @@ function ensureButtons() {
|
|
|
496
548
|
for (const orphan of r.circle.querySelectorAll(`:scope > .${BTN_CLASS}`)) orphan.remove();
|
|
497
549
|
btn = buildBadge(r.index);
|
|
498
550
|
r.circle.appendChild(btn);
|
|
499
|
-
buttons.set(
|
|
551
|
+
buttons.set(key, btn);
|
|
500
552
|
}
|
|
553
|
+
active.add(key);
|
|
501
554
|
btn.dataset.slot = String(r.index);
|
|
502
|
-
const cell = r
|
|
555
|
+
const cell = cellForRow(r);
|
|
503
556
|
btn.dataset.cell = cell == null ? "" : String(cell);
|
|
504
557
|
}
|
|
505
|
-
for (const [
|
|
506
|
-
if (!
|
|
558
|
+
for (const [key, btn] of [...buttons]) {
|
|
559
|
+
if (!active.has(key) || !btn.isConnected) {
|
|
507
560
|
btn.remove();
|
|
508
|
-
buttons.delete(
|
|
561
|
+
buttons.delete(key);
|
|
509
562
|
}
|
|
510
563
|
}
|
|
511
564
|
}
|
|
@@ -514,7 +567,8 @@ function renderButtons() {
|
|
|
514
567
|
const hasSession = !!lastSession?.myTeam;
|
|
515
568
|
for (const [, btn] of buttons) {
|
|
516
569
|
const id = playerForBadge(btn);
|
|
517
|
-
const
|
|
570
|
+
const cell = badgeCell(btn);
|
|
571
|
+
const on = (cell != null && blockedCellIds.has(cell)) || (id != null && isBlocked(id));
|
|
518
572
|
btn.classList.toggle("on", on);
|
|
519
573
|
btn.classList.toggle("unresolved", id == null && hasSession);
|
|
520
574
|
const title = on ? "Blocked — click to allow their bans" : "Block this teammate's bans";
|
|
@@ -640,6 +694,7 @@ function onDisable() {
|
|
|
640
694
|
failCount.clear();
|
|
641
695
|
cellToPlayer.clear();
|
|
642
696
|
enabled.clear();
|
|
697
|
+
blockedCellIds.clear();
|
|
643
698
|
playerNames.clear();
|
|
644
699
|
alias.clear();
|
|
645
700
|
fetchedNames.clear();
|
package/dodge-helper.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const PLUGIN_ID = "dodge-helper";
|
|
2
|
-
export const version = "1.4.
|
|
2
|
+
export const version = "1.4.14";
|
|
3
3
|
|
|
4
4
|
const PHASE_URI = "/lol-gameflow/v1/gameflow-phase";
|
|
5
5
|
const SESSION_URI = "/lol-gameflow/v1/session";
|
|
@@ -7,8 +7,8 @@ const CHAMP_SELECT_URI = "/lol-champ-select/v1/session";
|
|
|
7
7
|
const TIMER_URI = "/lol-champ-select/v1/session/timer";
|
|
8
8
|
const SUMMONER_URI = "/lol-summoner/v1/current-summoner";
|
|
9
9
|
const RANKED_STATS_URI = "/lol-ranked/v1/current-ranked-stats";
|
|
10
|
-
const
|
|
11
|
-
const
|
|
10
|
+
const QUIT_V2_URI = '/lol-login/v1/session/invoke?destination=lcdsServiceProxy&method=call&args=["","teambuilder-draft","quitV2",""]';
|
|
11
|
+
const CUSTOM_CANCEL_URI = "/lol-lobby/v1/lobby/custom/cancel-champ-select";
|
|
12
12
|
const STORE_KEY = "perfectionist:dodge-helper:accounts:v1";
|
|
13
13
|
const PENDING_KEY = "perfectionist:dodge-helper:pending:v1";
|
|
14
14
|
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
@@ -43,15 +43,30 @@ const GAME_PHASES = new Set([
|
|
|
43
43
|
|
|
44
44
|
const CSS = `
|
|
45
45
|
#${LAYER_ID} {
|
|
46
|
-
position: fixed !important; inset: 0 !important; z-index:
|
|
46
|
+
position: fixed !important; inset: 0 !important; z-index: 100 !important;
|
|
47
47
|
pointer-events: none !important;
|
|
48
48
|
}
|
|
49
49
|
#${ROOT_ID} {
|
|
50
50
|
position: fixed !important; display: flex !important; align-items: flex-end !important;
|
|
51
|
-
justify-content: center !important; width:
|
|
51
|
+
justify-content: center !important; width: 114px !important; height: 32px !important;
|
|
52
52
|
pointer-events: auto !important; z-index: 1 !important;
|
|
53
53
|
}
|
|
54
|
-
#${ROOT_ID}
|
|
54
|
+
#${ROOT_ID} .perf-dodge-button {
|
|
55
|
+
width: 100% !important; height: 32px !important; box-sizing: border-box !important;
|
|
56
|
+
appearance: none !important; -webkit-appearance: none !important; border-radius: 0 !important;
|
|
57
|
+
padding: 0 !important; border: 1px solid #785a28 !important;
|
|
58
|
+
background: linear-gradient(to bottom, #1e2328 0%, #11161c 55%, #0a0e12 100%) !important;
|
|
59
|
+
color: #cdbe91 !important; font-family: var(--font-display, "Beaufort for LOL", serif) !important;
|
|
60
|
+
font-size: 13px !important; font-weight: 700 !important; letter-spacing: 1px !important;
|
|
61
|
+
text-transform: uppercase !important; cursor: pointer !important;
|
|
62
|
+
text-shadow: 0 1px 2px #000 !important;
|
|
63
|
+
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.55), inset 0 1px 0 rgba(240, 230, 210, 0.12) !important;
|
|
64
|
+
}
|
|
65
|
+
#${ROOT_ID} .perf-dodge-button:hover {
|
|
66
|
+
color: #f0e6d2 !important; border-color: #c89b3c !important;
|
|
67
|
+
background: linear-gradient(to bottom, #2a3038 0%, #192027 55%, #0e141a 100%) !important;
|
|
68
|
+
}
|
|
69
|
+
#${ROOT_ID} .perf-dodge-button:disabled { opacity: 0.6 !important; cursor: default !important; }
|
|
55
70
|
#${ROOT_ID} .perf-dodge-cost {
|
|
56
71
|
position: absolute !important; left: 50% !important; bottom: calc(100% + 4px) !important;
|
|
57
72
|
transform: translateX(-50%) !important; box-sizing: border-box !important;
|
|
@@ -399,24 +414,20 @@ function build() {
|
|
|
399
414
|
const cost = document.createElement("div");
|
|
400
415
|
cost.id = COST_ID;
|
|
401
416
|
cost.className = "perf-dodge-cost";
|
|
402
|
-
const button = document.createElement("
|
|
417
|
+
const button = document.createElement("button");
|
|
418
|
+
button.type = "button";
|
|
403
419
|
button.id = BUTTON_ID;
|
|
420
|
+
button.className = "perf-dodge-button";
|
|
421
|
+
button.textContent = "DODGE";
|
|
404
422
|
bindButton(button);
|
|
405
423
|
root.append(cost, button);
|
|
406
424
|
return root;
|
|
407
425
|
}
|
|
408
426
|
|
|
409
427
|
function bindButton(button) {
|
|
410
|
-
if (!button) return;
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
button.addEventListener("click", onButtonClick, true);
|
|
414
|
-
}
|
|
415
|
-
const inner = button.shadowRoot?.querySelector(".lol-uikit-flat-button");
|
|
416
|
-
if (inner && !inner.__perfClickBound) {
|
|
417
|
-
inner.__perfClickBound = true;
|
|
418
|
-
inner.addEventListener("click", onButtonClick);
|
|
419
|
-
}
|
|
428
|
+
if (!button || button.__perfClickBound) return;
|
|
429
|
+
button.__perfClickBound = true;
|
|
430
|
+
button.addEventListener("click", onButtonClick);
|
|
420
431
|
}
|
|
421
432
|
|
|
422
433
|
function onButtonClick(event) {
|
|
@@ -470,19 +481,30 @@ function positionRoot() {
|
|
|
470
481
|
const root = document.getElementById(ROOT_ID);
|
|
471
482
|
if (!root) return;
|
|
472
483
|
const footer = visibleFooter();
|
|
473
|
-
const width = root.offsetWidth || 125;
|
|
474
484
|
const height = root.offsetHeight || 32;
|
|
475
|
-
if (footer
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
485
|
+
if (footer) {
|
|
486
|
+
const footerElement = document.querySelector(FOOTER_SELECTOR);
|
|
487
|
+
const chat = footerElement?.querySelector("lol-social-chat-toggle-button");
|
|
488
|
+
const voice = footerElement?.querySelector(".champ-select-voice-button-wrapper");
|
|
489
|
+
const chatRect = chat?.getBoundingClientRect();
|
|
490
|
+
const voiceRect = voice?.getBoundingClientRect();
|
|
491
|
+
const left = chatRect?.left;
|
|
492
|
+
const rightEdge = voiceRect?.right ?? footer.right;
|
|
493
|
+
const width = left && rightEdge > left ? Math.round(rightEdge - left) : 114;
|
|
494
|
+
const right = Math.round(Math.max(8, window.innerWidth - rightEdge));
|
|
495
|
+
const top = Math.round(Math.max(8, footer.top - height - 8));
|
|
496
|
+
root.style.width = `${width}px`;
|
|
497
|
+
root.style.left = "auto";
|
|
498
|
+
root.style.right = `${right}px`;
|
|
499
|
+
root.style.top = `${top}px`;
|
|
479
500
|
root.style.bottom = "auto";
|
|
480
501
|
return;
|
|
481
502
|
}
|
|
503
|
+
root.style.width = "114px";
|
|
482
504
|
root.style.left = "auto";
|
|
483
505
|
root.style.top = "auto";
|
|
484
|
-
root.style.right = "
|
|
485
|
-
root.style.bottom = "
|
|
506
|
+
root.style.right = "20px";
|
|
507
|
+
root.style.bottom = "76px";
|
|
486
508
|
}
|
|
487
509
|
|
|
488
510
|
function schedulePosition() {
|
|
@@ -698,14 +720,30 @@ function handleTimer(raw) {
|
|
|
698
720
|
syncTimer(raw);
|
|
699
721
|
}
|
|
700
722
|
|
|
723
|
+
async function requestDodge(uri) {
|
|
724
|
+
const options = { method: "POST" };
|
|
725
|
+
if (uri === QUIT_V2_URI) options.body = '["","teambuilder-draft","quitV2",""]';
|
|
726
|
+
const response = await fetch(uri, options);
|
|
727
|
+
if (!response.ok) throw new Error(`LCU ${uri} responded ${response.status}`);
|
|
728
|
+
return response;
|
|
729
|
+
}
|
|
730
|
+
|
|
701
731
|
async function quitOrDodge() {
|
|
702
732
|
if (!active || dodging || !state.queueId || isCustomQueue() || state.showQuitButton) return;
|
|
703
733
|
dodging = true;
|
|
704
734
|
render();
|
|
705
|
-
const ranked = RANKED_QUEUES.has(Number(state.queueId));
|
|
706
|
-
const uri = ranked ? DODGE_URI : QUIT_URI;
|
|
707
735
|
try {
|
|
708
|
-
|
|
736
|
+
let sent = false;
|
|
737
|
+
let lastError = null;
|
|
738
|
+
for (const uri of [QUIT_V2_URI, CUSTOM_CANCEL_URI]) {
|
|
739
|
+
try {
|
|
740
|
+
await requestDodge(uri);
|
|
741
|
+
sent = true;
|
|
742
|
+
} catch (error) {
|
|
743
|
+
lastError = error;
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
if (!sent) throw lastError ?? new Error("No dodge endpoint accepted the request");
|
|
709
747
|
await recordDodge();
|
|
710
748
|
} catch (error) {
|
|
711
749
|
console.warn("[Dodge Helper] quit failed:", error);
|
|
@@ -832,4 +870,4 @@ export function init() {
|
|
|
832
870
|
addEventListener("perfectionist:utils-ready", (event) => registerWith(event.detail ?? window.PerfectionistUtils), {
|
|
833
871
|
once: true,
|
|
834
872
|
});
|
|
835
|
-
}
|
|
873
|
+
}
|
package/hide-unowned-skins.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const version = "2.4.
|
|
1
|
+
export const version = "2.4.5";
|
|
2
2
|
|
|
3
3
|
const PLUGIN_ID = "hide-unowned-skins";
|
|
4
4
|
const STYLE_ID = "perfectionist-hide-unowned-skins-style";
|
|
@@ -27,7 +27,7 @@ const OBSERVER_OPTIONS = {
|
|
|
27
27
|
attributeFilter: ["src"],
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
-
const FILTER_VERSION = "2.4.
|
|
30
|
+
const FILTER_VERSION = "2.4.5";
|
|
31
31
|
const FILTER_STATE_KEY = "__perfSkinFilterState";
|
|
32
32
|
const filterState = (globalThis[FILTER_STATE_KEY] ??= { active: true });
|
|
33
33
|
|
|
@@ -69,7 +69,7 @@ function installArrayFilter() {
|
|
|
69
69
|
const nativeFilter = proto.filter;
|
|
70
70
|
const wrapped = function (callback, thisArg) {
|
|
71
71
|
const result = nativeFilter.call(this, callback, thisArg);
|
|
72
|
-
if (!filterState.active || !isSkinCollection(result)) return result;
|
|
72
|
+
if (!filterState.active || currentChampionId === null || !isSkinCollection(result)) return result;
|
|
73
73
|
let changed = false;
|
|
74
74
|
if (!skinShapeKeys) learnSkinShape(result);
|
|
75
75
|
const kept = nativeFilter.call(result, (skin) => {
|
|
@@ -109,7 +109,7 @@ function isOwnedSkin(skin) {
|
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
function filterSkinList(list) {
|
|
112
|
-
if (!Array.isArray(list)) return null;
|
|
112
|
+
if (!Array.isArray(list) || currentChampionId === null) return null;
|
|
113
113
|
if (!skinShapeKeys && isSkinCollection(list)) learnSkinShape(list);
|
|
114
114
|
let changed = false;
|
|
115
115
|
const filtered = list
|
|
@@ -133,7 +133,7 @@ function recordClientOrder(list) {
|
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
function rewriteWebSocketFrame(text) {
|
|
136
|
-
if (!filterState.active || typeof text !== "string") return null;
|
|
136
|
+
if (!filterState.active || currentChampionId === null || typeof text !== "string") return null;
|
|
137
137
|
if (text.indexOf("skin-carousel-skins") === -1) return null;
|
|
138
138
|
let frame;
|
|
139
139
|
try {
|
|
@@ -237,7 +237,7 @@ function installFetchFilter() {
|
|
|
237
237
|
? input.href
|
|
238
238
|
: "";
|
|
239
239
|
const promise = original.call(this, input, init);
|
|
240
|
-
if (!filterState.active || url.split("?")[0].indexOf(CAROUSEL_URI) === -1) return promise;
|
|
240
|
+
if (!filterState.active || currentChampionId === null || url.split("?")[0].indexOf(CAROUSEL_URI) === -1) return promise;
|
|
241
241
|
return promise.then((response) => {
|
|
242
242
|
if (!response || !response.ok) return response;
|
|
243
243
|
let body;
|
|
@@ -288,7 +288,7 @@ function installXhrFilter() {
|
|
|
288
288
|
const cache = { raw: null, filtered: null };
|
|
289
289
|
const filteredText = () => {
|
|
290
290
|
const raw = textDescriptor.get.call(xhr);
|
|
291
|
-
if (!filterState.active) return raw;
|
|
291
|
+
if (!filterState.active || currentChampionId === null) return raw;
|
|
292
292
|
if (cache.filtered === null || cache.raw !== raw) {
|
|
293
293
|
cache.raw = raw;
|
|
294
294
|
cache.filtered = raw;
|
|
@@ -436,6 +436,7 @@ function scheduleApply() {
|
|
|
436
436
|
requestAnimationFrame(() => {
|
|
437
437
|
applyQueued = false;
|
|
438
438
|
ensureSourceFilter();
|
|
439
|
+
if (currentChampionId === null) return;
|
|
439
440
|
const item = document.querySelector(SKIN_ITEM_SELECTOR);
|
|
440
441
|
if (!item && !document.querySelector(DOT_SELECTOR)) return;
|
|
441
442
|
applyAll();
|
package/package.json
CHANGED
package/perfectionist-utils.js
CHANGED
|
@@ -30,21 +30,21 @@ const BUNDLED_MODULES = [
|
|
|
30
30
|
id: "ban-blocker",
|
|
31
31
|
file: "ban-blocker.js",
|
|
32
32
|
name: "Ban Blocker",
|
|
33
|
-
version: "3.6.
|
|
33
|
+
version: "3.6.6",
|
|
34
34
|
description: "Adds a BLOCK button to your teammates in champ select. While a teammate is blocked, the champion they are about to ban is prepicked for you, so their ban can never land on it.",
|
|
35
35
|
},
|
|
36
36
|
{
|
|
37
37
|
id: "unlock-profile-skins",
|
|
38
38
|
file: "unlock-profile-skins.js",
|
|
39
39
|
name: "Unlock Profile Skins",
|
|
40
|
-
version: "1.2.
|
|
40
|
+
version: "1.2.6",
|
|
41
41
|
description: "Shows every skin as unlocked in the Set profile background window, event skins included, so you can pick any skin as your profile background.",
|
|
42
42
|
},
|
|
43
43
|
{
|
|
44
44
|
id: "hide-unowned-skins",
|
|
45
45
|
file: "hide-unowned-skins.js",
|
|
46
46
|
name: "Hide Unowned Skins",
|
|
47
|
-
version: "2.4.
|
|
47
|
+
version: "2.4.5",
|
|
48
48
|
description: "In champ select, the skin carousel only shows the skins you own for the champion you picked.",
|
|
49
49
|
},
|
|
50
50
|
{
|
|
@@ -58,7 +58,7 @@ const BUNDLED_MODULES = [
|
|
|
58
58
|
id: "dodge-helper",
|
|
59
59
|
file: "dodge-helper.js",
|
|
60
60
|
name: "Dodge Helper",
|
|
61
|
-
version: "1.4.
|
|
61
|
+
version: "1.4.13",
|
|
62
62
|
description: "Adds a DODGE/QUIT button to champ select, showing the LP and queue penalty for the next dodge.",
|
|
63
63
|
},
|
|
64
64
|
{
|
|
@@ -384,6 +384,7 @@ function isInstalled(mod) {
|
|
|
384
384
|
}
|
|
385
385
|
|
|
386
386
|
function moduleUrl(file) {
|
|
387
|
+
if (coords?.moduleBase) return new URL(file, coords.moduleBase).href;
|
|
387
388
|
return `${CDN}/${PKG}@${runningVersion}/${file}`;
|
|
388
389
|
}
|
|
389
390
|
|
package/unlock-profile-skins.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const version = "1.2.
|
|
1
|
+
export const version = "1.2.6";
|
|
2
2
|
|
|
3
3
|
const PLUGIN_ID = "unlock-profile-skins";
|
|
4
4
|
const PICKER_BUTTON_SELECTOR = ".style-profile-skin-picker-button";
|
|
@@ -39,8 +39,39 @@ function logError(scope, error) {
|
|
|
39
39
|
console.error(`[Perfectionist] Unlock Profile Skins: ${scope}`, error);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
const PICKER_ARM_MS = 5000;
|
|
43
|
+
let pickerArmUntil = 0;
|
|
44
|
+
let pickerArmTimer = null;
|
|
45
|
+
|
|
42
46
|
function isPickerOpen() {
|
|
43
|
-
|
|
47
|
+
for (const dialog of document.querySelectorAll("lol-uikit-dialog-frame")) {
|
|
48
|
+
const rect = dialog.getBoundingClientRect();
|
|
49
|
+
if (rect.width <= 0 || rect.height <= 0) continue;
|
|
50
|
+
if (/set profile background/i.test(dialog.textContent || "")) return true;
|
|
51
|
+
}
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function shouldFilter() {
|
|
56
|
+
return filterActive && (isPickerOpen() || Date.now() < pickerArmUntil);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function armPicker() {
|
|
60
|
+
pickerArmUntil = Date.now() + PICKER_ARM_MS;
|
|
61
|
+
if (pickerArmTimer !== null) clearTimeout(pickerArmTimer);
|
|
62
|
+
const waitForPicker = () => {
|
|
63
|
+
if (isPickerOpen()) {
|
|
64
|
+
pickerArmTimer = null;
|
|
65
|
+
startTierGrouping();
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (Date.now() >= pickerArmUntil) {
|
|
69
|
+
pickerArmTimer = null;
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
pickerArmTimer = setTimeout(waitForPicker, 100);
|
|
73
|
+
};
|
|
74
|
+
pickerArmTimer = setTimeout(waitForPicker, 50);
|
|
44
75
|
}
|
|
45
76
|
|
|
46
77
|
function cleanPath(url) {
|
|
@@ -386,7 +417,7 @@ function ensureSummonerId() {
|
|
|
386
417
|
});
|
|
387
418
|
}
|
|
388
419
|
function rewriteInventoryText(raw) {
|
|
389
|
-
if (typeof raw !== "string") return raw;
|
|
420
|
+
if (!shouldFilter() || typeof raw !== "string") return raw;
|
|
390
421
|
if (inventoryTextCache.has(raw)) {
|
|
391
422
|
const cached = inventoryTextCache.get(raw);
|
|
392
423
|
inventoryTextCache.delete(raw);
|
|
@@ -406,7 +437,7 @@ function rewriteInventoryText(raw) {
|
|
|
406
437
|
}
|
|
407
438
|
|
|
408
439
|
function rewriteWebSocketFrame(text) {
|
|
409
|
-
if (!
|
|
440
|
+
if (!shouldFilter() || typeof text !== "string") return null;
|
|
410
441
|
const targetFrame = text.indexOf("lol-champions/v1/inventories") !== -1;
|
|
411
442
|
const augmentFrame = text.indexOf("SKIN_AUGMENT") !== -1;
|
|
412
443
|
if (!targetFrame && !augmentFrame) return null;
|
|
@@ -512,12 +543,12 @@ function installFetchFilter() {
|
|
|
512
543
|
const inventory = pathIdOf(url) !== null;
|
|
513
544
|
const augmentRequest = isAugmentUrl(url);
|
|
514
545
|
let options = init;
|
|
515
|
-
if (
|
|
546
|
+
if (shouldFilter() && options && typeof options.body === "string") {
|
|
516
547
|
const mapped = remapVariantIds(options.body);
|
|
517
548
|
if (mapped !== options.body) options = { ...options, body: mapped };
|
|
518
549
|
}
|
|
519
550
|
const promise = original.call(this, input, options);
|
|
520
|
-
if (!
|
|
551
|
+
if (!shouldFilter() || (!inventory && !augmentRequest)) return promise;
|
|
521
552
|
if (inventory) maybeRefreshSummoner();
|
|
522
553
|
|
|
523
554
|
return whenSummonerKnown(SUMMONER_WAIT_MS).then(() => {
|
|
@@ -594,13 +625,13 @@ function installXhrFilter() {
|
|
|
594
625
|
const url = this.__perfProfileUrl || "";
|
|
595
626
|
const target = isTargetUrl(url);
|
|
596
627
|
const augment = !target && isAugmentUrl(url);
|
|
597
|
-
if (
|
|
598
|
-
if (
|
|
628
|
+
if (shouldFilter() && pathIdOf(url) !== null) maybeRefreshSummoner();
|
|
629
|
+
if (shouldFilter() && typeof args[0] === "string") {
|
|
599
630
|
const mapped = remapVariantIds(args[0]);
|
|
600
631
|
if (mapped !== args[0]) args = [mapped, ...args.slice(1)];
|
|
601
632
|
}
|
|
602
633
|
const xhr = this;
|
|
603
|
-
if (target &&
|
|
634
|
+
if (target && shouldFilter() && augmentIds.size === 0 && textDescriptor && textDescriptor.get) {
|
|
604
635
|
const latch = new Promise((resolve) => {
|
|
605
636
|
const finish = () => {
|
|
606
637
|
if (augmentIds.size === 0) {
|
|
@@ -619,7 +650,7 @@ function installXhrFilter() {
|
|
|
619
650
|
}
|
|
620
651
|
if (textDescriptor && textDescriptor.get && (pathIdOf(url) !== null || augment)) {
|
|
621
652
|
const cache = { raw: null, gate: null, filtered: null };
|
|
622
|
-
const gateOpen = () =>
|
|
653
|
+
const gateOpen = () => shouldFilter() && (augment || isTargetUrl(url));
|
|
623
654
|
const rewriteBody = (json) => (augment ? unlockAugmentInventory(json) : unlockDeep(json));
|
|
624
655
|
const filteredText = () => {
|
|
625
656
|
const gate = gateOpen();
|
|
@@ -653,7 +684,7 @@ function installXhrFilter() {
|
|
|
653
684
|
});
|
|
654
685
|
}
|
|
655
686
|
}
|
|
656
|
-
if (augment &&
|
|
687
|
+
if (augment && shouldFilter() && augmentIds.size === 0) {
|
|
657
688
|
const sendArgs = args;
|
|
658
689
|
ensureAugmentIds().finally(() => {
|
|
659
690
|
try {
|
|
@@ -693,11 +724,10 @@ function onEnable(utils) {
|
|
|
693
724
|
filterActive = true;
|
|
694
725
|
ensureSourceFilter();
|
|
695
726
|
ensureSummonerId();
|
|
696
|
-
tierArmListener = () => {
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
}, 0);
|
|
727
|
+
tierArmListener = (event) => {
|
|
728
|
+
const target = event.target instanceof Element ? event.target.closest(PICKER_BUTTON_SELECTOR) : null;
|
|
729
|
+
if (!target) return;
|
|
730
|
+
armPicker();
|
|
701
731
|
};
|
|
702
732
|
document.addEventListener("click", tierArmListener, true);
|
|
703
733
|
if (isPickerOpen()) startTierGrouping();
|
|
@@ -708,6 +738,9 @@ function onDisable() {
|
|
|
708
738
|
inventoryTextCache.clear();
|
|
709
739
|
if (tierArmListener) document.removeEventListener("click", tierArmListener, true);
|
|
710
740
|
tierArmListener = null;
|
|
741
|
+
if (pickerArmTimer !== null) clearTimeout(pickerArmTimer);
|
|
742
|
+
pickerArmTimer = null;
|
|
743
|
+
pickerArmUntil = 0;
|
|
711
744
|
stopTierGrouping();
|
|
712
745
|
api = null;
|
|
713
746
|
}
|