perfectionist-plugins 2.4.4 → 2.4.6
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 +2 -2
- package/auto-accept.js +43 -111
- package/auto-claimer.js +1 -2
- package/auto-read.js +1 -2
- package/ban-blocker.js +1 -2
- package/better-client.js +1 -4
- package/dodge-helper.js +835 -561
- package/hide-unowned-skins.js +2 -9
- package/package.json +40 -40
- package/perfectionist-utils.js +1041 -944
- package/unlock-profile-skins.js +1 -2
package/README.md
CHANGED
|
@@ -22,8 +22,8 @@ Built for [Pengu Loader](https://pengu.lol)
|
|
|
22
22
|
| 🛡️ **Ban Blocker** | 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 on your own pick turn, so their ban can never land on it. |
|
|
23
23
|
| 🔓 **Unlock Profile Skins** | In the **Set profile background** window, every skin shows as unlocked, even event skins (Signature). Browse the full list and pick any skin you like. |
|
|
24
24
|
| 🎨 **Hide Unowned Skins** | In champ select, the skin carousel only shows the skins you own for the champion you picked. The arrows and dots only move through owned skins, and the ones that are left keep their normal spacing. |
|
|
25
|
-
| ✅ **Auto Accept** | Accepts the match for you when the ready check pops up.
|
|
26
|
-
| 🚪 **Dodge Helper** | Adds a
|
|
25
|
+
| ✅ **Auto Accept** | Accepts the match for you when the ready check pops up. |
|
|
26
|
+
| 🚪 **Dodge Helper** | Adds a **DODGE** button in ranked Solo/Duo and Flex and a **QUIT** button in other modes, with the LP and queue-penalty cost of the next dodge. |
|
|
27
27
|
| 🎁 **Auto Claimer** | Claims rewards for you the moment they become claimable: event tracks, missions and the TFT Battle Pass. Three optional extras: auto-buy shop items Riot lists for 1 BE, auto-open mystery loot (icons, ward skins), and auto-open chests with keys. |
|
|
28
28
|
| 📬 **Auto Read** | Marks quests, loot, Clash, TFT and client notices as read, so no badge or dot stays lit. |
|
|
29
29
|
|
package/auto-accept.js
CHANGED
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
const PLUGIN_ID = "auto-accept";
|
|
2
|
-
export const version = "1.1.
|
|
2
|
+
export const version = "1.1.3";
|
|
3
3
|
|
|
4
4
|
const PHASE_URI = "/lol-gameflow/v1/gameflow-phase";
|
|
5
5
|
const READY_CHECK_URI = "/lol-matchmaking/v1/ready-check";
|
|
6
6
|
const ACCEPT_URI = "/lol-matchmaking/v1/ready-check/accept";
|
|
7
|
-
const
|
|
8
|
-
const DELAY_KEY = "perfectionist:auto-accept:delay";
|
|
9
|
-
const MAX_DELAY = 15000;
|
|
7
|
+
const ACCEPT_KEY = "autoAccept";
|
|
10
8
|
const RETRY_MS = 700;
|
|
11
9
|
const MAX_ATTEMPTS = 4;
|
|
10
|
+
const GAME_SELECT_GUARD_MS = 1500;
|
|
12
11
|
const STYLE_ID = "perf-auto-accept-style";
|
|
13
12
|
const ROOT_ID = "perfAutoAccept";
|
|
14
13
|
const TOGGLE_ID = "perfAutoAcceptToggle";
|
|
15
|
-
const DELAY_INPUT_ID = "perfAutoAcceptDelay";
|
|
16
14
|
|
|
17
15
|
const CSS = `#perfAutoAccept {
|
|
18
16
|
display: flex !important; flex-direction: row !important; flex-wrap: nowrap !important;
|
|
@@ -24,24 +22,7 @@ const CSS = `#perfAutoAccept {
|
|
|
24
22
|
font-family: var(--font-body, "LoL Body", Arial, sans-serif) !important;
|
|
25
23
|
font-size: 12px !important; letter-spacing: 0.3px !important; color: #a09b8c !important;
|
|
26
24
|
}
|
|
27
|
-
#perfAutoAccept .auto-accept-button[selected] .auto-accept-button-text { color: #f0e6d2 !important; }
|
|
28
|
-
#perfAutoAccept .auto-accept-delay {
|
|
29
|
-
display: flex !important; align-items: center !important; box-sizing: border-box !important;
|
|
30
|
-
width: 82px !important; height: 24px !important; margin-left: 0 !important;
|
|
31
|
-
background: #1e2328 !important; border: 1px solid #785a28 !important; border-radius: 0 !important;
|
|
32
|
-
transition: border-color 0.15s ease, background-color 0.15s ease !important;
|
|
33
|
-
}
|
|
34
|
-
#perfAutoAccept .auto-accept-delay:hover { border-color: #c89b3c !important; }
|
|
35
|
-
#perfAutoAccept .auto-accept-delay:focus-within { border-color: #c89b3c !important; background: #0a1428 !important; }
|
|
36
|
-
#perfAutoAccept .auto-accept-delay input {
|
|
37
|
-
width: 100% !important; height: 100% !important; box-sizing: border-box !important;
|
|
38
|
-
background: transparent !important; border: none !important; outline: none !important; box-shadow: none !important;
|
|
39
|
-
color: #f0e6d2 !important; font-family: var(--font-body, "LoL Body", Arial, sans-serif) !important;
|
|
40
|
-
font-size: 12px !important; letter-spacing: 0.3px !important; text-align: center !important; padding: 0 6px !important;
|
|
41
|
-
}
|
|
42
|
-
#perfAutoAccept .auto-accept-delay input::placeholder { color: #5b5a56 !important; }
|
|
43
|
-
#perfAutoAccept .auto-accept-delay input::-webkit-outer-spin-button,
|
|
44
|
-
#perfAutoAccept .auto-accept-delay input::-webkit-inner-spin-button { -webkit-appearance: none !important; margin: 0 !important; }`;
|
|
25
|
+
#perfAutoAccept .auto-accept-button[selected] .auto-accept-button-text { color: #f0e6d2 !important; }`;
|
|
45
26
|
|
|
46
27
|
let api = null;
|
|
47
28
|
let active = false;
|
|
@@ -52,29 +33,11 @@ let attempts = 0;
|
|
|
52
33
|
let unsubscribes = [];
|
|
53
34
|
let removeStyle = null;
|
|
54
35
|
let domObserver = null;
|
|
55
|
-
let domTimer = null;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
function readDelay() {
|
|
59
|
-
try {
|
|
60
|
-
const raw = Number(localStorage.getItem(DELAY_KEY));
|
|
61
|
-
if (!Number.isFinite(raw) || raw < 0) return 0;
|
|
62
|
-
return Math.min(Math.floor(raw), MAX_DELAY);
|
|
63
|
-
} catch {
|
|
64
|
-
return 0;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function writeDelay(value) {
|
|
69
|
-
delayValue = value;
|
|
70
|
-
try {
|
|
71
|
-
localStorage.setItem(DELAY_KEY, String(value));
|
|
72
|
-
} catch {}
|
|
73
|
-
}
|
|
74
|
-
|
|
36
|
+
let domTimer = null;
|
|
37
|
+
|
|
75
38
|
function enabled() {
|
|
76
39
|
try {
|
|
77
|
-
return api?.getOption?.(PLUGIN_ID,
|
|
40
|
+
return api?.getOption?.(PLUGIN_ID, ACCEPT_KEY, true) === true;
|
|
78
41
|
} catch {
|
|
79
42
|
return false;
|
|
80
43
|
}
|
|
@@ -136,19 +99,13 @@ async function acceptNow() {
|
|
|
136
99
|
} finally {
|
|
137
100
|
sending = false;
|
|
138
101
|
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function queueAccept() {
|
|
142
|
-
if (!active || !enabled() || accepted || sending || timer) return;
|
|
143
|
-
if (delayValue > 0) timer = setTimeout(acceptNow, delayValue);
|
|
144
|
-
else acceptNow();
|
|
145
|
-
}
|
|
146
|
-
|
|
102
|
+
}
|
|
103
|
+
|
|
147
104
|
function onPhase(raw) {
|
|
148
105
|
const phase = unwrap(raw);
|
|
149
106
|
if (typeof phase !== "string") return;
|
|
150
107
|
if (phase === "ReadyCheck") {
|
|
151
|
-
if (!accepted)
|
|
108
|
+
if (!accepted) acceptNow();
|
|
152
109
|
return;
|
|
153
110
|
}
|
|
154
111
|
resetReadyCheck();
|
|
@@ -166,13 +123,13 @@ function onReadyCheck(raw) {
|
|
|
166
123
|
resetReadyCheck();
|
|
167
124
|
return;
|
|
168
125
|
}
|
|
169
|
-
|
|
126
|
+
acceptNow();
|
|
170
127
|
}
|
|
171
128
|
|
|
172
129
|
async function refresh() {
|
|
173
130
|
const phase = unwrap(await api.lcu.get(PHASE_URI).catch(() => null));
|
|
174
131
|
if (!active) return;
|
|
175
|
-
if (phase === "ReadyCheck")
|
|
132
|
+
if (phase === "ReadyCheck") acceptNow();
|
|
176
133
|
else resetReadyCheck();
|
|
177
134
|
}
|
|
178
135
|
|
|
@@ -181,31 +138,18 @@ function syncButton() {
|
|
|
181
138
|
if (!option) return;
|
|
182
139
|
if (enabled()) option.setAttribute("selected", "true");
|
|
183
140
|
else option.removeAttribute("selected");
|
|
184
|
-
const field = document.getElementById(DELAY_INPUT_ID);
|
|
185
|
-
if (field && document.activeElement !== field) field.value = String(delayValue);
|
|
186
141
|
}
|
|
187
142
|
|
|
188
143
|
function toggle() {
|
|
189
144
|
const next = !enabled();
|
|
190
145
|
try {
|
|
191
|
-
api.setOption(PLUGIN_ID,
|
|
146
|
+
api.setOption(PLUGIN_ID, ACCEPT_KEY, next, false);
|
|
192
147
|
} catch {}
|
|
193
148
|
syncButton();
|
|
194
|
-
if (next)
|
|
149
|
+
if (next) acceptNow();
|
|
195
150
|
else resetReadyCheck();
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
function onDelayInput(event) {
|
|
199
|
-
const raw = Number(event.target.value);
|
|
200
|
-
const next = Math.min(Math.max(Number.isFinite(raw) ? Math.floor(raw) : 0, 0), MAX_DELAY);
|
|
201
|
-
writeDelay(next);
|
|
202
|
-
if (event.type === "change") event.target.value = String(next);
|
|
203
|
-
if (active && enabled() && timer) {
|
|
204
|
-
clearTimer();
|
|
205
|
-
queueAccept();
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
151
|
+
}
|
|
152
|
+
|
|
209
153
|
function buildButton() {
|
|
210
154
|
const root = document.createElement("div");
|
|
211
155
|
root.id = ROOT_ID;
|
|
@@ -221,29 +165,15 @@ function buildButton() {
|
|
|
221
165
|
event.preventDefault();
|
|
222
166
|
event.stopPropagation();
|
|
223
167
|
toggle();
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
input.className = "auto-accept-delay";
|
|
228
|
-
const field = document.createElement("input");
|
|
229
|
-
field.id = DELAY_INPUT_ID;
|
|
230
|
-
field.type = "number";
|
|
231
|
-
field.min = "0";
|
|
232
|
-
field.max = String(MAX_DELAY);
|
|
233
|
-
field.step = "100";
|
|
234
|
-
field.placeholder = "ms";
|
|
235
|
-
field.title = "Delay before accepting, in milliseconds";
|
|
236
|
-
field.value = String(delayValue);
|
|
237
|
-
field.addEventListener("input", onDelayInput);
|
|
238
|
-
field.addEventListener("change", onDelayInput);
|
|
239
|
-
field.addEventListener("click", (event) => event.stopPropagation());
|
|
240
|
-
input.append(field);
|
|
241
|
-
|
|
242
|
-
root.append(option, input);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
root.append(option);
|
|
243
171
|
return root;
|
|
244
172
|
}
|
|
245
173
|
|
|
246
174
|
let buttonRetry = null;
|
|
175
|
+
let gameSelectGuardUntil = 0;
|
|
176
|
+
let gameSelectClickHandler = null;
|
|
247
177
|
|
|
248
178
|
function footer() {
|
|
249
179
|
return (
|
|
@@ -253,6 +183,7 @@ function footer() {
|
|
|
253
183
|
}
|
|
254
184
|
|
|
255
185
|
function gameSelectOpen() {
|
|
186
|
+
if (Date.now() < gameSelectGuardUntil) return true;
|
|
256
187
|
try {
|
|
257
188
|
return !!document.querySelector(".parties-game-select-screen.game-select-show");
|
|
258
189
|
} catch {
|
|
@@ -260,6 +191,15 @@ function gameSelectOpen() {
|
|
|
260
191
|
}
|
|
261
192
|
}
|
|
262
193
|
|
|
194
|
+
function onGameSelectClick(event) {
|
|
195
|
+
const target = event.target;
|
|
196
|
+
if (!(target instanceof Element)) return;
|
|
197
|
+
if (!target.closest(".parties-game-select-screen, .play-button-container, .lobby-back-button")) return;
|
|
198
|
+
gameSelectGuardUntil = Date.now() + GAME_SELECT_GUARD_MS;
|
|
199
|
+
clearTimeout(buttonRetry);
|
|
200
|
+
buttonRetry = setTimeout(ensureButton, GAME_SELECT_GUARD_MS + 100);
|
|
201
|
+
}
|
|
202
|
+
|
|
263
203
|
function ensureButton() {
|
|
264
204
|
if (!active) return;
|
|
265
205
|
clearTimeout(buttonRetry);
|
|
@@ -290,6 +230,10 @@ function onEnable(utils) {
|
|
|
290
230
|
domObserver = new MutationObserver(scheduleEnsure);
|
|
291
231
|
domObserver.observe(document.documentElement ?? document, { childList: true, subtree: true });
|
|
292
232
|
|
|
233
|
+
gameSelectClickHandler = onGameSelectClick;
|
|
234
|
+
document.addEventListener("pointerdown", gameSelectClickHandler, true);
|
|
235
|
+
document.addEventListener("click", gameSelectClickHandler, true);
|
|
236
|
+
|
|
293
237
|
for (const uri of [PHASE_URI, READY_CHECK_URI]) {
|
|
294
238
|
try {
|
|
295
239
|
const off = utils.subscribe(uri, uri === PHASE_URI ? onPhase : onReadyCheck);
|
|
@@ -316,40 +260,28 @@ function onDisable() {
|
|
|
316
260
|
domTimer = null;
|
|
317
261
|
clearTimeout(buttonRetry);
|
|
318
262
|
buttonRetry = null;
|
|
263
|
+
if (gameSelectClickHandler) {
|
|
264
|
+
document.removeEventListener("pointerdown", gameSelectClickHandler, true);
|
|
265
|
+
document.removeEventListener("click", gameSelectClickHandler, true);
|
|
266
|
+
}
|
|
267
|
+
gameSelectClickHandler = null;
|
|
268
|
+
gameSelectGuardUntil = 0;
|
|
319
269
|
document.getElementById(ROOT_ID)?.remove();
|
|
320
270
|
removeStyle?.();
|
|
321
271
|
removeStyle = null;
|
|
322
272
|
api = null;
|
|
323
273
|
}
|
|
324
274
|
|
|
325
|
-
function onOptionChange(key) {
|
|
326
|
-
if (key !== OPTION_KEY) return;
|
|
327
|
-
syncButton();
|
|
328
|
-
if (enabled()) queueAccept();
|
|
329
|
-
else resetReadyCheck();
|
|
330
|
-
}
|
|
331
|
-
|
|
332
275
|
export function init() {
|
|
333
276
|
const registerWith = (utils) => {
|
|
334
277
|
utils.registerPlugin({
|
|
335
278
|
id: PLUGIN_ID,
|
|
336
279
|
name: "Auto Accept",
|
|
337
280
|
description:
|
|
338
|
-
"Accepts the ready check automatically
|
|
281
|
+
"Accepts the ready check automatically. Use the Auto Accept switch in the lobby footer to turn it on or off.",
|
|
339
282
|
version,
|
|
340
|
-
defaultEnabled: true,
|
|
341
|
-
options: [
|
|
342
|
-
{
|
|
343
|
-
key: OPTION_KEY,
|
|
344
|
-
label: "Auto accept matches",
|
|
345
|
-
description:
|
|
346
|
-
"Accepts the ready check for you. The Auto Accept switch in the lobby footer toggles this same setting.",
|
|
347
|
-
default: true,
|
|
348
|
-
},
|
|
349
|
-
],
|
|
350
283
|
onEnable,
|
|
351
284
|
onDisable,
|
|
352
|
-
onOptionChange,
|
|
353
285
|
});
|
|
354
286
|
};
|
|
355
287
|
|
|
@@ -360,4 +292,4 @@ export function init() {
|
|
|
360
292
|
addEventListener("perfectionist:utils-ready", (event) => registerWith(event.detail ?? window.PerfectionistUtils), {
|
|
361
293
|
once: true,
|
|
362
294
|
});
|
|
363
|
-
}
|
|
295
|
+
}
|
package/auto-claimer.js
CHANGED
|
@@ -362,7 +362,6 @@ export function init() {
|
|
|
362
362
|
name: "Auto Claimer",
|
|
363
363
|
description: "Automatically claims battle pass, event and mission rewards the moment they become claimable.",
|
|
364
364
|
version,
|
|
365
|
-
defaultEnabled: true,
|
|
366
365
|
options: [
|
|
367
366
|
{
|
|
368
367
|
key: "buy1Be",
|
|
@@ -402,4 +401,4 @@ export function init() {
|
|
|
402
401
|
return;
|
|
403
402
|
}
|
|
404
403
|
addEventListener("perfectionist:utils-ready", (e) => registerWith(e.detail ?? window.PerfectionistUtils), { once: true });
|
|
405
|
-
}
|
|
404
|
+
}
|
package/auto-read.js
CHANGED
|
@@ -358,7 +358,6 @@ export function init() {
|
|
|
358
358
|
name: "Auto Read",
|
|
359
359
|
description: "Automatically marks quests, loot, Clash, TFT and client notices as read so no badge or dot stays lit.",
|
|
360
360
|
version,
|
|
361
|
-
defaultEnabled: true,
|
|
362
361
|
options: [
|
|
363
362
|
{
|
|
364
363
|
type: "chips",
|
|
@@ -388,4 +387,4 @@ export function init() {
|
|
|
388
387
|
return;
|
|
389
388
|
}
|
|
390
389
|
addEventListener("perfectionist:utils-ready", (e) => registerWith(e.detail ?? window.PerfectionistUtils), { once: true });
|
|
391
|
-
}
|
|
390
|
+
}
|
package/ban-blocker.js
CHANGED
|
@@ -632,7 +632,6 @@ export function init() {
|
|
|
632
632
|
name: "Ban Blocker",
|
|
633
633
|
description: "During bans, blocking a teammate instantly claims the champion they hover to ban.",
|
|
634
634
|
version,
|
|
635
|
-
defaultEnabled: true,
|
|
636
635
|
onEnable,
|
|
637
636
|
onDisable,
|
|
638
637
|
});
|
|
@@ -647,4 +646,4 @@ export function init() {
|
|
|
647
646
|
(e) => registerWith(e.detail ?? window.PerfectionistUtils),
|
|
648
647
|
{ once: true },
|
|
649
648
|
);
|
|
650
|
-
}
|
|
649
|
+
}
|
package/better-client.js
CHANGED
|
@@ -286,8 +286,6 @@ function createFetch(env) {
|
|
|
286
286
|
storeInCache(key, ttl, response);
|
|
287
287
|
}, () => {});
|
|
288
288
|
}
|
|
289
|
-
// Every caller gets its own clone; the original response stays unread so
|
|
290
|
-
// concurrent callers can clone it after one caller consumes the body.
|
|
291
289
|
return request.then((response) => (response?.clone ? response.clone() : response));
|
|
292
290
|
}
|
|
293
291
|
|
|
@@ -780,7 +778,6 @@ export function init() {
|
|
|
780
778
|
description:
|
|
781
779
|
"Debloats the client: blocks telemetry and analytics calls, merges duplicate requests, caches static client data, decodes images asynchronously and keeps settings, chat and friend requests usable during a game.",
|
|
782
780
|
version,
|
|
783
|
-
defaultEnabled: true,
|
|
784
781
|
options: OPTIONS,
|
|
785
782
|
onEnable,
|
|
786
783
|
onDisable,
|
|
@@ -793,4 +790,4 @@ export function init() {
|
|
|
793
790
|
return;
|
|
794
791
|
}
|
|
795
792
|
addEventListener("perfectionist:utils-ready", (e) => registerWith(e.detail ?? window.PerfectionistUtils), { once: true });
|
|
796
|
-
}
|
|
793
|
+
}
|