haraberget commited on
Commit
b9cadb2
·
verified ·
1 Parent(s): 98731fc

Update injection.js

Browse files
Files changed (1) hide show
  1. injection.js +244 -99
injection.js CHANGED
@@ -1,9 +1,9 @@
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";
@@ -15,7 +15,6 @@
15
  totalSteps: 0,
16
  checkpoints: new Set(),
17
  completedUrl: "",
18
- lastReport: null,
19
  minimized: false
20
  };
21
 
@@ -41,68 +40,126 @@
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
- <div id="hit-content" style="
69
- padding:14px;
70
- max-height:calc(85vh - 45px);
71
- overflow-y:auto;
72
- ">
73
- <div style="margin-top:2px">RENDER PROGRESS</div>
74
  <div style="height:12px;background:#333;border-radius:8px;margin:6px 0;overflow:hidden">
75
  <div id="hit-bar" style="height:100%;width:0%;background:#20b875;transition:width .3s"></div>
76
  </div>
77
  <div id="hit-progress" style="font-size:18px">Waiting for H3...</div>
78
  <div id="hit-step" style="color:#aaa"></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  <hr style="border-color:#444;margin:12px 0">
80
- <div><strong>PROMPT INSPECTOR</strong></div>
 
81
  <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>
 
82
  <hr style="border-color:#444;margin:12px 0">
 
83
  <div style="display:flex;justify-content:space-between;align-items:center">
84
  <strong>CALLBACK SIMULATOR</strong>
85
  <label style="font-size:11px">
86
- <input id="hit-report" type="checkbox" checked>
87
- Report to 1hit.no
88
  </label>
89
  </div>
90
  <div style="color:#e6b85c;font-size:11px;margin:4px 0 8px">
91
  Simulation only — no network requests
92
  </div>
93
  <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>
 
94
  <hr style="border-color:#444;margin:12px 0">
95
- <div><strong>OUTPUT URL</strong></div>
 
96
  <div id="hit-url" style="color:#8fcaff;overflow-wrap:anywhere;margin-top:5px">Waiting for video...</div>
97
- <div id="hit-status" style="color:#aaa;font-size:11px;margin-top:10px">Polling every 15 seconds</div>
98
  </div>
99
  `;
100
 
101
  document.body.appendChild(panel);
102
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  const el = id => panel.querySelector("#" + id);
104
 
105
- // Restore the previous position, if available.
106
  try {
107
  const saved = JSON.parse(sessionStorage.getItem(POSITION_KEY) || "null");
108
 
@@ -112,9 +169,7 @@
112
  panel.style.right = "auto";
113
  panel.style.bottom = "auto";
114
  }
115
- } catch (e) {
116
- console.warn("Could not restore monitor position:", e);
117
- }
118
 
119
  function savePosition() {
120
  const rect = panel.getBoundingClientRect();
@@ -127,7 +182,7 @@
127
  } catch (e) {}
128
  }
129
 
130
- // Drag the monitor using its title bar.
131
  const header = el("hit-header");
132
  let dragging = false;
133
  let dragOffsetX = 0;
@@ -137,7 +192,6 @@
137
  if (event.target.closest("button")) return;
138
 
139
  dragging = true;
140
-
141
  const rect = panel.getBoundingClientRect();
142
  dragOffsetX = event.clientX - rect.left;
143
  dragOffsetY = event.clientY - rect.top;
@@ -145,7 +199,6 @@
145
  panel.style.right = "auto";
146
  panel.style.bottom = "auto";
147
  header.style.cursor = "grabbing";
148
-
149
  header.setPointerCapture(event.pointerId);
150
  event.preventDefault();
151
  });
@@ -153,18 +206,15 @@
153
  header.addEventListener("pointermove", event => {
154
  if (!dragging) return;
155
 
156
- const width = panel.offsetWidth;
157
- const height = panel.offsetHeight;
 
 
158
 
159
- const left = Math.max(
160
- 0,
161
- Math.min(window.innerWidth - width, event.clientX - dragOffsetX)
162
- );
163
-
164
- const top = Math.max(
165
- 0,
166
- Math.min(window.innerHeight - height, event.clientY - dragOffsetY)
167
- );
168
 
169
  panel.style.left = left + "px";
170
  panel.style.top = top + "px";
@@ -172,7 +222,6 @@
172
 
173
  function stopDragging() {
174
  if (!dragging) return;
175
-
176
  dragging = false;
177
  header.style.cursor = "grab";
178
  savePosition();
@@ -182,41 +231,147 @@
182
  header.addEventListener("pointercancel", stopDragging);
183
  header.addEventListener("lostpointercapture", stopDragging);
184
 
185
- // Minimize and restore without stopping the monitor.
186
  el("hit-minimize").onclick = () => {
187
  state.minimized = !state.minimized;
 
 
 
 
 
 
188
 
189
- el("hit-content").style.display =
190
- state.minimized ? "none" : "block";
 
191
 
192
- el("hit-minimize").textContent =
193
- state.minimized ? "+" : "−";
194
 
195
- el("hit-minimize").title =
196
- state.minimized ? "Restore" : "Minimize";
 
197
 
198
- panel.style.width = state.minimized ? "260px" : "440px";
 
199
 
200
- savePosition();
201
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
202
 
203
  function addEvent(data) {
204
  if (!el("hit-report").checked) return;
205
 
206
- const json = JSON.stringify(data, null, 2);
207
  const log = el("hit-json");
208
 
209
  log.textContent =
210
- (log.textContent === "Waiting for events..." ? "" : log.textContent + "\n\n")
211
- + json;
212
 
213
  log.scrollTop = log.scrollHeight;
214
  }
215
 
216
  function getPrompt() {
217
- const fields = [
218
- ...document.querySelectorAll("textarea, [contenteditable='true']")
219
- ];
220
 
221
  const candidates = fields.map(node => ({
222
  text: (node.value || node.innerText || node.textContent || "").trim(),
@@ -245,16 +400,9 @@
245
  ];
246
 
247
  for (const node of candidates) {
248
- const url =
249
- node.currentSrc ||
250
- node.src ||
251
- node.href ||
252
- "";
253
-
254
- if (url && (
255
- /\.mp4(?:[?#]|$)/i.test(url) ||
256
- url.startsWith("blob:")
257
- )) {
258
  return url;
259
  }
260
  }
@@ -276,33 +424,26 @@
276
  }
277
 
278
  function poll() {
 
 
279
  const prompt = getPrompt();
280
 
281
  if (prompt && prompt !== state.prompt) {
282
  state.prompt = prompt;
283
  state.checkpoints.clear();
284
  state.completedUrl = "";
285
-
286
  el("hit-prompt").textContent = prompt;
287
-
288
- addEvent({
289
- ...baseEvent("prompt"),
290
- message: "New prompt detected"
291
- });
292
  }
293
 
294
- const messages = [
295
- ...document.querySelectorAll('div[type="message"]')
296
- ];
297
 
298
  const matching = messages
299
  .map(node => node.innerText || "")
300
  .filter(text => text.includes("H3 denoising:"));
301
 
302
  if (matching.length) {
303
- const latest = matching[matching.length - 1];
304
-
305
- const match = latest.match(
306
  /H3 denoising:\s*(\d+)%.*?\|\s*(\d+)\/(\d+)/
307
  );
308
 
@@ -323,17 +464,12 @@
323
  el("hit-bar").style.width = pct + "%";
324
  el("hit-progress").textContent = pct + "%";
325
  el("hit-step").textContent = `Step ${step} / ${total}`;
326
-
327
  el("hit-title-progress").textContent = "· " + pct + "%";
328
 
329
  for (const threshold of [25, 50, 75, 100]) {
330
  if (pct >= threshold && !state.checkpoints.has(threshold)) {
331
  state.checkpoints.add(threshold);
332
-
333
- addEvent({
334
- ...baseEvent("progress"),
335
- checkpoint: threshold
336
- });
337
  }
338
  }
339
  }
@@ -359,17 +495,26 @@
359
 
360
  el("hit-status").textContent =
361
  "Last scan: " + new Date().toLocaleTimeString() +
362
- " · Polling every 15 seconds";
363
  }
364
 
 
365
  el("hit-close").onclick = () => {
366
  clearInterval(window.hitRenderMonitorTimer);
 
 
367
  window.hitRenderMonitorTimer = null;
 
 
368
  panel.remove();
369
  };
370
 
 
 
371
  poll();
 
 
372
  window.hitRenderMonitorTimer = setInterval(poll, 15000);
373
 
374
- console.log("H3 Render Monitor v3 started.");
375
  })();
 
1
 
2
+
3
  (() => {
4
+ // H3 Render Monitor v6 — Kaggle Live Dashboard
5
+ if (window.hitRenderMonitorTimer) clearInterval(window.hitRenderMonitorTimer);
6
+ if (window.hitResourceMonitorTimer) clearInterval(window.hitResourceMonitorTimer);
 
7
  document.getElementById("hit-render-monitor")?.remove();
8
 
9
  const POSITION_KEY = "hitRenderMonitorPosition";
 
15
  totalSteps: 0,
16
  checkpoints: new Set(),
17
  completedUrl: "",
 
18
  minimized: false
19
  };
20
 
 
40
 
41
  panel.innerHTML = `
42
  <div id="hit-header" style="
43
+ display:flex;justify-content:space-between;align-items:center;
44
+ padding:12px 14px;background:#22252d;
45
+ border-radius:10px 10px 0 0;cursor:grab;
46
+ user-select:none;touch-action:none">
 
 
 
 
 
 
47
  <strong style="font-size:15px">
48
  H3 Monitor <span id="hit-title-progress" style="color:#20b875">· Waiting</span>
49
  </strong>
50
  <div style="display:flex;gap:6px">
51
+ <button id="hit-minimize" title="Minimize"
52
+ style="background:#444;color:white;border:0;padding:3px 10px;cursor:pointer;font-size:16px">−</button>
53
+ <button id="hit-close" title="Close"
54
+ style="background:#744;color:white;border:0;padding:3px 9px;cursor:pointer;font-size:15px">×</button>
 
 
 
 
55
  </div>
56
  </div>
57
+
58
+ <div id="hit-content" style="padding:14px;max-height:calc(85vh - 45px);overflow-y:auto">
59
+
60
+ <strong>RENDER PROGRESS</strong>
 
 
61
  <div style="height:12px;background:#333;border-radius:8px;margin:6px 0;overflow:hidden">
62
  <div id="hit-bar" style="height:100%;width:0%;background:#20b875;transition:width .3s"></div>
63
  </div>
64
  <div id="hit-progress" style="font-size:18px">Waiting for H3...</div>
65
  <div id="hit-step" style="color:#aaa"></div>
66
+
67
+ <hr style="border-color:#444;margin:12px 0">
68
+
69
+ <strong>KAGGLE SESSION</strong>
70
+ <div style="display:grid;grid-template-columns:1fr 1fr;gap:7px;margin-top:8px">
71
+ <div class="hit-stat"><small>ACCELERATOR</small><strong id="hit-accelerator">--</strong></div>
72
+ <div class="hit-stat"><small>SESSION TIME</small><strong id="hit-session-time">--</strong></div>
73
+ <div class="hit-stat"><small>DISK</small><strong id="hit-disk">--</strong></div>
74
+ <div class="hit-stat"><small>QUOTA</small><strong id="hit-quota">--</strong></div>
75
+ <div class="hit-stat"><small>PERSISTENCE</small><strong id="hit-persistence">--</strong></div>
76
+ <div class="hit-stat"><small>INTERNET</small><strong id="hit-internet">--</strong></div>
77
+ <div class="hit-stat" style="grid-column:span 2"><small>ENVIRONMENT</small><strong id="hit-environment">--</strong></div>
78
+ </div>
79
+
80
+ <hr style="border-color:#444;margin:12px 0">
81
+
82
+ <div style="display:flex;justify-content:space-between;align-items:center">
83
+ <strong>LIVE RESOURCE USAGE</strong>
84
+ <span id="hit-resource-status" style="font-size:10px;color:#aaa">Waiting...</span>
85
+ </div>
86
+
87
+ <div style="display:grid;grid-template-columns:1fr 1fr;gap:7px;margin-top:8px">
88
+ <div class="hit-stat"><small>CPU</small><strong id="hit-cpu">--</strong></div>
89
+ <div class="hit-stat"><small>RAM</small><strong id="hit-ram">--</strong></div>
90
+ <div class="hit-stat" style="grid-column:span 2"><small>DISK USAGE</small><strong id="hit-disk-live">--</strong></div>
91
+ </div>
92
+
93
+ <div style="margin-top:9px;background:#242730;padding:9px;border-radius:6px">
94
+ <strong style="font-size:12px">GPU 1</strong>
95
+ <div style="display:grid;grid-template-columns:1fr 1fr;gap:7px;margin-top:6px">
96
+ <div><small style="color:#aaa">UTILISATION</small><strong id="hit-gpu-1" style="display:block">--</strong></div>
97
+ <div><small style="color:#aaa">MEMORY</small><strong id="hit-vram-1" style="display:block">--</strong></div>
98
+ </div>
99
+ </div>
100
+
101
+ <div style="margin-top:7px;background:#242730;padding:9px;border-radius:6px">
102
+ <strong style="font-size:12px">GPU 2</strong>
103
+ <div style="display:grid;grid-template-columns:1fr 1fr;gap:7px;margin-top:6px">
104
+ <div><small style="color:#aaa">UTILISATION</small><strong id="hit-gpu-2" style="display:block">--</strong></div>
105
+ <div><small style="color:#aaa">MEMORY</small><strong id="hit-vram-2" style="display:block">--</strong></div>
106
+ </div>
107
+ </div>
108
+
109
  <hr style="border-color:#444;margin:12px 0">
110
+
111
+ <strong>PROMPT INSPECTOR</strong>
112
  <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>
113
+
114
  <hr style="border-color:#444;margin:12px 0">
115
+
116
  <div style="display:flex;justify-content:space-between;align-items:center">
117
  <strong>CALLBACK SIMULATOR</strong>
118
  <label style="font-size:11px">
119
+ <input id="hit-report" type="checkbox" checked> Report to 1hit.no
 
120
  </label>
121
  </div>
122
  <div style="color:#e6b85c;font-size:11px;margin:4px 0 8px">
123
  Simulation only — no network requests
124
  </div>
125
  <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>
126
+
127
  <hr style="border-color:#444;margin:12px 0">
128
+
129
+ <strong>OUTPUT URL</strong>
130
  <div id="hit-url" style="color:#8fcaff;overflow-wrap:anywhere;margin-top:5px">Waiting for video...</div>
131
+ <div id="hit-status" style="color:#aaa;font-size:11px;margin-top:10px">Progress scan every 15 seconds · Resources every 2.5 seconds</div>
132
  </div>
133
  `;
134
 
135
  document.body.appendChild(panel);
136
 
137
+ // Style statistic cards.
138
+ panel.querySelectorAll(".hit-stat").forEach(card => {
139
+ Object.assign(card.style, {
140
+ background: "#242730",
141
+ padding: "8px",
142
+ borderRadius: "6px",
143
+ minWidth: "0",
144
+ overflowWrap: "anywhere"
145
+ });
146
+
147
+ const small = card.querySelector("small");
148
+ const strong = card.querySelector("strong");
149
+
150
+ if (small) Object.assign(small.style, {
151
+ display: "block",
152
+ color: "#aaa",
153
+ fontSize: "10px",
154
+ marginBottom: "3px"
155
+ });
156
+
157
+ if (strong) Object.assign(strong.style, {fontSize: "12px"});
158
+ });
159
+
160
  const el = id => panel.querySelector("#" + id);
161
 
162
+ // Restore previous popup position.
163
  try {
164
  const saved = JSON.parse(sessionStorage.getItem(POSITION_KEY) || "null");
165
 
 
169
  panel.style.right = "auto";
170
  panel.style.bottom = "auto";
171
  }
172
+ } catch (e) {}
 
 
173
 
174
  function savePosition() {
175
  const rect = panel.getBoundingClientRect();
 
182
  } catch (e) {}
183
  }
184
 
185
+ // Drag popup.
186
  const header = el("hit-header");
187
  let dragging = false;
188
  let dragOffsetX = 0;
 
192
  if (event.target.closest("button")) return;
193
 
194
  dragging = true;
 
195
  const rect = panel.getBoundingClientRect();
196
  dragOffsetX = event.clientX - rect.left;
197
  dragOffsetY = event.clientY - rect.top;
 
199
  panel.style.right = "auto";
200
  panel.style.bottom = "auto";
201
  header.style.cursor = "grabbing";
 
202
  header.setPointerCapture(event.pointerId);
203
  event.preventDefault();
204
  });
 
206
  header.addEventListener("pointermove", event => {
207
  if (!dragging) return;
208
 
209
+ const left = Math.max(0, Math.min(
210
+ window.innerWidth - panel.offsetWidth,
211
+ event.clientX - dragOffsetX
212
+ ));
213
 
214
+ const top = Math.max(0, Math.min(
215
+ window.innerHeight - panel.offsetHeight,
216
+ event.clientY - dragOffsetY
217
+ ));
 
 
 
 
 
218
 
219
  panel.style.left = left + "px";
220
  panel.style.top = top + "px";
 
222
 
223
  function stopDragging() {
224
  if (!dragging) return;
 
225
  dragging = false;
226
  header.style.cursor = "grab";
227
  savePosition();
 
231
  header.addEventListener("pointercancel", stopDragging);
232
  header.addEventListener("lostpointercapture", stopDragging);
233
 
234
+ // Minimize and restore.
235
  el("hit-minimize").onclick = () => {
236
  state.minimized = !state.minimized;
237
+ el("hit-content").style.display = state.minimized ? "none" : "block";
238
+ el("hit-minimize").textContent = state.minimized ? "+" : "−";
239
+ el("hit-minimize").title = state.minimized ? "Restore" : "Minimize";
240
+ panel.style.width = state.minimized ? "260px" : "440px";
241
+ savePosition();
242
+ };
243
 
244
+ // Read a metric from Kaggle's visible metric cards.
245
+ function readMetrics() {
246
+ const result = [];
247
 
248
+ const metricNodes = [...document.querySelectorAll('span[tabindex="0"]')];
 
249
 
250
+ for (const node of metricNodes) {
251
+ const card = node.querySelector("div");
252
+ if (!card) continue;
253
 
254
+ const children = [...card.children];
255
+ if (children.length < 2) continue;
256
 
257
+ const label = (children[0].innerText || "").trim();
258
+ const value = (children[1].innerText || "").trim();
259
+ const maximum = (children[2]?.innerText || "").trim();
260
+
261
+ if (!label || !value) continue;
262
+
263
+ result.push({
264
+ label,
265
+ value,
266
+ maximum,
267
+ container: node.parentElement
268
+ });
269
+ }
270
+
271
+ return result;
272
+ }
273
+
274
+ function updateResourceUsage() {
275
+ const metrics = readMetrics();
276
+
277
+ const findAll = label =>
278
+ metrics.filter(item => item.label.toLowerCase() === label.toLowerCase());
279
+
280
+ const findOne = label => findAll(label)[0];
281
+
282
+ const cpu = findOne("CPU");
283
+ const ram = findOne("RAM");
284
+ const disk = findOne("Disk");
285
+ const session = findOne("Session");
286
+ const gpu = findAll("GPU");
287
+ const gpuMemory = findAll("GPU Memory");
288
+
289
+ if (cpu) el("hit-cpu").textContent = cpu.value;
290
+ if (ram) el("hit-ram").textContent =
291
+ ram.value + (ram.maximum ? " / " + ram.maximum : "");
292
+
293
+ if (disk) {
294
+ const diskText = disk.value + (disk.maximum ? " / " + disk.maximum : "");
295
+ el("hit-disk").textContent = diskText;
296
+ el("hit-disk-live").textContent = diskText;
297
+ }
298
+
299
+ if (session) {
300
+ el("hit-session-time").textContent =
301
+ session.value + (session.maximum ? " / " + session.maximum : "");
302
+ }
303
+
304
+ if (gpu[0]) el("hit-gpu-1").textContent = gpu[0].value;
305
+ if (gpuMemory[0]) {
306
+ el("hit-vram-1").textContent =
307
+ gpuMemory[0].value + (gpuMemory[0].maximum ? " / " + gpuMemory[0].maximum : "");
308
+ }
309
+
310
+ if (gpu[1]) el("hit-gpu-2").textContent = gpu[1].value;
311
+ if (gpuMemory[1]) {
312
+ el("hit-vram-2").textContent =
313
+ gpuMemory[1].value + (gpuMemory[1].maximum ? " / " + gpuMemory[1].maximum : "");
314
+ }
315
+
316
+ const found = [cpu, ram, disk, session].filter(Boolean).length +
317
+ gpu.length + gpuMemory.length;
318
+
319
+ el("hit-resource-status").textContent =
320
+ found ? "Live · " + new Date().toLocaleTimeString() : "Waiting for Kaggle metrics";
321
+ }
322
+
323
+ // Read Kaggle session options.
324
+ function updateKaggleOptions() {
325
+ const getValue = label => {
326
+ const field = [...document.querySelectorAll('[role="combobox"]')]
327
+ .find(node => {
328
+ const text = (
329
+ node.getAttribute("aria-label") ||
330
+ node.getAttribute("aria-labelledby") ||
331
+ ""
332
+ ).toLowerCase();
333
+
334
+ return text.includes(label.toLowerCase());
335
+ });
336
+
337
+ return field?.innerText?.trim() || "";
338
+ };
339
+
340
+ const accelerator = getValue("Accelerator");
341
+ const persistence = getValue("Persistence");
342
+ const environment = getValue("Environment");
343
+
344
+ const internetInput = document.querySelector(
345
+ '#internet-toggle-switch-label input[type="checkbox"]'
346
+ );
347
+
348
+ const quota = [...document.querySelectorAll("p")]
349
+ .find(node => node.innerText.includes("Quota:"))
350
+ ?.innerText.match(/Quota:\s*(.*?)(?:\s*-\s*Link|$)/)?.[1] || "";
351
+
352
+ el("hit-accelerator").textContent = accelerator || "Not detected";
353
+ el("hit-quota").textContent = quota || "Not detected";
354
+ el("hit-persistence").textContent = persistence || "Not detected";
355
+ el("hit-environment").textContent = environment || "Not detected";
356
+ el("hit-internet").textContent = internetInput
357
+ ? (internetInput.checked ? "On" : "Off")
358
+ : "Not detected";
359
+ }
360
 
361
  function addEvent(data) {
362
  if (!el("hit-report").checked) return;
363
 
 
364
  const log = el("hit-json");
365
 
366
  log.textContent =
367
+ (log.textContent === "Waiting for events..." ? "" : log.textContent + "\n\n") +
368
+ JSON.stringify(data, null, 2);
369
 
370
  log.scrollTop = log.scrollHeight;
371
  }
372
 
373
  function getPrompt() {
374
+ const fields = [...document.querySelectorAll("textarea, [contenteditable='true']")];
 
 
375
 
376
  const candidates = fields.map(node => ({
377
  text: (node.value || node.innerText || node.textContent || "").trim(),
 
400
  ];
401
 
402
  for (const node of candidates) {
403
+ const url = node.currentSrc || node.src || node.href || "";
404
+
405
+ if (url && (/\.mp4(?:[?#]|$)/i.test(url) || url.startsWith("blob:"))) {
 
 
 
 
 
 
 
406
  return url;
407
  }
408
  }
 
424
  }
425
 
426
  function poll() {
427
+ updateKaggleOptions();
428
+
429
  const prompt = getPrompt();
430
 
431
  if (prompt && prompt !== state.prompt) {
432
  state.prompt = prompt;
433
  state.checkpoints.clear();
434
  state.completedUrl = "";
 
435
  el("hit-prompt").textContent = prompt;
436
+ addEvent({...baseEvent("prompt"), message: "New prompt detected"});
 
 
 
 
437
  }
438
 
439
+ const messages = [...document.querySelectorAll('div[type="message"]')];
 
 
440
 
441
  const matching = messages
442
  .map(node => node.innerText || "")
443
  .filter(text => text.includes("H3 denoising:"));
444
 
445
  if (matching.length) {
446
+ const match = matching[matching.length - 1].match(
 
 
447
  /H3 denoising:\s*(\d+)%.*?\|\s*(\d+)\/(\d+)/
448
  );
449
 
 
464
  el("hit-bar").style.width = pct + "%";
465
  el("hit-progress").textContent = pct + "%";
466
  el("hit-step").textContent = `Step ${step} / ${total}`;
 
467
  el("hit-title-progress").textContent = "· " + pct + "%";
468
 
469
  for (const threshold of [25, 50, 75, 100]) {
470
  if (pct >= threshold && !state.checkpoints.has(threshold)) {
471
  state.checkpoints.add(threshold);
472
+ addEvent({...baseEvent("progress"), checkpoint: threshold});
 
 
 
 
473
  }
474
  }
475
  }
 
495
 
496
  el("hit-status").textContent =
497
  "Last scan: " + new Date().toLocaleTimeString() +
498
+ " · Progress scan every 15 seconds";
499
  }
500
 
501
+ // Close and clean up both timers.
502
  el("hit-close").onclick = () => {
503
  clearInterval(window.hitRenderMonitorTimer);
504
+ clearInterval(window.hitResourceMonitorTimer);
505
+
506
  window.hitRenderMonitorTimer = null;
507
+ window.hitResourceMonitorTimer = null;
508
+
509
  panel.remove();
510
  };
511
 
512
+ // Start monitoring.
513
+ updateResourceUsage();
514
  poll();
515
+
516
+ window.hitResourceMonitorTimer = setInterval(updateResourceUsage, 2500);
517
  window.hitRenderMonitorTimer = setInterval(poll, 15000);
518
 
519
+ console.log("H3 Render Monitor v6 started — live resource monitoring enabled.");
520
  })();