/* 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, SourceTrack, SourceTrackKind}; 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::Subtitle => '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::Subtitle => "Subtitle: ".to_string(), }; f.write_fmt(format_args!( "{} {:?} {} ({})", kspec, self.name, self.language, self.codec )) } } 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)) } }