This repository has no description
1use crate::{synchronization::sync::Syncable, ui::MaybeProgressBar};
2use serde::Deserialize;
3use serde_aux::field_attributes::deserialize_number_from_string;
4use std::{collections::HashMap, io::Read, path::PathBuf, process::Stdio};
5
6use super::sync::TimestampMS;
7
8pub struct CueMarkersSynchronizer {
9 pub path: PathBuf,
10}
11
12#[derive(Debug, Deserialize)]
13struct FFprobeChapterTags {
14 title: String,
15}
16
17#[derive(Debug, Deserialize)]
18struct FFprobeChapter {
19 // id: usize,
20 // time_base: String,
21
22 // start: usize,
23 #[serde(deserialize_with = "deserialize_number_from_string")]
24 start_time: f32,
25
26 // end: usize,
27 // #[serde(deserialize_with = "deserialize_number_from_string")]
28 // end_time: f32,
29 tags: FFprobeChapterTags,
30}
31
32#[derive(Debug, Deserialize)]
33struct FFprobeOutput {
34 chapters: Vec<FFprobeChapter>,
35}
36
37impl Syncable for CueMarkersSynchronizer {
38 fn new(path: impl Into<PathBuf>) -> Self {
39 Self { path: path.into() }
40 }
41
42 fn load(
43 &self,
44 progress: Option<&indicatif::ProgressBar>,
45 ) -> super::sync::SyncData {
46 progress.set_length(4);
47 progress.set_message("Running ffprobe");
48
49 let mut ffprobe = std::process::Command::new("ffprobe")
50 .args(["-v", "error"])
51 .args(["-i", &self.path.to_string_lossy()])
52 .args(["-output_format", "json"])
53 .arg("-show_chapters")
54 .stdout(Stdio::piped())
55 .spawn()
56 .expect(&format!(
57 "Couldn't run ffprobe to get chapters of {:?}",
58 self.path
59 ));
60
61 progress.inc(1);
62 progress.set_message("Getting ffprobe output");
63
64 let mut raw_output = String::new();
65 ffprobe
66 .stdout
67 .take()
68 .expect("Coudln't get stdout of ffprobe run")
69 .read_to_string(&mut raw_output)
70 .expect("Couldn't read ffprobe stdout");
71
72 progress.inc(1);
73 progress.set_message("Parsing ffprobe output");
74
75 let output: FFprobeOutput =
76 serde_json::from_str(&raw_output).expect("Invalid ffprobe output");
77
78 progress.inc(1);
79 progress.set_message("Gathering chapters");
80
81 super::sync::SyncData {
82 stems: HashMap::new(),
83 bpm: None,
84 markers: output
85 .chapters
86 .iter()
87 .map(|ch| {
88 (
89 (ch.start_time.to_owned() * 1_000.0) as TimestampMS,
90 ch.tags.title.clone(),
91 )
92 })
93 .collect(),
94 }
95 }
96}