Background-audio handoff for video + repository/player refactor

Hand video playback off to a native audio-only stream when the app is
backgrounded or locked, with no on-device video decode (UR-040). Adds
player_enter/exit_background_audio commands, an audio-only stream URL
for video items across the repository layer, and the frontend handoff
state machine wired into VideoPlayer. Includes accompanying
repository/offline/player refactoring and regenerates the traceability
matrix.
This commit is contained in:
2026-07-22 21:52:07 +02:00
parent 4e6ab017d4
commit 3fbf6afdbc
72 changed files with 6728 additions and 2338 deletions
+32
View File
@@ -390,6 +390,38 @@ describe("RepositoryClient", () => {
});
});
it("should get audio-only stream URL for a video item (camelCase params)", async () => {
// TRACES: UR-040 | JA-032 | UT-061
const mockUrl = "https://server.com/Audio/item123/universal?AudioStreamIndex=2";
(invoke as any).mockResolvedValueOnce(mockUrl);
const url = await client.getAudioOnlyStreamUrlForVideo("item123", "source456", 193, 2);
expect(url).toBe(mockUrl);
expect(invoke).toHaveBeenCalledWith("repository_get_audio_only_stream_url_for_video", {
handle: "test-handle-123",
itemId: "item123",
mediaSourceId: "source456",
startTimeSeconds: 193,
audioStreamIndex: 2,
});
});
it("should default optional params to null for audio-only stream URL", async () => {
// TRACES: UR-040 | JA-032 | UT-061
(invoke as any).mockResolvedValueOnce("https://server.com/Audio/item123/universal");
await client.getAudioOnlyStreamUrlForVideo("item123");
expect(invoke).toHaveBeenCalledWith("repository_get_audio_only_stream_url_for_video", {
handle: "test-handle-123",
itemId: "item123",
mediaSourceId: null,
startTimeSeconds: null,
audioStreamIndex: null,
});
});
it("should report playback progress", async () => {
(invoke as any).mockResolvedValueOnce(undefined);