From 165c960e525b36b65613c1199a09378ed1b8607a Mon Sep 17 00:00:00 2001 From: firestar5683 <168790843+firestar5683@users.noreply.github.com> Date: Sat, 1 Aug 2026 18:43:53 -0500 Subject: [PATCH] seggs --- .../system/the_galaxy/assets/components/router.js | 2 +- .../the_galaxy/assets/components/tools/tuning.js | 11 +++++++++++ .../the_galaxy/tests/test_dashboard_stats.py | 15 +++++++++++++++ starpilot/system/the_galaxy/the_galaxy.py | 11 +++++++++-- starpilot/system/the_galaxy/utilities.py | 13 +++++++++++-- 5 files changed, 47 insertions(+), 5 deletions(-) diff --git a/starpilot/system/the_galaxy/assets/components/router.js b/starpilot/system/the_galaxy/assets/components/router.js index e6e42c548..5a89e33e6 100644 --- a/starpilot/system/the_galaxy/assets/components/router.js +++ b/starpilot/system/the_galaxy/assets/components/router.js @@ -19,7 +19,7 @@ import { ModelManager } from "/assets/components/tools/model_manager.js?v=202603 import { LivePlots } from "/assets/components/tools/plots.js" import { ThemeMaker } from "/assets/components/tools/theme_maker.js" import { TestingGround } from "/assets/components/tools/testing_ground.js" -import { Tuning } from "/assets/components/tools/tuning.js?v=flm-saved-tunes-1" +import { Tuning } from "/assets/components/tools/tuning.js?v=flm-route-length-1" import { Troubleshoot } from "/assets/components/tools/troubleshoot.js" import { TmuxLog } from "/assets/components/tools/tmux.js" import { ToggleControl } from "/assets/components/tools/toggles.js" diff --git a/starpilot/system/the_galaxy/assets/components/tools/tuning.js b/starpilot/system/the_galaxy/assets/components/tools/tuning.js index 8e57f3de2..0246149bb 100644 --- a/starpilot/system/the_galaxy/assets/components/tools/tuning.js +++ b/starpilot/system/the_galaxy/assets/components/tools/tuning.js @@ -57,6 +57,16 @@ function safeCount(value) { return Number.isFinite(n) ? n : 0 } +function formatRouteLength(route) { + const segmentCount = Math.max(0, Math.round(safeCount(route?.segmentCount))) + if (!segmentCount) return "Length unavailable" + const approximateMinutes = Math.max(1, Math.round(safeCount(route?.approxDurationSeconds) / 60) || segmentCount) + const duration = approximateMinutes >= 60 + ? `~${Math.floor(approximateMinutes / 60)}h ${approximateMinutes % 60}m` + : `~${approximateMinutes} min` + return `${segmentCount} segment${segmentCount === 1 ? "" : "s"} (${duration})` +} + function connectRouteUrl(routeName) { const dongleId = String(state.connectDongleId || "").trim() const routeId = String(routeName || "").trim() @@ -1196,6 +1206,7 @@ export function Tuning() { ${route.timestampLabel} ${route.name} + ${formatRouteLength(route)} ${() => connectRouteUrl(route.name) ? html` diff --git a/starpilot/system/the_galaxy/tests/test_dashboard_stats.py b/starpilot/system/the_galaxy/tests/test_dashboard_stats.py index 9f1b999a2..c25559e49 100644 --- a/starpilot/system/the_galaxy/tests/test_dashboard_stats.py +++ b/starpilot/system/the_galaxy/tests/test_dashboard_stats.py @@ -259,6 +259,21 @@ class FakeDashboardAnalyzerProcess: self.terminated = True +def test_route_inventory_counts_segments_without_video_probing(monkeypatch): + segments = [ + SimpleNamespace(route_name=SimpleNamespace(time_str="route-new")), + SimpleNamespace(route_name=SimpleNamespace(time_str="route-new")), + SimpleNamespace(route_name=SimpleNamespace(time_str="route-new")), + SimpleNamespace(route_name=SimpleNamespace(time_str="route-old")), + ] + monkeypatch.setattr(utilities, "get_all_segment_names", lambda _path: segments) + + assert utilities.get_routes_with_segment_counts("/tmp/routes") == [ + ("route-old", 1), + ("route-new", 3), + ] + + def test_dashboard_background_analysis_does_not_start_onroad(monkeypatch): def fail_if_started(*args, **kwargs): raise AssertionError("worker started onroad") diff --git a/starpilot/system/the_galaxy/the_galaxy.py b/starpilot/system/the_galaxy/the_galaxy.py index 9d8a31fde..93328e652 100644 --- a/starpilot/system/the_galaxy/the_galaxy.py +++ b/starpilot/system/the_galaxy/the_galaxy.py @@ -5350,13 +5350,20 @@ def setup(app): @app.route("/api/routes", methods=["GET"]) def list_routes(): def generate(): - routes = [(path, name) for path in FOOTAGE_PATHS for name in utilities.get_routes_names(path)] + routes = [ + (path, name, segment_count) + for path in FOOTAGE_PATHS + for name, segment_count in utilities.get_routes_with_segment_counts(path) + ] total = len(routes) connect_dongle_id = params.get("StockDongleId", encoding="utf-8") or params.get("DongleId", encoding="utf-8") or "" yield f"data: {json.dumps({'progress': 0, 'total': total, 'connectDongleId': connect_dongle_id})}\n\n" with ThreadPoolExecutor(max_workers=10) as executor: - futures = {executor.submit(utilities.process_route, path, name): (path, name) for path, name in routes} + futures = { + executor.submit(utilities.process_route, path, name, segment_count): (path, name) + for path, name, segment_count in routes + } for processed, future in enumerate(as_completed(futures), start=1): try: result = future.result() diff --git a/starpilot/system/the_galaxy/utilities.py b/starpilot/system/the_galaxy/utilities.py index 33ebc12e9..bfac7b153 100644 --- a/starpilot/system/the_galaxy/utilities.py +++ b/starpilot/system/the_galaxy/utilities.py @@ -2895,6 +2895,13 @@ def get_routes_names(footage_path): route_times = {segment.route_name.time_str for segment in segments} return sorted(route_times, reverse=True) +def get_routes_with_segment_counts(footage_path): + route_counts = {} + for segment in get_all_segment_names(footage_path): + route_name = segment.route_name.time_str + route_counts[route_name] = route_counts.get(route_name, 0) + 1 + return sorted(route_counts.items(), reverse=True) + def get_segments_in_route(route_time_str, footage_path): return [ f"{segment.time_str}--{segment.segment_num}" @@ -2930,7 +2937,7 @@ def normalize_theme_name(name, for_path=False): return f"{normalized_parts[0]} ({' '.join(normalized_parts[1:])})".replace(" Week", "") return ' '.join(normalized_parts).replace(" Week", "") -def process_route(footage_path, route_name): +def process_route(footage_path, route_name, segment_count=0): segment_path = f"{footage_path}{route_name}--0" qcamera_path = f"{segment_path}/qcamera.ts" @@ -2954,7 +2961,9 @@ def process_route(footage_path, route_name): "name": route_name, "png": f"/thumbnails/{route_name}--0/preview.png", "timestamp": route_timestamp_str, - "is_preserved": has_preserve_attr(segment_path) + "is_preserved": has_preserve_attr(segment_path), + "segmentCount": max(0, int(segment_count)), + "approxDurationSeconds": max(0, int(segment_count)) * 60, } def process_screen_recording(mp4):