/* This file is part of jellything (https://codeberg.org/metamuffin/jellything) which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2025 metamuffin */ use crate::{ Node, NodeID, NodeIDOrSlug, ObjectIds, SourceTrack, SourceTrackKind, TmdbKind, TraktKind, }; use serde::{Deserialize, Serialize}; use std::{fmt::Display, str::FromStr}; impl SourceTrackKind { pub fn letter(&self) -> char { match self { SourceTrackKind::Video { .. } => 'v', SourceTrackKind::Audio { .. } => 'a', SourceTrackKind::Subtitles => 's', } } } impl Display for SourceTrack { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let kspec = match &self.kind { SourceTrackKind::Video { width, height, fps, .. } => { format!("Video: {width}x{height} {}fps ", fps.unwrap_or(0.)) } SourceTrackKind::Audio { channels, sample_rate, bit_depth, } => format!( "Audio: {channels}ch {sample_rate}Hz {}bits ", bit_depth.unwrap_or(0) ), SourceTrackKind::Subtitles => "Subtitles: ".to_string(), }; f.write_fmt(format_args!( "{} {:?} {} ({})", kspec, self.name, self.language, self.codec )) } } impl Display for TmdbKind { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str(match self { TmdbKind::Tv => "tv", TmdbKind::Movie => "movie", }) } } impl TraktKind { pub fn singular(self) -> &'static str { match self { TraktKind::Movie => "movie", TraktKind::Show => "show", TraktKind::Season => "season", TraktKind::Episode => "episode", TraktKind::Person => "person", TraktKind::User => "user", } } pub fn plural(self) -> &'static str { match self { TraktKind::Movie => "movies", TraktKind::Show => "shows", TraktKind::Season => "seasons", TraktKind::Episode => "episodes", TraktKind::Person => "people", TraktKind::User => "users", // //! not used in API } } } impl Display for TraktKind { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str(match self { TraktKind::Movie => "Movie", TraktKind::Show => "Show", TraktKind::Season => "Season", TraktKind::Episode => "Episode", TraktKind::Person => "Person", TraktKind::User => "User", }) } } impl Display for ObjectIds { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if let Some(id) = self.trakt { f.write_fmt(format_args!("trakt={}", id))?; } if let Some(_id) = &self.slug { f.write_str(",slug")?; } if let Some(id) = self.tmdb { f.write_fmt(format_args!(",tmdb={}", id))?; } if let Some(_id) = &self.imdb { f.write_str(",imdb")?; } if let Some(_id) = &self.tvdb { f.write_str(",tvdb")?; } if let Some(_id) = &self.omdb { f.write_str(",omdb")?; } Ok(()) } } impl NodeID { pub fn from_slug(slug: &str) -> Self { let mut h = blake3::Hasher::new(); h.update(slug.as_bytes()); Self(*h.finalize().as_bytes()) } #[inline] pub fn from_node(node: &Node) -> Self { Self::from_slug(&node.slug) } } impl Node { #[inline] pub fn id(&self) -> NodeID { NodeID::from_node(self) } } impl NodeID { pub const MIN: NodeID = NodeID([0; 32]); pub const MAX: NodeID = NodeID([255; 32]); } impl FromStr for NodeID { type Err = hex::FromHexError; fn from_str(s: &str) -> Result { if let Some(id) = s.strip_prefix("+") { let mut k = [0; 32]; hex::decode_to_slice(id, &mut k)?; Ok(NodeID(k)) } else { Ok(NodeID::from_slug(s)) } } } impl Display for NodeID { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str("+")?; f.write_str(&hex::encode(self.0))?; Ok(()) } } impl Display for NodeIDOrSlug { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { NodeIDOrSlug::ID(x) => x.fmt(f), NodeIDOrSlug::Slug(x) => x.fmt(f), } } } impl From for NodeIDOrSlug { fn from(value: NodeID) -> Self { Self::ID(value) } } impl From for NodeIDOrSlug { fn from(value: String) -> Self { Self::Slug(value) } } impl Serialize for NodeID { fn serialize(&self, serializer: S) -> Result { serializer.serialize_str(&hex::encode(self.0)) } } impl<'de> Deserialize<'de> for NodeID { fn deserialize>(deserializer: D) -> Result { let mut k = [0; 32]; hex::decode_to_slice(String::deserialize(deserializer)?, &mut k).map_err(|_| { ::custom(format_args!("nodeid hex invalid")) })?; Ok(NodeID(k)) } }