diff --git a/src/main.rs b/src/main.rs index 742ecd894945b4af74b755a1f529773e3c404a34..0c08408fade7481910fa48d9d3f51b3b764d6d29 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,30 +3,26 @@ #![forbid(elided_lifetimes_in_paths, unsafe_code)] mod iotro; +mod project; mod question; mod render; mod time; use self::{ iotro::Language, - question::Question, - render::{ffmpeg::FfmpegOutputFormat, Renderer}, - time::{parse_date, parse_time, Date, Time} + project::{Project, ProjectLecture, ProjectSource, Resolution}, + render::Renderer, + time::{parse_date, parse_time, Time} }; use camino::Utf8PathBuf as PathBuf; use clap::Parser; use console::style; -use rational::Rational; -use serde::{Deserialize, Serialize}; -use serde_with::{serde_as, DisplayFromStr}; #[cfg(feature = "mem_limit")] use std::sync::RwLock; use std::{ - collections::BTreeSet, fmt::Display, fs, - io::{self, BufRead as _, Write}, - str::FromStr + io::{self, BufRead as _, Write} }; #[cfg(feature = "mem_limit")] @@ -73,159 +69,6 @@ struct Args { stereo: bool } -macro_rules! resolutions { - ($($res:ident: $width:literal x $height:literal at $bitrate:literal in $format:ident),+) => { - #[allow(non_camel_case_types, clippy::upper_case_acronyms)] - #[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)] - enum Resolution { - $( - #[doc = concat!(stringify!($width), "x", stringify!($height))] - $res - ),+ - } - - const NUM_RESOLUTIONS: usize = { - let mut num = 0; - $(num += 1; stringify!($res);)+ - num - }; - - impl Resolution { - fn values() -> [Self; NUM_RESOLUTIONS] { - [$(Self::$res),+] - } - - fn width(self) -> usize { - match self { - $(Self::$res => $width),+ - } - } - - fn height(self) -> usize { - match self { - $(Self::$res => $height),+ - } - } - - fn bitrate(self) -> u64 { - match self { - $(Self::$res => $bitrate),+ - } - } - - fn format(self) -> FfmpegOutputFormat { - match self { - $(Self::$res => FfmpegOutputFormat::$format),+ - } - } - } - - impl FromStr for Resolution { - type Err = anyhow::Error; - - fn from_str(s: &str) -> anyhow::Result<Self> { - Ok(match s { - $(concat!(stringify!($height), "p") => Self::$res,)+ - _ => anyhow::bail!("Unknown Resolution: {s:?}") - }) - } - } - } -} - -resolutions! { - nHD: 640 x 360 at 500_000 in AvcAac, - HD: 1280 x 720 at 1_000_000 in AvcAac, - FullHD: 1920 x 1080 at 750_000 in Av1Opus, - WQHD: 2560 x 1440 at 1_000_000 in Av1Opus, - // TODO qsx muss mal sagen wieviel bitrate für 4k - UHD: 3840 x 2160 at 2_000_000 in Av1Opus -} - -#[derive(Deserialize, Serialize)] -struct Project { - lecture: ProjectLecture, - source: ProjectSource, - progress: ProjectProgress -} - -#[serde_as] -#[derive(Deserialize, Serialize)] -struct ProjectLecture { - course: String, - label: String, - docent: String, - #[serde_as(as = "DisplayFromStr")] - date: Date, - #[serde(default = "Default::default")] - #[serde_as(as = "DisplayFromStr")] - lang: Language<'static> -} - -#[serde_as] -#[derive(Deserialize, Serialize)] -struct ProjectSource { - files: Vec<String>, - stereo: bool, - - #[serde_as(as = "Option<DisplayFromStr>")] - start: Option<Time>, - #[serde_as(as = "Option<DisplayFromStr>")] - end: Option<Time>, - - #[serde(default)] - #[serde_as(as = "Vec<(DisplayFromStr, DisplayFromStr)>")] - fast: Vec<(Time, Time)>, - - #[serde(default)] - #[serde_as(as = "Vec<(DisplayFromStr, DisplayFromStr, _)>")] - questions: Vec<(Time, Time, String)>, - - metadata: Option<ProjectSourceMetadata> -} - -#[serde_as] -#[derive(Deserialize, Serialize)] -struct ProjectSourceMetadata { - /// The duration of the source video. - #[serde_as(as = "DisplayFromStr")] - source_duration: Time, - /// The FPS of the source video. - #[serde_as(as = "DisplayFromStr")] - source_fps: Rational, - /// The time base of the source video. - #[serde_as(as = "DisplayFromStr")] - source_tbn: Rational, - /// The resolution of the source video. - source_res: Resolution, - /// The sample rate of the source audio. - source_sample_rate: u32 -} - -#[derive(Default, Deserialize, Serialize)] -struct ProjectProgress { - #[serde(default)] - preprocessed: bool, - - #[serde(default)] - asked_start_end: bool, - - #[serde(default)] - asked_fast: bool, - - #[serde(default)] - asked_questions: bool, - - #[serde(default)] - rendered_assets: bool, - - #[serde(default)] - rendered: bool, - - #[serde(default)] - transcoded: BTreeSet<Resolution> -} - fn ask(question: impl Display) -> String { let mut stdout = io::stdout().lock(); let mut stdin = io::stdin().lock(); diff --git a/src/render/mod.rs b/src/render/mod.rs index 15fdf80889c8f81b5843bc155c607d899f8cdcec..cc34ed9359ac6139fcec80d28a7886c01812ceb8 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -7,10 +7,10 @@ use self::{ }; use crate::{ iotro::{intro, outro}, + project::{Project, ProjectLecture, ProjectSourceMetadata, Resolution}, question::Question, render::ffmpeg::{Ffmpeg, FfmpegInput}, - time::{format_date, format_time, Time}, - Project, ProjectLecture, ProjectSourceMetadata, Resolution + time::{format_date, format_time, Time} }; use anyhow::{bail, Context}; use camino::{Utf8Path as Path, Utf8PathBuf as PathBuf};