@danhachuel/thunderbolt 0.4.70 → 0.4.72
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/app/main.py +9 -2
- package/hermes_ui/update_manager.py +4 -1
- package/package.json +1 -1
- package/scripts/cli.mjs +36 -10
package/app/main.py
CHANGED
|
@@ -1856,7 +1856,7 @@ def format_metric_number(value: Any) -> str:
|
|
|
1856
1856
|
|
|
1857
1857
|
|
|
1858
1858
|
def classify_channel_platform(channel: Any) -> str:
|
|
1859
|
-
"""
|
|
1859
|
+
"""Classify channels while keeping legacy YouTube records visible."""
|
|
1860
1860
|
if not isinstance(channel, dict):
|
|
1861
1861
|
return "unknown"
|
|
1862
1862
|
value = str(channel.get("platform") or "").strip().casefold().replace(" ", "")
|
|
@@ -1864,7 +1864,14 @@ def classify_channel_platform(channel: Any) -> str:
|
|
|
1864
1864
|
return "youtube"
|
|
1865
1865
|
if value in {"tiktok", "tik-tok", "tt"}:
|
|
1866
1866
|
return "tiktok"
|
|
1867
|
-
|
|
1867
|
+
def has_tiktok_marker(item: Any) -> bool:
|
|
1868
|
+
if isinstance(item, dict):
|
|
1869
|
+
return any(has_tiktok_marker(key) or has_tiktok_marker(value) for key, value in item.items())
|
|
1870
|
+
if isinstance(item, (list, tuple, set)):
|
|
1871
|
+
return any(has_tiktok_marker(value) for value in item)
|
|
1872
|
+
normalized = str(item or "").strip().casefold().replace(" ", "")
|
|
1873
|
+
return "tiktok" in normalized or normalized == "tik-tok"
|
|
1874
|
+
return "tiktok" if has_tiktok_marker(channel) else "youtube"
|
|
1868
1875
|
|
|
1869
1876
|
|
|
1870
1877
|
def _tiktok_channel_records() -> list[dict[str, Any]]:
|
|
@@ -18,6 +18,7 @@ import requests
|
|
|
18
18
|
PACKAGE_NAME = "@danhachuel/thunderbolt"
|
|
19
19
|
REGISTRY_URL = "https://registry.npmjs.org/@danhachuel/thunderbolt/latest"
|
|
20
20
|
UPDATE_TIMEOUT_SECONDS = 20 * 60
|
|
21
|
+
LAUNCHER_RESTART_EXIT_CODE = 75
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
@dataclass(frozen=True)
|
|
@@ -44,7 +45,9 @@ class UpdateResult:
|
|
|
44
45
|
|
|
45
46
|
|
|
46
47
|
def restart_current_process(*, exec_fn: Callable[..., Any] = os.execv) -> None:
|
|
47
|
-
"""
|
|
48
|
+
"""Ask the launcher to restart Streamlit, or re-exec standalone callers."""
|
|
49
|
+
if os.environ.get("THUNDERBOLT_LAUNCHER_RESTART") == "1":
|
|
50
|
+
raise SystemExit(LAUNCHER_RESTART_EXIT_CODE)
|
|
48
51
|
executable = sys.executable
|
|
49
52
|
exec_fn(executable, [executable, *sys.argv])
|
|
50
53
|
|
package/package.json
CHANGED
package/scripts/cli.mjs
CHANGED
|
@@ -242,23 +242,49 @@ const pipelineWorker = spawn(python, ["-m", "hermes_ui.pipeline_worker"], {
|
|
|
242
242
|
env: runtimeEnv,
|
|
243
243
|
windowsHide: false,
|
|
244
244
|
});
|
|
245
|
-
const
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
245
|
+
const restartExitCode = 75;
|
|
246
|
+
let shuttingDown = false;
|
|
247
|
+
let child;
|
|
248
|
+
|
|
249
|
+
function startStreamlit() {
|
|
250
|
+
child = spawn(python, ["-m", "streamlit", "run", main, "--server.port", String(backendPort), "--server.address", "127.0.0.1"], {
|
|
251
|
+
cwd: root,
|
|
252
|
+
stdio: "ignore",
|
|
253
|
+
env: { ...runtimeEnv, THUNDERBOLT_LAUNCHER_RESTART: "1" },
|
|
254
|
+
windowsHide: false,
|
|
255
|
+
});
|
|
256
|
+
child.on("exit", (code, signal) => {
|
|
257
|
+
if (shuttingDown) {
|
|
258
|
+
stopWorker();
|
|
259
|
+
process.exit(code ?? (signal ? 1 : 0));
|
|
260
|
+
}
|
|
261
|
+
if (code === restartExitCode) {
|
|
262
|
+
const executable = platform() === "win32" ? "npx.cmd" : "npx";
|
|
263
|
+
const replacement = spawn(executable, ["--yes", "--prefer-online", "@danhachuel/thunderbolt"], {
|
|
264
|
+
cwd: userHome,
|
|
265
|
+
env: process.env,
|
|
266
|
+
detached: true,
|
|
267
|
+
stdio: "ignore",
|
|
268
|
+
windowsHide: false,
|
|
269
|
+
});
|
|
270
|
+
replacement.unref();
|
|
271
|
+
stopWorker();
|
|
272
|
+
process.exit(0);
|
|
273
|
+
}
|
|
274
|
+
stopWorker();
|
|
275
|
+
process.exit(code ?? (signal ? 1 : 0));
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
startStreamlit();
|
|
251
280
|
|
|
252
281
|
const stopWorker = () => {
|
|
282
|
+
shuttingDown = true;
|
|
253
283
|
proxy.close();
|
|
254
284
|
if (!worker.killed) worker.kill();
|
|
255
285
|
if (!pipelineWorker.killed) pipelineWorker.kill();
|
|
256
286
|
};
|
|
257
287
|
process.on("SIGINT", stopWorker);
|
|
258
288
|
process.on("SIGTERM", stopWorker);
|
|
259
|
-
child.on("exit", (code, signal) => {
|
|
260
|
-
stopWorker();
|
|
261
|
-
process.exit(code ?? (signal ? 1 : 0));
|
|
262
|
-
});
|
|
263
289
|
worker.on("error", (error) => console.error(`Thunderbolt worker: ${error.message}`));
|
|
264
290
|
pipelineWorker.on("error", (error) => console.error(`Thunderbolt pipeline worker: ${error.message}`));
|