Files
qbz/crates/qbz-account-migration/Cargo.toml
T
vicrodh 800255ac58 feat(account-migration): snapshot, plan, apply and local-profile copy
A frontend-agnostic crate for moving a Qobuz account's favorites and
playlists into another account, additively (contract
qbz-nix-docs/specs/2026-09-02-account-migration-contract.md §9):

- snapshot: capture the signed-in account (five favorite kinds with
  favorited_at, owned playlists with track ids in order, followed
  playlists) into users/<uid>/account_migration/snapshot-*.json; the same
  capture is the target's live state at migration time.
- plan: the pure delta against the target and the ledger. Same-name
  playlists holding nothing foreign are the same playlist and get the
  missing tracks appended; anything foreign means a different playlist and
  a " (migrated)" copy. Favorites are written oldest first so the target's
  own stamps keep the chronology.
- apply: one favorite per call with pacing and bounded retries, 50-track
  chunks, subscriptions re-followed; every success lands in the ledger
  before the next write, so a run resumes and a second run adds nothing.
- local: copy the old profile directory row by row (library folders and
  scanned tracks on the fast path, playlist folders, settings keyed by
  qobuz_playlist_id remapped through the ledger, pinned items, orders,
  preferences, blacklist; media servers, scrobblers and listening history
  behind options). Never the favorites cache, the subscription clock, the
  session or the purchases.

The writes are the ones the app already issues when a user hearts or
creates a playlist; nothing touches subscriptions, purchases or account
data.

cc
2026-09-02 08:24:01 -06:00

21 lines
612 B
TOML

[package]
name = "qbz-account-migration"
version = "0.1.0"
edition = "2021"
description = "Qobuz account migration for QBZ — snapshot one account's favorites and playlists, plan and apply them additively into another (headless, frontend-agnostic)"
authors = ["blitzkriegfc"]
[dependencies]
qbz-models = { path = "../qbz-models" }
qbz-qobuz = { path = "../qbz-qobuz" }
serde = { workspace = true }
serde_json = { workspace = true }
log = { workspace = true }
tokio = { workspace = true }
chrono = { workspace = true }
rusqlite = { version = "0.40", features = ["bundled"] }
[dev-dependencies]
tempfile = "3"