// Code generated by ndpgen. DO NOT EDIT.
//
//! Navidrome shared plugin data types.

use serde::{Deserialize, Serialize};
use std::collections::HashMap;

// Helper functions for skip_serializing_if with numeric types
#[allow(dead_code)]
fn is_zero_i32(value: &i32) -> bool { *value == 0 }
#[allow(dead_code)]
fn is_zero_u32(value: &u32) -> bool { *value == 0 }
#[allow(dead_code)]
fn is_zero_i64(value: &i64) -> bool { *value == 0 }
#[allow(dead_code)]
fn is_zero_u64(value: &u64) -> bool { *value == 0 }
#[allow(dead_code)]
fn is_zero_f32(value: &f32) -> bool { *value == 0.0 }
#[allow(dead_code)]
fn is_zero_f64(value: &f64) -> bool { *value == 0.0 }
/// ArtistRef is the minimal information a plugin returns for Navidrome to match an
/// artist against the library. It is a reference, not a full artist entity: it
/// carries only matching keys (name and optional internal/MusicBrainz IDs) plus a
/// few projection fields used when describing a track's participants, never
/// descriptive data such as biographies or images.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ArtistRef {
    /// ID is the internal Navidrome artist ID (if known).
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub id: String,
    /// Name is the artist name.
    #[serde(default)]
    pub name: String,
    /// MBID is the MusicBrainz ID for the artist.
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub mbid: String,
    /// SortName is the artist name used for sorting (if known).
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub sort_name: String,
    /// Role is the participation category (e.g. "artist", "composer", "performer").
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub role: String,
    /// SubRole is a specialization within Role (e.g. the instrument for a performer).
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub sub_role: String,
}
/// SongRef is the minimal information exchanged between a plugin and Navidrome to
/// match a song. It is used both as input (a song Navidrome already has) and as
/// output (a song a plugin suggests, which may not be in the library yet). Unlike
/// Track, it is an abstract recording reference carrying only matching keys (IDs,
/// ISRC, and title/artist/album/duration) that Navidrome resolves to a library track.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SongRef {
    /// ID is the internal Navidrome mediafile ID (if known).
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub id: String,
    /// Name is the song name.
    #[serde(default)]
    pub name: String,
    /// MBID is the MusicBrainz ID for the song.
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub mbid: String,
    /// ISRC is the International Standard Recording Code for the song.
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub isrc: String,
    /// Artist is the artist name.
    /// 
    /// Deprecated: use Artists.
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub artist: String,
    /// ArtistMBID is the MusicBrainz artist ID.
    /// 
    /// Deprecated: use Artists.
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub artist_mbid: String,
    /// Artists is the full artist list; when set, takes precedence over Artist/ArtistMBID for matching.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub artists: Vec<ArtistRef>,
    /// Album is the album name.
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub album: String,
    /// AlbumMBID is the MusicBrainz release ID.
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub album_mbid: String,
    /// Duration is the song duration in seconds.
    /// 
    /// Deprecated: use DurationMs, which carries millisecond precision. When
    /// DurationMs is non-zero it takes precedence; Duration is kept only for
    /// backwards compatibility with plugins that still send seconds.
    #[serde(default, skip_serializing_if = "is_zero_f32")]
    pub duration: f32,
    /// DurationMs is the song duration in milliseconds. It supersedes Duration
    /// when non-zero.
    #[serde(default, skip_serializing_if = "is_zero_u32")]
    pub duration_ms: u32,
}
/// Track is a stable, public projection of a library media file for plugin consumption.
/// It is a sane subset of the internal model.MediaFile, intended for reuse across host
/// services and capabilities. Timestamps are Unix epoch seconds.
/// 
/// Unlike SongRef, which is an abstract recording reference carrying only matching keys,
/// Track is a concrete library entity: it identifies a specific media file that exists
/// (or once existed) in the library and exposes its full descriptive metadata.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Track {
    /// Identity & location
    #[serde(default)]
    pub id: String,
    #[serde(default)]
    pub library_id: i32,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub library_name: String,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub path: String,
    #[serde(default)]
    pub missing: bool,
    /// Core metadata
    #[serde(default)]
    pub title: String,
    #[serde(default)]
    pub album: String,
    #[serde(default)]
    pub artist: String,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub album_artist: String,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub album_id: String,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub sort_title: String,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub sort_album_name: String,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub sort_artist_name: String,
    /// Track / disc / dates
    #[serde(default)]
    pub track_number: i32,
    #[serde(default)]
    pub disc_number: i32,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub disc_subtitle: String,
    #[serde(default)]
    pub year: i32,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub date: String,
    #[serde(default)]
    pub original_year: i32,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub original_date: String,
    #[serde(default)]
    pub release_year: i32,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub release_date: String,
    /// Audio / file
    #[serde(default)]
    pub size: i64,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub suffix: String,
    #[serde(default)]
    pub duration: f64,
    #[serde(default)]
    pub bit_rate: i32,
    #[serde(default)]
    pub sample_rate: i32,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub bit_depth: Option<i32>,
    #[serde(default)]
    pub channels: i32,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub codec: String,
    /// Descriptive
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub genres: Vec<String>,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub comment: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub bpm: Option<i32>,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub explicit_status: String,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub catalog_num: String,
    #[serde(default)]
    pub compilation: bool,
    #[serde(default)]
    pub has_cover_art: bool,
    /// MusicBrainz
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub mbz_recording_id: String,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub mbz_release_track_id: String,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub mbz_album_id: String,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub mbz_release_group_id: String,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub mbz_album_type: String,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    pub mbz_album_comment: String,
    /// ReplayGain — nil means no data; 0 is a valid measured value, so these
    /// must stay pointers to distinguish "absent" from "0".
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub rg_album_gain: Option<f64>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub rg_album_peak: Option<f64>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub rg_track_gain: Option<f64>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub rg_track_peak: Option<f64>,
    /// Timestamps (Unix epoch seconds)
    #[serde(default)]
    pub birth_time: i64,
    #[serde(default)]
    pub created_at: i64,
    #[serde(default)]
    pub updated_at: i64,
    /// AverageRating is the track's mean rating across all users (always set; 0 when unrated).
    #[serde(default)]
    pub average_rating: f64,
    /// Per-user annotations, set only for a user-scoped match. Timestamps are Unix
    /// seconds; a nil pointer means "no value".
    #[serde(default, skip_serializing_if = "std::ops::Not::not")]
    pub starred: bool,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub starred_at: Option<i64>,
    #[serde(default, skip_serializing_if = "is_zero_i32")]
    pub rating: i32,
    #[serde(default, skip_serializing_if = "is_zero_i64")]
    pub play_count: i64,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub play_date: Option<i64>,
    /// Composite
    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
    pub tags: std::collections::HashMap<String, Vec<String>>,
    /// Participants lists the track's artists across all roles, each tagged with its Role.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub participants: Vec<ArtistRef>,
}
