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