use std::env;
use std::io;
use std::io::Write;
use std::fs;
use std::process::Command;
use std::time::Duration;
use anyhow::{Result, Context};
use clap::Arg;
use tracing_subscriber::EnvFilter;
use tracing_subscriber::prelude::*;
use dash_mpd::MPD;
use dash_mpd::fetch::{DashDownloader, parse_resolving_xlinks};
#[tokio::main]
async fn main() -> Result<()> {
let fmt_layer = tracing_subscriber::fmt::layer()
.compact();
let filter_layer = EnvFilter::try_from_default_env()
.or_else(|_| EnvFilter::try_new("info,reqwest=warn"))
.unwrap();
tracing_subscriber::registry()
.with(filter_layer)
.with(fmt_layer)
.init();
let matches = clap::Command::new("round-trip")
.arg(Arg::new("url")
.num_args(1)
.value_name("MPD-URL")
.help("URL of the MPD manifest")
.required(true)
.index(1))
.get_matches();
let url = matches.get_one::<String>("url").unwrap();
let client = reqwest::Client::builder()
.timeout(Duration::new(30, 0))
.build()
.context("creating HTTP client")?;
let xml = client.get(url)
.header("Accept", "application/dash+xml,video/vnd.mpeg.dash.mpd")
.header("Accept-language", "en-US,en")
.send().await
.context("requesting DASH MPD")?
.error_for_status()
.context("requesting DASH MPD")?
.text().await
.context("fetching MPD content")?;
let out1 = env::temp_dir().join("mpd-orig.xml");
fs::write(&out1, &xml)?;
let dl = DashDownloader::new(url)
.with_http_client(client.clone());
let mpd: MPD = parse_resolving_xlinks(&dl, &xml.into_bytes()).await
.context("parsing DASH XML")?;
let rewritten = mpd.to_string();
let out2 = env::temp_dir().join("mpd-rewritten.xml");
fs::write(&out2, rewritten)?;
println!("==== xmldiff output ====");
let cmd = Command::new("xmldiff")
.args([out1.clone(), out2.clone()])
.output()
.context("executing xmldiff as a subprocess")?;
io::stdout().write_all(&cmd.stdout).unwrap();
println!("==== xdiff output ====");
if let Ok(meta) = fs::metadata(out1.clone()) {
if meta.len() < 100_000 {
let cmd = Command::new("xdiff")
.args(["-left", &out1.to_string_lossy(), "-right", &out2.to_string_lossy()])
.output()
.context("executing xdiff as a subprocess")?;
io::stdout().write_all(&cmd.stdout).unwrap();
} else {
println!(" skipping xdiff for this large MPD manifest");
}
}
Ok(())
}