domain: primaryImageTag -> imageId end-to-end (phase 4a/4b)

Rust: PlayerMediaItem and MergedMediaItem gain image_id (dual-carry),
populated from primary_image_tag at every construction/conversion site.
Regenerated bindings.

Frontend: all catalog + player + merged readers now use imageId. The
NowPlayingItem->MediaItem bridge (player.ts) properly maps the remote
session's Jellyfin fields (Type, runTimeTicks, primaryImageTag) onto the
neutral kind/durationMs/imageId. Types that are genuinely out of scope
(Person, NowPlayingItem, PlayItemRequest) keep primaryImageTag.

Rust 456, frontend 644, check clean.
This commit is contained in:
2026-07-23 21:40:58 +02:00
parent 2b42b74912
commit 93d198ce21
33 changed files with 107 additions and 51 deletions
+3
View File
@@ -380,6 +380,7 @@ mod tests {
artist_items: None,
artists: Some(vec!["Test Artist".to_string()]),
primary_image_tag: None,
image_id: None,
item_type: Some("Audio".to_string()),
playlist_id: None,
duration: Some(180.0),
@@ -438,6 +439,7 @@ mod tests {
artist_items: None,
artists: Some(vec!["Test Artist".to_string()]),
primary_image_tag: None,
image_id: None,
item_type: Some("Audio".to_string()),
playlist_id: None,
duration: Some(180.0),
@@ -490,6 +492,7 @@ mod tests {
artist_items: None,
artists: Some(vec!["Test Artist".to_string()]),
primary_image_tag: None,
image_id: None,
item_type: Some("Audio".to_string()),
playlist_id: None,
duration: Some(180.0),
+14 -1
View File
@@ -67,9 +67,16 @@ pub struct MediaItem {
/// Artists as array of strings (fallback when artist_items not available)
#[serde(default, skip_serializing_if = "Option::is_none")]
pub artists: Option<Vec<String>>,
/// Primary image tag for artwork
/// Primary image tag for artwork.
///
/// Legacy Jellyfin name; being replaced by `image_id` (same value). Dual-carried
/// while the frontend migrates (docs/specs/frontend-domain-model.md).
#[serde(default, skip_serializing_if = "Option::is_none")]
pub primary_image_tag: Option<String>,
/// Neutral image identifier the frontend resolves to a URL — replaces
/// `primary_image_tag`.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub image_id: Option<String>,
/// Item type (Audio, Movie, Episode, etc.)
#[serde(rename = "type", default, skip_serializing_if = "Option::is_none")]
pub item_type: Option<String>,
@@ -345,6 +352,7 @@ mod tests {
artist_items: None,
artists: None,
primary_image_tag: None,
image_id: None,
item_type: None,
playlist_id: None,
duration: None,
@@ -380,6 +388,7 @@ mod tests {
artist_items: None,
artists: None,
primary_image_tag: None,
image_id: None,
item_type: None,
playlist_id: None,
duration: None,
@@ -414,6 +423,7 @@ mod tests {
artist_items: None,
artists: None,
primary_image_tag: None,
image_id: None,
item_type: None,
playlist_id: None,
duration: None,
@@ -448,6 +458,7 @@ mod tests {
artist_items: None,
artists: None,
primary_image_tag: None,
image_id: None,
item_type: None,
playlist_id: None,
duration: None,
@@ -489,6 +500,7 @@ mod tests {
artist_items: None,
artists: None,
primary_image_tag: None,
image_id: None,
item_type: None,
playlist_id: None,
duration: None,
@@ -523,6 +535,7 @@ mod tests {
artist_items: None,
artists: None,
primary_image_tag: None,
image_id: None,
item_type: Some("Movie".to_string()),
playlist_id: None,
duration: Some(120.0),
+1
View File
@@ -1397,6 +1397,7 @@ mod tests {
artist_items: None,
artists: Some(vec!["Test Artist".to_string()]),
primary_image_tag: None,
image_id: None,
item_type: Some("Audio".to_string()),
playlist_id: None,
duration: Some(180.0),
+1
View File
@@ -551,6 +551,7 @@ mod tests {
artist_items: None,
artists: Some(vec!["Artist".to_string()]),
primary_image_tag: None,
image_id: None,
item_type: Some("Audio".to_string()),
playlist_id: None,
duration: Some(180.0),
+2
View File
@@ -242,6 +242,7 @@ mod tests {
artist_items: None,
artists: Some(vec!["Test Artist".to_string()]),
primary_image_tag: None,
image_id: None,
item_type: Some("Audio".to_string()),
playlist_id: None,
duration: Some(180.0),
@@ -272,6 +273,7 @@ mod tests {
artist_items: None,
artists: None,
primary_image_tag: None,
image_id: None,
item_type: Some("Movie".to_string()),
playlist_id: None,
duration: Some(7200.0),
+1
View File
@@ -323,6 +323,7 @@ mod tests {
artist_items: None,
artists: None,
primary_image_tag: None,
image_id: None,
item_type: Some("Video".to_string()),
playlist_id: None,
duration: Some(100.0),