feat(offline-cache): schema migration for v2 CMAF bundle storage

Adds columns to cached_tracks for the v2 format that stores Qobuz's raw
CMAF segments bit-identical on disk, with the per-track AES content key
wrapped via qbz-secrets (OS keyring or KDF fallback).

New columns (added via idempotent ALTER TABLE, safe to re-run):
- cache_format    INTEGER DEFAULT 1   — 1 = legacy plain FLAC (existing),
                                          2 = raw CMAF bundle (new)
- init_path       TEXT                — path to init.mp4 (FLAC header +
                                          segment table)
- content_key_wrapped BLOB            — wrapped 16-byte AES content key
- infos_wrapped       BLOB            — wrapped session infos salt
- format_id       INTEGER             — Qobuz format id (5/6/7/27)
- n_segments      INTEGER             — number of audio segments

Existing rows keep cache_format=1 and continue to play from the plain
FLAC at file_path — zero regression for users with populated caches
when the upgrade ships. New downloads will land as cache_format=2. The
two formats coexist until v1 rows age out naturally (user re-download
or subscription-lapse cache wipe).

Adds set_cmaf_bundle() / get_cmaf_bundle() helpers + a CmafBundleRow
struct so the download path and the playback path have one authoritative
DB surface to talk to.

Also adds qbz-secrets as a direct src-tauri dep so the next commit
(rewiring spawn_track_cache_download) can wrap keys right at the
download site.

cc
This commit is contained in:
vicrodh committed 2026-04-17 07:30:50 -06:00
1 parent 1743c9e5ec
commit 935b3f81e0
3 files changed
+165

No files matched your search

+1
View File
@@ -35,6 +35,7 @@ qbz-cache = { path = "../crates/qbz-cache" }
qbz-library = { path = "../crates/qbz-library" }
qbz-cast = { path = "../crates/qbz-cast" }
qbz-cmaf = { path = "../crates/qbz-cmaf" }
qbz-secrets = { path = "../crates/qbz-secrets" }
mdns-sd = "0.11"
qconnect-app = { path = "../crates/qconnect-app" }
qconnect-core = { path = "../crates/qconnect-core" }