haraberget commited on
Commit
8f577f9
·
verified ·
1 Parent(s): bc2d619

Create injection.js

Browse files

COPY and past into console (you can open with F12)
VibeCoded with ChatGPT

Files changed (1) hide show
  1. injection.js +384 -0
injection.js ADDED
@@ -0,0 +1,384 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ (() => {
3
+ // Stop the previous monitor before replacing its window.
4
+ if (window.hitRenderMonitorTimer) {
5
+ clearInterval(window.hitRenderMonitorTimer);
6
+ }
7
+ document.getElementById("hit-render-monitor")?.remove();
8
+
9
+ const POSITION_KEY = "hitRenderMonitorPosition";
10
+
11
+ const state = {
12
+ prompt: "",
13
+ progress: 0,
14
+ step: 0,
15
+ totalSteps: 0,
16
+ checkpoints: new Set(),
17
+ completedUrl: "",
18
+ lastReport: null,
19
+ minimized: false
20
+ };
21
+
22
+ const panel = document.createElement("div");
23
+ panel.id = "hit-render-monitor";
24
+
25
+ Object.assign(panel.style, {
26
+ position: "fixed",
27
+ right: "20px",
28
+ bottom: "20px",
29
+ width: "440px",
30
+ maxHeight: "85vh",
31
+ overflow: "hidden",
32
+ zIndex: "999999",
33
+ background: "#17191f",
34
+ color: "#eeeeee",
35
+ border: "1px solid #555",
36
+ borderRadius: "10px",
37
+ padding: "0",
38
+ font: "13px/1.45 monospace",
39
+ boxShadow: "0 5px 30px #0009"
40
+ });
41
+
42
+ panel.innerHTML = `
43
+ <div id="hit-header" style="
44
+ display:flex;
45
+ justify-content:space-between;
46
+ align-items:center;
47
+ padding:12px 14px;
48
+ background:#22252d;
49
+ border-radius:10px 10px 0 0;
50
+ cursor:grab;
51
+ user-select:none;
52
+ touch-action:none;
53
+ ">
54
+ <strong style="font-size:15px">
55
+ H3 Monitor <span id="hit-title-progress" style="color:#20b875">· Waiting</span>
56
+ </strong>
57
+ <div style="display:flex;gap:6px">
58
+ <button id="hit-minimize" title="Minimize" style="
59
+ background:#444;color:white;border:0;
60
+ padding:3px 10px;cursor:pointer;font-size:16px
61
+ ">−</button>
62
+ <button id="hit-close" title="Close" style="
63
+ background:#744;color:white;border:0;
64
+ padding:3px 9px;cursor:pointer;font-size:15px
65
+ ">×</button>
66
+ </div>
67
+ </div>
68
+
69
+ <div id="hit-content" style="
70
+ padding:14px;
71
+ max-height:calc(85vh - 45px);
72
+ overflow-y:auto;
73
+ ">
74
+ <div style="margin-top:2px">RENDER PROGRESS</div>
75
+ <div style="height:12px;background:#333;border-radius:8px;margin:6px 0;overflow:hidden">
76
+ <div id="hit-bar" style="height:100%;width:0%;background:#20b875;transition:width .3s"></div>
77
+ </div>
78
+ <div id="hit-progress" style="font-size:18px">Waiting for H3...</div>
79
+ <div id="hit-step" style="color:#aaa"></div>
80
+
81
+ <hr style="border-color:#444;margin:12px 0">
82
+
83
+ <div><strong>PROMPT INSPECTOR</strong></div>
84
+ <div id="hit-prompt" style="background:#242730;padding:8px;margin-top:6px;max-height:125px;overflow:auto;white-space:pre-wrap;overflow-wrap:anywhere;color:#ddd">Waiting for prompt...</div>
85
+
86
+ <hr style="border-color:#444;margin:12px 0">
87
+
88
+ <div style="display:flex;justify-content:space-between;align-items:center">
89
+ <strong>CALLBACK SIMULATOR</strong>
90
+ <label style="font-size:11px">
91
+ <input id="hit-report" type="checkbox" checked>
92
+ Report to 1hit.no
93
+ </label>
94
+ </div>
95
+ <div style="color:#e6b85c;font-size:11px;margin:4px 0 8px">
96
+ Simulation only — no network requests
97
+ </div>
98
+
99
+ <div id="hit-json" style="background:#090b0e;padding:9px;max-height:230px;overflow:auto;white-space:pre-wrap;overflow-wrap:anywhere;font-size:11px;color:#9fe5b2">Waiting for events...</div>
100
+
101
+ <hr style="border-color:#444;margin:12px 0">
102
+
103
+ <div><strong>OUTPUT URL</strong></div>
104
+ <div id="hit-url" style="color:#8fcaff;overflow-wrap:anywhere;margin-top:5px">Waiting for video...</div>
105
+
106
+ <div id="hit-status" style="color:#aaa;font-size:11px;margin-top:10px">Polling every 15 seconds</div>
107
+ </div>
108
+ `;
109
+
110
+ document.body.appendChild(panel);
111
+
112
+ const el = id => panel.querySelector("#" + id);
113
+
114
+ // Restore the previous position, if available.
115
+ try {
116
+ const saved = JSON.parse(sessionStorage.getItem(POSITION_KEY) || "null");
117
+
118
+ if (saved && Number.isFinite(saved.left) && Number.isFinite(saved.top)) {
119
+ panel.style.left = saved.left + "px";
120
+ panel.style.top = saved.top + "px";
121
+ panel.style.right = "auto";
122
+ panel.style.bottom = "auto";
123
+ }
124
+ } catch (e) {
125
+ console.warn("Could not restore monitor position:", e);
126
+ }
127
+
128
+ function savePosition() {
129
+ const rect = panel.getBoundingClientRect();
130
+
131
+ try {
132
+ sessionStorage.setItem(POSITION_KEY, JSON.stringify({
133
+ left: Math.round(rect.left),
134
+ top: Math.round(rect.top)
135
+ }));
136
+ } catch (e) {}
137
+ }
138
+
139
+ // Drag the monitor using its title bar.
140
+ const header = el("hit-header");
141
+ let dragging = false;
142
+ let dragOffsetX = 0;
143
+ let dragOffsetY = 0;
144
+
145
+ header.addEventListener("pointerdown", event => {
146
+ if (event.target.closest("button")) return;
147
+
148
+ dragging = true;
149
+
150
+ const rect = panel.getBoundingClientRect();
151
+ dragOffsetX = event.clientX - rect.left;
152
+ dragOffsetY = event.clientY - rect.top;
153
+
154
+ panel.style.right = "auto";
155
+ panel.style.bottom = "auto";
156
+ header.style.cursor = "grabbing";
157
+
158
+ header.setPointerCapture(event.pointerId);
159
+ event.preventDefault();
160
+ });
161
+
162
+ header.addEventListener("pointermove", event => {
163
+ if (!dragging) return;
164
+
165
+ const width = panel.offsetWidth;
166
+ const height = panel.offsetHeight;
167
+
168
+ const left = Math.max(
169
+ 0,
170
+ Math.min(window.innerWidth - width, event.clientX - dragOffsetX)
171
+ );
172
+
173
+ const top = Math.max(
174
+ 0,
175
+ Math.min(window.innerHeight - height, event.clientY - dragOffsetY)
176
+ );
177
+
178
+ panel.style.left = left + "px";
179
+ panel.style.top = top + "px";
180
+ });
181
+
182
+ function stopDragging() {
183
+ if (!dragging) return;
184
+
185
+ dragging = false;
186
+ header.style.cursor = "grab";
187
+ savePosition();
188
+ }
189
+
190
+ header.addEventListener("pointerup", stopDragging);
191
+ header.addEventListener("pointercancel", stopDragging);
192
+ header.addEventListener("lostpointercapture", stopDragging);
193
+
194
+ // Minimize and restore without stopping the monitor.
195
+ el("hit-minimize").onclick = () => {
196
+ state.minimized = !state.minimized;
197
+
198
+ el("hit-content").style.display =
199
+ state.minimized ? "none" : "block";
200
+
201
+ el("hit-minimize").textContent =
202
+ state.minimized ? "+" : "−";
203
+
204
+ el("hit-minimize").title =
205
+ state.minimized ? "Restore" : "Minimize";
206
+
207
+ panel.style.width = state.minimized ? "260px" : "440px";
208
+
209
+ savePosition();
210
+ };
211
+
212
+ function addEvent(data) {
213
+ if (!el("hit-report").checked) return;
214
+
215
+ const json = JSON.stringify(data, null, 2);
216
+ const log = el("hit-json");
217
+
218
+ log.textContent =
219
+ (log.textContent === "Waiting for events..." ? "" : log.textContent + "\n\n")
220
+ + json;
221
+
222
+ log.scrollTop = log.scrollHeight;
223
+ }
224
+
225
+ function getPrompt() {
226
+ const fields = [
227
+ ...document.querySelectorAll("textarea, [contenteditable='true']")
228
+ ];
229
+
230
+ const candidates = fields.map(node => ({
231
+ text: (node.value || node.innerText || node.textContent || "").trim(),
232
+ hint: [
233
+ node.getAttribute("aria-label"),
234
+ node.getAttribute("placeholder"),
235
+ node.parentElement?.innerText
236
+ ].filter(Boolean).join(" ").toLowerCase()
237
+ })).filter(x => x.text.length > 10);
238
+
239
+ const labelled = candidates
240
+ .filter(x => /prompt|description/.test(x.hint))
241
+ .sort((a, b) => b.text.length - a.text.length);
242
+
243
+ if (labelled.length) return labelled[0].text;
244
+
245
+ candidates.sort((a, b) => b.text.length - a.text.length);
246
+ return candidates[0]?.text || "";
247
+ }
248
+
249
+ function getVideoUrl() {
250
+ const candidates = [
251
+ ...document.querySelectorAll("video"),
252
+ ...document.querySelectorAll("video source"),
253
+ ...document.querySelectorAll("a[href]")
254
+ ];
255
+
256
+ for (const node of candidates) {
257
+ const url =
258
+ node.currentSrc ||
259
+ node.src ||
260
+ node.href ||
261
+ "";
262
+
263
+ if (url && (
264
+ /\.mp4(?:[?#]|$)/i.test(url) ||
265
+ url.startsWith("blob:")
266
+ )) {
267
+ return url;
268
+ }
269
+ }
270
+
271
+ return "";
272
+ }
273
+
274
+ function baseEvent(event) {
275
+ return {
276
+ session_id: "kaggle-" + location.host,
277
+ event,
278
+ render_url: location.href,
279
+ prompt: state.prompt,
280
+ progress: state.progress,
281
+ step: state.step,
282
+ total_steps: state.totalSteps,
283
+ timestamp: new Date().toISOString()
284
+ };
285
+ }
286
+
287
+ function poll() {
288
+ const prompt = getPrompt();
289
+
290
+ if (prompt && prompt !== state.prompt) {
291
+ state.prompt = prompt;
292
+ state.checkpoints.clear();
293
+ state.completedUrl = "";
294
+
295
+ el("hit-prompt").textContent = prompt;
296
+
297
+ addEvent({
298
+ ...baseEvent("prompt"),
299
+ message: "New prompt detected"
300
+ });
301
+ }
302
+
303
+ const messages = [
304
+ ...document.querySelectorAll('div[type="message"]')
305
+ ];
306
+
307
+ const matching = messages
308
+ .map(node => node.innerText || "")
309
+ .filter(text => text.includes("H3 denoising:"));
310
+
311
+ if (matching.length) {
312
+ const latest = matching[matching.length - 1];
313
+
314
+ const match = latest.match(
315
+ /H3 denoising:\s*(\d+)%.*?\|\s*(\d+)\/(\d+)/
316
+ );
317
+
318
+ if (match) {
319
+ const pct = Number(match[1]);
320
+ const step = Number(match[2]);
321
+ const total = Number(match[3]);
322
+
323
+ if (pct < state.progress && pct <= 25) {
324
+ state.checkpoints.clear();
325
+ state.completedUrl = "";
326
+ }
327
+
328
+ state.progress = pct;
329
+ state.step = step;
330
+ state.totalSteps = total;
331
+
332
+ el("hit-bar").style.width = pct + "%";
333
+ el("hit-progress").textContent = pct + "%";
334
+ el("hit-step").textContent = `Step ${step} / ${total}`;
335
+
336
+ el("hit-title-progress").textContent = "· " + pct + "%";
337
+
338
+ for (const threshold of [25, 50, 75, 100]) {
339
+ if (pct >= threshold && !state.checkpoints.has(threshold)) {
340
+ state.checkpoints.add(threshold);
341
+
342
+ addEvent({
343
+ ...baseEvent("progress"),
344
+ checkpoint: threshold
345
+ });
346
+ }
347
+ }
348
+ }
349
+ }
350
+
351
+ const videoUrl = getVideoUrl();
352
+
353
+ if (videoUrl) {
354
+ el("hit-url").textContent = videoUrl;
355
+
356
+ if (state.progress >= 100 && videoUrl !== state.completedUrl) {
357
+ state.completedUrl = videoUrl;
358
+
359
+ addEvent({
360
+ ...baseEvent("completed"),
361
+ video: {
362
+ url: videoUrl,
363
+ filename: videoUrl.split("/").pop().split("?")[0]
364
+ }
365
+ });
366
+ }
367
+ }
368
+
369
+ el("hit-status").textContent =
370
+ "Last scan: " + new Date().toLocaleTimeString() +
371
+ " · Polling every 15 seconds";
372
+ }
373
+
374
+ el("hit-close").onclick = () => {
375
+ clearInterval(window.hitRenderMonitorTimer);
376
+ window.hitRenderMonitorTimer = null;
377
+ panel.remove();
378
+ };
379
+
380
+ poll();
381
+ window.hitRenderMonitorTimer = setInterval(poll, 15000);
382
+
383
+ console.log("H3 Render Monitor v3 started.");
384
+ })();