Restructure step 5: one media pipeline on a player host

- PlayerHost port (MediaKitHost): players by role, pins, hwdec policy,
  render probe, log routing, disposal order; the only media_kit user.
- MediaPipeline: plan (one pure switch over state, origin, caps,
  presence) -> resolve -> open (prepared player promoted, else fresh)
  -> ready; commands queued during a switch apply once (P15); viewers
  play the buffer and wait for a dropped source without seek loops (D6).
- Every web page resolved by our yt-dlp into an EDL with headers and
  cookies (danmaku excluded); mpv's ytdl_hook no longer used (ytdl=no).
- D11: sign-in errors say which cookies were used and whether they hold
  any for the site.
- Relay: 256 KiB slices read as they fill, superseded pulls released
  (seek-to-play ~4.2 s -> ~2.8 s, P29); own Jellyfin relay channel only
  when someone needs it (P28).
- STARSYNC_SMOKE run and a Windows CI smoke step after the build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
foxyzandClaude Opus 5.5 committed 2026-10-16 01:08:54 +03:00
1 parent 8970f2694b
commit 25b19f2d6a
47 files changed
+4083 -1728

No files matched your search

+39
View File
@@ -0,0 +1,39 @@
#!/usr/bin/env bash
# The close smoke run of tool/smoke_windows.ps1 on Linux (the same app
# mode, apps/desktop/lib/src/platform/smoke.dart): start the release
# bundle with a short clip, open it, play, close; check it exited within
# LIMIT seconds and left no process. Needs a display (skips without one).
# Usage (after `flutter build linux --release`): tool/smoke_linux.sh [LIMIT]
set -euo pipefail
LIMIT="${1:-45}"
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
EXE="$ROOT/apps/desktop/build/linux/x64/release/bundle/starsync"
[[ -x "$EXE" ]] || { echo "build first: $EXE missing" >&2; exit 1; }
if [[ -z "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ]]; then echo "skipped: no display"; exit 0; fi
WORK="$(mktemp -d)"; trap 'rm -rf "$WORK"' EXIT
MEDIA="$WORK/smoke.mp4"
ffmpeg -y -v error -f lavfi -i testsrc2=size=320x180:rate=24 -f lavfi -i sine=frequency=440 \
-t 5 -c:v libx264 -preset ultrafast -pix_fmt yuv420p -c:a aac "$MEDIA"
OUT="$WORK/smoke.txt"
start=$(date +%s)
STARSYNC_PROFILE=smoke STARSYNC_SMOKE="$MEDIA" STARSYNC_SMOKE_OUT="$OUT" "$EXE" >"$WORK/stdout.txt" 2>&1 &
pid=$!
exited=0
for _ in $(seq $((LIMIT * 10))); do
if ! kill -0 "$pid" 2>/dev/null; then exited=1; break; fi
sleep 0.1
done
secs=$(( $(date +%s) - start ))
steps="$(tr '\n' '|' < "$OUT" 2>/dev/null || true)"
echo "smoke steps: $steps (after $secs s)"
grep -E 'smoke:|close:|mpv: render' "$WORK/stdout.txt" | tail -20 || true
if [[ $exited == 0 ]]; then kill -9 "$pid" 2>/dev/null || true; fi
left="$(pgrep -f "$EXE" || true)"
[[ -n "$left" ]] && kill -9 $left 2>/dev/null || true
grep -qx start "$OUT" 2>/dev/null || { [[ $exited == 1 ]] && { echo "skipped: the app never came up"; exit 0; }; echo "did not come up nor exit" >&2; exit 1; }
grep -q '^skip ' "$OUT" && { echo "skipped: $(grep '^skip ' "$OUT")"; exit 0; }
grep -q '^fail ' "$OUT" && { echo "smoke failed: $(grep '^fail ' "$OUT")" >&2; exit 1; }
grep -q '^opened ' "$OUT" || { echo "the media never opened" >&2; exit 1; }
[[ $exited == 1 ]] || { echo "the app did not close within $LIMIT s (P32)" >&2; exit 1; }
[[ -z "$left" ]] || { echo "a starsync process was left behind (P32)" >&2; exit 1; }
echo "smoke ok: opened and closed in $secs s, no process left"
+70
View File
@@ -0,0 +1,70 @@
# Close smoke run (P32) on the built Windows app: start it with a short
# media file, let it open the file in a player with a video output, play a
# second and close the normal way (`apps/desktop/lib/src/platform/smoke.dart`),
# then check it exited within $Limit seconds and left no process behind.
# A runner that cannot bring up a window or a video output skips (warning).
# Usage (after a release build): powershell -File tool/smoke_windows.ps1 [-Limit 45]
param([int]$Limit = 45)
$ErrorActionPreference = 'Stop'
$Root = Split-Path -Parent $PSScriptRoot
$Exe = Join-Path $Root 'apps/desktop/build/windows/x64/runner/Release/starsync.exe'
if (-not (Test-Path $Exe)) { throw "build first: $Exe missing" }
$Exe = (Resolve-Path $Exe).Path
$Work = Join-Path ([IO.Path]::GetTempPath()) "starsync-smoke-$PID"
New-Item -ItemType Directory -Force $Work | Out-Null
$Out = Join-Path $Work 'smoke.txt'
# Media: a 5 s clip with ffmpeg when the runner has it, else a 5 s WAV
# written here (mpv opens either; headless mpv needs an audio track).
$Media = Join-Path $Work 'smoke.mp4'
$ffmpeg = Get-Command ffmpeg -ErrorAction SilentlyContinue
if ($ffmpeg) {
& $ffmpeg.Source -y -v error -f lavfi -i 'testsrc2=size=320x180:rate=24' -f lavfi -i 'sine=frequency=440' `
-t 5 -c:v libx264 -preset ultrafast -pix_fmt yuv420p -c:a aac $Media
}
if (-not $ffmpeg -or $LASTEXITCODE -or -not (Test-Path $Media)) {
$Media = Join-Path $Work 'smoke.wav'
$rate = 48000; $n = $rate * 5
$data = New-Object byte[] ($n * 2)
for ($i = 0; $i -lt $n; $i++) {
$v = [int16](3000 * [Math]::Sin(2 * [Math]::PI * 440 * $i / $rate))
$data[2 * $i] = [byte]($v -band 0xFF); $data[2 * $i + 1] = [byte](($v -shr 8) -band 0xFF)
}
$f = [IO.File]::Create($Media); $w = New-Object IO.BinaryWriter($f)
$w.Write([Text.Encoding]::ASCII.GetBytes('RIFF')); $w.Write([int](36 + $data.Length))
$w.Write([Text.Encoding]::ASCII.GetBytes('WAVEfmt ')); $w.Write([int]16); $w.Write([int16]1); $w.Write([int16]1)
$w.Write([int]$rate); $w.Write([int]($rate * 2)); $w.Write([int16]2); $w.Write([int16]16)
$w.Write([Text.Encoding]::ASCII.GetBytes('data')); $w.Write([int]$data.Length); $w.Write($data); $w.Close()
}
# Its own profile: no settings, sign-ins or client id of a real install.
$env:STARSYNC_PROFILE = 'smoke'
$env:STARSYNC_SMOKE = $Media
$env:STARSYNC_SMOKE_OUT = $Out
$clock = [Diagnostics.Stopwatch]::StartNew()
$p = Start-Process -FilePath $Exe -PassThru
$exited = $p.WaitForExit($Limit * 1000)
$secs = [int]$clock.Elapsed.TotalSeconds
$lines = if (Test-Path $Out) { Get-Content $Out } else { @() }
Write-Host "smoke steps: $($lines -join ' | ') (after $secs s)"
$logs = Join-Path $env:APPDATA 'foxyz\Starsync\profiles\smoke\logs'
if (Test-Path $logs) {
Get-ChildItem $logs -Filter 'app-*.log' | Sort-Object LastWriteTime | Select-Object -Last 1 |
ForEach-Object { Select-String -Path $_.FullName -Pattern 'smoke:|close:|mpv: render' | ForEach-Object { $_.Line } }
}
$left = Get-Process -Name starsync -ErrorAction SilentlyContinue | Where-Object { $_.Path -eq $Exe }
if (-not $exited) { $p | Stop-Process -Force -ErrorAction SilentlyContinue }
$left | Stop-Process -Force -ErrorAction SilentlyContinue
if (-not ($lines -contains 'start')) {
if ($exited) { Write-Warning "skipped: the app never came up on this runner (exit $($p.ExitCode))"; exit 0 }
Write-Error "the app did not come up and did not exit within $Limit s"; exit 1
}
if ($lines | Where-Object { $_ -like 'skip *' }) { Write-Warning "skipped: $($lines -like 'skip *')"; exit 0 }
if ($lines | Where-Object { $_ -like 'fail *' }) { Write-Error "smoke failed: $($lines -like 'fail *')"; exit 1 }
if (-not ($lines | Where-Object { $_ -like 'opened *' })) { Write-Error 'the media never opened'; exit 1 }
if (-not $exited) { Write-Error "the app did not close within $Limit s (P32)"; exit 1 }
if ($left) { Write-Error "a starsync process was left behind (P32)"; exit 1 }
Write-Host "smoke ok: opened and closed in $secs s, no process left"
Remove-Item -Recurse -Force $Work -ErrorAction SilentlyContinue