5bf787eb2b
apple / swift (push) Successful in 1m1s
android / android (push) Successful in 4m13s
ci / rust (push) Successful in 4m42s
ci / web (push) Successful in 50s
ci / docs-site (push) Successful in 53s
windows-host / package (push) Successful in 5m51s
apple / screenshots (push) Successful in 5m1s
deb / build-publish (push) Successful in 2m29s
decky / build-publish (push) Successful in 12s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 5s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 33s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 5s
ci / bench (push) Successful in 4m35s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 9m9s
docker / deploy-docs (push) Successful in 18s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 9m10s
Arm streaming-perf-stats capture from the web console, play, stop, and review the run as graphs; finished captures are saved to disk as browsable/exportable recordings. Covers both the native punktfunk/1 path and GameStream. - stats_recorder.rs: one shared Arc<StatsRecorder> ring (created in gamestream::serve, shared with the mgmt API + both streaming loops, mirroring NativePairing). The hot-path gate is a runtime AtomicBool that replaces the startup-only PUNKTFUNK_PERF for *recording* (PERF stdout logging unchanged); bounded ring (~3 h); atomic temp+rename writes to ~/.config/punktfunk/captures/*.json; path-traversal-safe ids; poison-resilient locks. - native (punktfunk1.rs) + GameStream (stream.rs) emit a StatsSample at their existing ~2 s / ~1 s aggregation boundary — per-stage latency p50/p99, fps new/repeat, goodput, loss/FEC deltas — with no new per-frame work beyond the cheap atomic check. FrameMsg.was_measured keeps pre-arm in-flight frames out of the first window's percentiles (without zeroing the Windows-relay path's fps/encode). - mgmt.rs: 7 bearer-only /api/v1/stats/* endpoints (capture start/stop/status/live; recordings list/get/delete); api/openapi.json regenerated, in sync. - web: new "Performance" page (recharts, rendered SSR-safe) — capture control, live graphs while armed, recordings table (view / download-JSON / delete), and a detail view with the latency stacked-area bottleneck breakdown (p50/p99 toggle) + throughput + health. Charts adapt to either path's stage set. Design: design/stats-capture-plan.md. Built and adversarially reviewed via a multi-agent workflow; workspace build/clippy(-D warnings)/fmt/tests green, OpenAPI no-drift. Not yet on-glass validated against a live session. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
155 lines
6.4 KiB
JSON
155 lines
6.4 KiB
JSON
{
|
|
"$schema": "https://inlang.com/schema/inlang-message-format",
|
|
"app_name": "punktfunk",
|
|
"app_tagline": "management console",
|
|
"nav_dashboard": "Dashboard",
|
|
"nav_host": "Host",
|
|
"nav_clients": "Paired clients",
|
|
"nav_pairing": "Pairing",
|
|
"nav_library": "Library",
|
|
"nav_settings": "Settings",
|
|
"status_title": "Live status",
|
|
"status_video": "Video",
|
|
"status_audio": "Audio",
|
|
"status_streaming": "Streaming",
|
|
"status_idle": "Idle",
|
|
"status_session": "Session",
|
|
"status_no_session": "No active session",
|
|
"status_paired_count": "Paired clients",
|
|
"status_pin_pending": "Pairing PIN pending",
|
|
"stream_codec": "Codec",
|
|
"stream_resolution": "Resolution",
|
|
"stream_fps": "Frame rate",
|
|
"stream_bitrate": "Bitrate",
|
|
"action_stop_session": "Stop session",
|
|
"action_request_idr": "Request keyframe",
|
|
"action_unpair": "Unpair",
|
|
"host_identity": "Identity",
|
|
"host_hostname": "Hostname",
|
|
"host_local_ip": "Local IP",
|
|
"host_version": "Version",
|
|
"host_abi": "ABI version",
|
|
"host_codecs": "Codecs",
|
|
"host_ports": "Ports",
|
|
"host_uniqueid": "Unique ID",
|
|
"host_compositors": "Compositors",
|
|
"host_compositors_help": "Backends the host can drive a virtual output on. Pass an id to a client's --compositor flag; the host honors it if available, else auto-detects.",
|
|
"compositor_available": "Available",
|
|
"compositor_unavailable": "Unavailable",
|
|
"compositor_default": "Default",
|
|
"clients_title": "Paired clients",
|
|
"clients_empty": "No paired clients yet.",
|
|
"clients_name": "Name",
|
|
"clients_fingerprint": "Fingerprint",
|
|
"clients_unpair_confirm": "Unpair this client? It will need to pair again to connect.",
|
|
"pairing_title": "Pairing",
|
|
"pairing_idle": "No pairing in progress. Start pairing from a Moonlight client, then enter its PIN here.",
|
|
"pairing_waiting": "A client is waiting to pair. Enter the PIN it shows:",
|
|
"pairing_pin_label": "PIN",
|
|
"pairing_submit": "Submit PIN",
|
|
"pairing_success": "Paired successfully.",
|
|
"pairing_failed": "Pairing failed — check the PIN and try again.",
|
|
"pairing_native_title": "Pair a device",
|
|
"pairing_native_desc": "Show a one-time PIN here, then enter it in your punktfunk app to pair this device.",
|
|
"pairing_native_disabled": "The native host isn't running. Start it with `serve --native` to pair punktfunk devices.",
|
|
"pairing_native_arm": "Pair a device",
|
|
"pairing_native_enter": "Enter this PIN on your device:",
|
|
"pairing_native_expires": "Expires in",
|
|
"pairing_native_cancel": "Cancel",
|
|
"pairing_native_devices": "Paired devices",
|
|
"pairing_native_empty": "No devices paired yet.",
|
|
"pairing_native_unpair_confirm": "Unpair this device? It will need to pair again to connect.",
|
|
"pairing_pending_title": "Waiting for approval",
|
|
"pairing_pending_desc": "These devices tried to connect. Approving pairs a device immediately — no PIN needed.",
|
|
"pairing_pending_approve": "Approve",
|
|
"pairing_pending_deny": "Deny",
|
|
"pairing_pending_name_prompt": "Name this device:",
|
|
"pairing_pending_age_just_now": "just now",
|
|
"pairing_pending_age_secs": "{s}s ago",
|
|
"pairing_pending_age_mins": "{min} min ago",
|
|
"pairing_moonlight_title": "Moonlight (GameStream) pairing",
|
|
"library_title": "Library",
|
|
"library_empty": "No games found yet.",
|
|
"library_store_steam": "Steam",
|
|
"library_store_custom": "Custom",
|
|
"library_add_title": "Add a custom game",
|
|
"library_edit_title": "Edit custom game",
|
|
"library_add_button": "Add custom game",
|
|
"library_field_title": "Title",
|
|
"library_field_portrait": "Portrait art URL",
|
|
"library_field_hero": "Hero art URL",
|
|
"library_field_header": "Header art URL",
|
|
"library_field_command": "Launch command",
|
|
"library_field_command_help": "Optional. The command the host runs to launch this title.",
|
|
"library_save": "Save",
|
|
"library_create": "Add",
|
|
"library_cancel": "Cancel",
|
|
"library_edit": "Edit",
|
|
"library_delete": "Delete",
|
|
"library_delete_confirm": "Delete this custom game? This can't be undone.",
|
|
"settings_title": "Settings",
|
|
"settings_token_label": "API token",
|
|
"settings_token_help": "Bearer token for the management API. Leave empty for a loopback host with no token.",
|
|
"settings_language": "Language",
|
|
"settings_save": "Save",
|
|
"settings_saved": "Saved.",
|
|
"common_loading": "Loading…",
|
|
"common_error": "Something went wrong.",
|
|
"common_retry": "Retry",
|
|
"common_yes": "Yes",
|
|
"common_cancel": "Cancel",
|
|
"common_unauthorized": "Session expired — redirecting to sign in…",
|
|
"login_title": "Sign in",
|
|
"login_subtitle": "Enter the management password to continue.",
|
|
"login_password": "Password",
|
|
"login_submit": "Sign in",
|
|
"login_error": "Wrong password.",
|
|
"login_signing_in": "Signing in…",
|
|
"action_logout": "Sign out",
|
|
"nav_stats": "Performance",
|
|
"stats_title": "Performance",
|
|
"stats_subtitle": "Record a session's pipeline timings and review them as graphs.",
|
|
"stats_capture_title": "Capture",
|
|
"stats_capture_desc": "Arm capture, run a session, then stop to save a recording. Sampling runs at the host's aggregation boundary — no per-frame overhead.",
|
|
"stats_recording": "Recording",
|
|
"stats_idle": "Idle",
|
|
"stats_start": "Start capture",
|
|
"stats_stop": "Stop & save",
|
|
"stats_elapsed": "Elapsed",
|
|
"stats_samples": "Samples",
|
|
"stats_kind": "Path",
|
|
"stats_kind_native": "Native",
|
|
"stats_kind_gamestream": "GameStream",
|
|
"stats_live_title": "Live",
|
|
"stats_live_waiting": "Armed — waiting for the first samples. Start a session to begin recording.",
|
|
"stats_latency_title": "Latency by stage",
|
|
"stats_latency_axis": "µs",
|
|
"stats_latency_desc": "Per-stage pipeline time, stacked — the \"where does the time go\" view.",
|
|
"stats_throughput_title": "Throughput",
|
|
"stats_health_title": "Health",
|
|
"stats_fps_new": "New fps",
|
|
"stats_fps_repeat": "Repeat fps",
|
|
"stats_mbps": "Mb/s",
|
|
"stats_p99": "p99",
|
|
"stats_p50": "p50",
|
|
"stats_frames_dropped": "Frames dropped",
|
|
"stats_packets_dropped": "Packets dropped",
|
|
"stats_send_dropped": "Send drops",
|
|
"stats_fec_recovered": "FEC recovered",
|
|
"stats_recordings_title": "Recordings",
|
|
"stats_recordings_empty": "No recordings yet. Start a capture to record one.",
|
|
"stats_col_time": "Time",
|
|
"stats_col_kind": "Path",
|
|
"stats_col_resolution": "Resolution",
|
|
"stats_col_codec": "Codec",
|
|
"stats_col_duration": "Duration",
|
|
"stats_col_samples": "Samples",
|
|
"stats_view": "View",
|
|
"stats_download": "Download",
|
|
"stats_delete": "Delete",
|
|
"stats_delete_confirm": "Delete this recording? This can't be undone.",
|
|
"stats_detail_title": "Recording detail",
|
|
"stats_close": "Close",
|
|
"stats_no_samples": "This recording has no samples."
|
|
}
|