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
|
use anyhow::{anyhow, bail};
use clap::Parser;
use jellycommon::{ItemInfo, Source, SourceTrack};
use std::{collections::BTreeMap, fs::File, io::Write, path::PathBuf};
use webm_iterable::{
matroska_spec::{Master, MatroskaSpec},
WebmIterator,
};
#[derive(Parser)]
struct Args {
#[clap(short = 'I', long)]
identifier: String,
#[clap(short = 'O', long)]
write_json: bool,
#[clap(short, long)]
title: String,
#[clap(short = 'i', long)]
input: PathBuf,
}
fn main() -> anyhow::Result<()> {
let args = Args::parse();
let mut tracks = BTreeMap::new();
let mut input = File::open(args.input.clone()).unwrap();
for tag in WebmIterator::new(&mut input, &[MatroskaSpec::TrackEntry(Master::Start)]) {
let tag = tag?;
match tag {
MatroskaSpec::TrackEntry(master) => {
let (
mut index,
mut language,
mut codec,
mut kind,
mut sample_rate,
mut channels,
mut width,
mut height,
mut name,
) = (None, None, None, None, None, None, None, None, None);
for c in master.get_children() {
match c {
MatroskaSpec::CodecID(b) => codec = Some(b),
MatroskaSpec::Language(v) => language = Some(v),
MatroskaSpec::TrackNumber(v) => index = Some(v),
MatroskaSpec::TrackType(v) => kind = Some(v),
MatroskaSpec::Audio(master) => {
for c in master.get_children() {
match c {
MatroskaSpec::Channels(v) => channels = Some(v as usize),
MatroskaSpec::SamplingFrequency(v) => sample_rate = Some(v),
_ => (),
}
}
}
MatroskaSpec::Video(master) => {
for c in master.get_children() {
match c {
MatroskaSpec::PixelWidth(v) => width = Some(v),
MatroskaSpec::PixelHeight(v) => height = Some(v),
_ => (),
}
}
}
MatroskaSpec::Name(v) => name = Some(v),
_ => (),
}
}
tracks.insert(
index.unwrap(),
match kind.ok_or(anyhow!("track type required"))? {
1 => SourceTrack::Video {
language: language.unwrap_or("none".to_string()),
codec: codec.unwrap(),
width: width.unwrap(),
height: height.unwrap(),
},
2 => SourceTrack::Audio {
channels: channels.unwrap(),
codec: codec.unwrap(),
sample_rate: sample_rate.unwrap(),
language: language.unwrap(),
},
17 => SourceTrack::Subtitles {
language: name.unwrap_or("unknown".to_string()),
codec: codec.unwrap(),
},
_ => bail!("invalid track type"),
},
);
}
MatroskaSpec::Tags(Master::End) => break,
_ => (),
}
}
let k = serde_json::to_string_pretty(&ItemInfo {
title: args.title,
source: Source {
path: args.input.clone(),
tracks,
},
})?;
if args.write_json {
let mut f = File::create(format!("{}.json", args.identifier))?;
f.write_all(k.as_bytes())?;
} else {
println!("{k}")
}
Ok(())
}
|