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))
}
}
|