feat(models,core): playlist revision evidence and track-ids fetch

Playlist and PlaylistWithTrackIds deserialize the API updated_at stamp
(absent on some list shapes, hence optional), and the core facade
exposes the lightweight playlist/get?extra=track_ids fetch the
membership hydrator drives.

cc
This commit is contained in:
vicrodh committed 2026-08-30 16:38:13 -06:00
1 parent e1138756e6
commit 44df1e53a4
4 files changed
+30 -12

No files matched your search

@@ -34,10 +34,7 @@ pub enum PlaylistTrackRef {
/// A library-projected row: a local file, or a Jellyfin/Subsonic track
/// (their playlist storage identity is the projection). `path` is the
/// `local_tracks.file_path` value local playlists key on.
Library {
track_id: i64,
path: Option<String>,
},
Library { track_id: i64, path: Option<String> },
/// A Plex track by rating key.
Plex { rating_key: String },
}
@@ -467,7 +464,10 @@ mod tests {
// The Qobuz playlist holds the library row and the Plex key (2 of 3);
// the local playlist holds all three.
assert_eq!(contained(&rows, ContainmentTarget::Qobuz(7)), Some(2));
assert_eq!(contained(&rows, ContainmentTarget::Local(lp.clone())), Some(3));
assert_eq!(
contained(&rows, ContainmentTarget::Local(lp.clone())),
Some(3)
);
assert_eq!(rows[0].target, ContainmentTarget::Local(lp));
}
@@ -215,10 +215,7 @@ pub fn current_generation(conn: &Connection) -> Result<i64> {
/// An EMPTY list is still recorded (a user can genuinely delete every
/// playlist), but the caller must only invoke this for a fetch that
/// succeeded — a network failure must never masquerade as an empty library.
pub fn record_authoritative_list(
conn: &Connection,
entries: &[AuthoritativeEntry],
) -> Result<i64> {
pub fn record_authoritative_list(conn: &Connection, entries: &[AuthoritativeEntry]) -> Result<i64> {
let ts = now_ms();
conn.execute_batch("BEGIN IMMEDIATE")?;
let result = (|| -> Result<i64> {
@@ -620,9 +617,7 @@ pub fn track_ids(conn: &Connection, qobuz_playlist_id: u64) -> Result<Vec<u64>>
WHERE qobuz_playlist_id = ?1 ORDER BY position",
)?;
let mut out = Vec::new();
for r in stmt.query_map(params![qobuz_playlist_id as i64], |r| {
r.get::<_, i64>(0)
})? {
for r in stmt.query_map(params![qobuz_playlist_id as i64], |r| r.get::<_, i64>(0))? {
out.push(r? as u64);
}
Ok(out)