pub mod format; use jellycommon::ItemInfo; use log::{debug, info}; use std::{fs::File, io::Write, path::PathBuf, sync::Arc}; use webm_iterable::{ matroska_spec::{Block, Master, MatroskaSpec}, WebmIterator, WebmWriter, }; pub struct RemuxerContext {} impl RemuxerContext { pub fn new() -> Arc { Arc::new(Self {}) } pub fn generate_into( &self, writer: impl Write, offset: usize, path_base: PathBuf, item: ItemInfo, selection: Vec, ) -> anyhow::Result<()> { let source_path = path_base.join(item.source.path); info!("remuxing {source_path:?} to have tracks {selection:?}"); let mut input = File::open(source_path)?; let tags = WebmIterator::new(&mut input, &[MatroskaSpec::TrackEntry(Master::Start)]); let mut output = WebmWriter::new(writer); let mut tscale = None; let mut duration = None; let mut ignore = false; for tag in tags { let tag = tag.unwrap(); match tag { MatroskaSpec::SeekHead(Master::Start) | MatroskaSpec::Cues(Master::Start) => { ignore = true } MatroskaSpec::SeekHead(Master::End) | MatroskaSpec::Cues(Master::End) => { ignore = false } MatroskaSpec::TrackEntry(master) => { let children = master.get_children(); let mut number = None; for c in &children { if let MatroskaSpec::TrackNumber(n) = c { number = Some(*n) } } let number = number.unwrap(); if selection.contains(&number) { output.write(&MatroskaSpec::TrackEntry(Master::Full(children)))?; } } MatroskaSpec::Block(ref data) => { let data: &[u8] = &data; let block: Block = data.try_into()?; if selection.contains(&block.track) { output.write(&tag)?; } } MatroskaSpec::SimpleBlock(ref data) => { let data: &[u8] = &data; let block: Block = data.try_into()?; if selection.contains(&block.track) { output.write(&tag)?; } } MatroskaSpec::Info(Master::Start) => (), MatroskaSpec::TimestampScale(n) => tscale = Some(n), MatroskaSpec::Duration(n) => duration = Some(n), MatroskaSpec::Info(Master::End) => { output.write(&MatroskaSpec::Info(Master::Full(vec![ MatroskaSpec::TimestampScale(tscale.unwrap()), MatroskaSpec::Title(item.title.clone()), MatroskaSpec::Duration(duration.unwrap()), MatroskaSpec::MuxingApp("jellyremux".to_string()), MatroskaSpec::WritingApp("jellything".to_string()), ])))?; } x => { if !ignore { debug!("{x:?}"); output.write(&x)?; } } } } Ok(()) } } // pub struct SendWriter(pub Sender>); // impl Write for SendWriter { // fn write(&mut self, buf: &[u8]) -> std::io::Result { // self.0.blocking_send(buf.to_owned()).unwrap(); // Ok(buf.len()) // } // fn flush(&mut self) -> std::io::Result<()> { // Ok(()) // TODO should we actually do something here? // } // }