import { describe, it, expect } from "vitest"; import { downloadedFilePath, resolveVideoSource } from "./localSource"; describe("downloadedFilePath", () => { // The download worker rewrites `downloads.file_path` to the absolute path it // actually wrote once the transfer completes, so a completed row is already // rooted. Joining it onto the storage root again produced // `/data/user/0/app//data/user/0/app/videos/x.mp4`, which the asset protocol // cannot open — offline video died with MEDIA_ERR_SRC_NOT_SUPPORTED while // audio, which resolves the same column through Rust, played fine. it("leaves a completed download's absolute path alone", () => { const root = "/data/user/0/com.dtourolle.jellytau"; const stored = `${root}/videos/Taming of the Shrew.mp4`; expect(downloadedFilePath(root, stored)).toBe(stored); }); it("roots a path that is still relative to the storage directory", () => { // Rows only hold a relative path before the worker completes them, but a // half-migrated database can still carry one. expect(downloadedFilePath("/var/data/jellytau", "videos/film.mp4")).toBe( "/var/data/jellytau/videos/film.mp4" ); }); it("leaves an absolute Windows path alone", () => { const stored = "C:\\Users\\u\\AppData\\jellytau\\videos\\film.mp4"; expect(downloadedFilePath("C:\\Users\\u\\AppData\\jellytau", stored)).toBe(stored); }); }); // A stand-in for Tauri's convertFileSrc, so the module stays pure. const toAssetUrl = (p: string) => `asset://localhost/${encodeURIComponent(p)}`; describe("resolveVideoSource", () => { it("plays the downloaded file when one exists", () => { const decision = resolveVideoSource({ localPath: "/home/u/.local/share/jellytau/movie.mp4", remoteUrl: "https://server/Videos/abc/master.m3u8", remoteNeedsTranscoding: true, toAssetUrl, }); expect(decision.isLocal).toBe(true); expect(decision.url).toBe(toAssetUrl("/home/u/.local/share/jellytau/movie.mp4")); }); it("never marks a local file as needing transcoding, even when the remote did", () => { // The transcoded path re-requests a whole new stream URL on every seek. // A local file seeks natively; sending it down that route would ask the // server for a stream we deliberately avoided. const decision = resolveVideoSource({ localPath: "/downloads/film.mkv", remoteUrl: "https://server/Videos/abc/master.m3u8", remoteNeedsTranscoding: true, toAssetUrl, }); expect(decision.needsTranscoding).toBe(false); }); it("streams when nothing is downloaded, preserving the transcoding flag", () => { const decision = resolveVideoSource({ localPath: null, remoteUrl: "https://server/Videos/abc/master.m3u8", remoteNeedsTranscoding: true, toAssetUrl, }); expect(decision).toEqual({ url: "https://server/Videos/abc/master.m3u8", needsTranscoding: true, isLocal: false, }); }); it("streams a direct-play remote without claiming it transcodes", () => { const decision = resolveVideoSource({ localPath: null, remoteUrl: "https://server/Videos/abc/stream.mp4", remoteNeedsTranscoding: false, toAssetUrl, }); expect(decision.needsTranscoding).toBe(false); expect(decision.isLocal).toBe(false); }); it("falls back to streaming for a blank path rather than building a dead asset URL", () => { for (const localPath of ["", " "]) { const decision = resolveVideoSource({ localPath, remoteUrl: "https://server/stream", remoteNeedsTranscoding: false, toAssetUrl, }); expect(decision.isLocal).toBe(false); expect(decision.url).toBe("https://server/stream"); } }); });