aboutsummaryrefslogtreecommitdiff
path: root/common/src/impl.rs
blob: 585c7789836178d21cf7858b0ea11d584eba97f1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/*
    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 <metamuffin.org>
*/
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<Self, Self::Err> {
        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<NodeID> for NodeIDOrSlug {
    fn from(value: NodeID) -> Self {
        Self::ID(value)
    }
}
impl From<String> for NodeIDOrSlug {
    fn from(value: String) -> Self {
        Self::Slug(value)
    }
}
impl Serialize for NodeID {
    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        serializer.serialize_str(&hex::encode(self.0))
    }
}
impl<'de> Deserialize<'de> for NodeID {
    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        let mut k = [0; 32];
        hex::decode_to_slice(String::deserialize(deserializer)?, &mut k).map_err(|_| {
            <D::Error as serde::de::Error>::custom(format_args!("nodeid hex invalid"))
        })?;
        Ok(NodeID(k))
    }
}