This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

♻️ Add a Pretty trait (with .pretty() -> String) instead of ui::format_* functions

+101 -83
+53 -42
src/ui.rs
··· 9 9 use std::thread::{self, JoinHandle}; 10 10 use std::time::{self, Duration}; 11 11 12 + use crate::Timestamp; 13 + 12 14 pub const PROGRESS_BARS_STYLE: &str = "\x1b]9;4;1;{percent}\x1b\\{prefix:>12.bold.cyan} {percent:03}% [{bar:25}] {msg:01} ({per_sec}, {elapsed} ago)"; 13 15 14 16 pub struct Spinner { ··· 138 140 } 139 141 } 140 142 141 - pub fn display_counts(counts: HashMap<impl std::fmt::Display, usize>) -> String { 142 - counts 143 - .iter() 144 - .filter_map(|(name, &count)| { 145 - if count > 0 { 146 - Some(format!("{count} {name}")) 147 - } else { 148 - None 149 - } 150 - }) 151 - .join(", ") 143 + pub(crate) trait Pretty { 144 + fn pretty(&self) -> String; 145 + } 146 + 147 + impl<K: std::fmt::Display> Pretty for HashMap<K, usize> { 148 + fn pretty(&self) -> String { 149 + self.iter() 150 + .filter_map(|(name, &count)| { 151 + if count > 0 { 152 + Some(format!("{count} {name}")) 153 + } else { 154 + None 155 + } 156 + }) 157 + .join(", ") 158 + } 152 159 } 153 160 154 - pub(crate) fn format_duration(duration: Duration) -> String { 155 - let (hours, rest) = duration.as_millis().div_rem(&3_600_000); 156 - let (minutes, rest) = rest.div_rem(&60_000); 157 - let (seconds, milliseconds) = rest.div_rem(&1_000); 161 + impl Pretty for Duration { 162 + fn pretty(&self) -> String { 163 + let (hours, rest) = self.as_millis().div_rem(&3_600_000); 164 + let (minutes, rest) = rest.div_rem(&60_000); 165 + let (seconds, milliseconds) = rest.div_rem(&1_000); 158 166 159 - if hours > 0 { 160 - format!("{} h {:02} m {:02} s", hours, minutes, seconds) 161 - } else if minutes > 0 { 162 - format!("{} m {:02} s", minutes, seconds) 163 - } else if seconds > 0 { 164 - format!("{}.{:03} s", seconds, milliseconds) 165 - } else { 166 - format!("{} ms", milliseconds) 167 + if hours > 0 { 168 + format!("{} h {:02} m {:02} s", hours, minutes, seconds) 169 + } else if minutes > 0 { 170 + format!("{} m {:02} s", minutes, seconds) 171 + } else if seconds > 0 { 172 + format!("{}.{:03} s", seconds, milliseconds) 173 + } else { 174 + format!("{} ms", milliseconds) 175 + } 167 176 } 168 177 } 169 178 ··· 177 186 } 178 187 } 179 188 180 - pub(crate) fn format_timestamp(ms: usize) -> String { 181 - format!( 182 - "{}", 183 - DateTime::from_timestamp_millis(ms as i64) 184 - .unwrap() 185 - .format("%H:%M:%S%.3f") 186 - ) 189 + impl Pretty for Timestamp { 190 + fn pretty(&self) -> String { 191 + format!( 192 + "{}", 193 + DateTime::from_timestamp_millis(self.ms() as i64) 194 + .unwrap() 195 + .format("%H:%M:%S%.3f") 196 + ) 197 + } 187 198 } 188 199 189 - pub(crate) fn format_timestamp_range(ms_range: &Range<usize>) -> String { 190 - format!( 191 - "from {} to {}", 192 - format_timestamp(ms_range.start), 193 - format_timestamp(ms_range.end) 194 - ) 200 + impl Pretty for Range<Timestamp> { 201 + fn pretty(&self) -> String { 202 + format!("from {} to {}", self.start.pretty(), self.end.pretty()) 203 + } 195 204 } 196 205 197 - pub(crate) fn format_filepath(path: &std::path::Path) -> String { 198 - format!( 199 - "{}{}", 200 - if path.is_relative() { "./" } else { "" }, 201 - path.to_string_lossy() 202 - ) 206 + impl Pretty for std::path::PathBuf { 207 + fn pretty(&self) -> String { 208 + format!( 209 + "{}{}", 210 + if self.is_relative() { "./" } else { "" }, 211 + self.to_string_lossy() 212 + ) 213 + } 203 214 }
+3 -3
src/video/context.rs
··· 1 1 use super::Animation; 2 2 use super::animation::{AnimationUpdateFunction, LayerAnimationUpdateFunction}; 3 3 use super::hooks::{LaterHook, LaterRenderFunction}; 4 + use crate::Timestamp; 4 5 use crate::synchronization::audio::{Note, StemAtInstant}; 5 6 use crate::synchronization::sync::SyncData; 6 - use crate::ui; 7 7 use itertools::Itertools; 8 8 use nanoid::nanoid; 9 9 use std::fmt::Display; ··· 26 26 } 27 27 28 28 impl<C> Context<'_, C> { 29 - pub fn timestamp(&self) -> String { 30 - ui::format_timestamp(self.ms).to_string() 29 + pub fn timestamp(&self) -> Timestamp { 30 + Timestamp(self.ms) 31 31 } 32 32 33 33 pub fn beat_fractional(&self) -> f32 {
+3 -3
src/video/encoders/ffmpeg.rs
··· 1 1 use crate::{ 2 2 Video, 3 3 rendering::rasterization::{create_pixmap, paint_svg_on_pixmap}, 4 - ui, 4 + ui::Pretty, 5 5 video::{encoders::Encoder, engine::EngineOutput}, 6 6 }; 7 7 use anyhow::Result; ··· 122 122 fn finish_message(&self, time_elapsed: std::time::Duration) -> String { 123 123 format!( 124 124 "video to {} in {}", 125 - ui::format_filepath(&self.destination), 126 - ui::format_duration(time_elapsed) 125 + self.destination.pretty(), 126 + time_elapsed.pretty() 127 127 ) 128 128 } 129 129 }
+5 -5
src/video/encoders/vgv.rs
··· 1 1 use crate::{ 2 2 Canvas, Video, 3 3 rendering::svg, 4 - ui, 4 + ui::Pretty, 5 5 video::{encoders::Encoder, engine::EngineOutput}, 6 6 }; 7 7 use ::vgv::Transcoder; ··· 99 99 match self.transcode { 100 100 VGVTranscodeMode::None => format!( 101 101 "VGV video to {} in {}", 102 - ui::format_filepath(&self.destination), 103 - ui::format_duration(time_elapsed) 102 + self.destination.pretty(), 103 + time_elapsed.pretty() 104 104 ), 105 105 VGVTranscodeMode::ToHTML => format!( 106 106 "HTML player for VGV video to {} in {}", 107 - ui::format_filepath(&self.destination), 108 - ui::format_duration(time_elapsed) 107 + self.destination.pretty(), 108 + time_elapsed.pretty() 109 109 ), 110 110 } 111 111 }
+15 -14
src/video/encoding.rs
··· 1 1 use super::Video; 2 - use crate::ui::{self, Log}; 2 + use crate::ui::{Log, Pretty}; 3 3 use crate::video::encoders::Encoder; 4 4 use crate::video::encoders::vgv::VGVTranscodeMode; 5 5 use crate::video::engine::EngineOutput; ··· 22 22 23 23 let _ = notify_rust::Notification::new() 24 24 .appname("Shapemaker") 25 - .summary(&format!( 26 - "{} is ready", 27 - ui::format_filepath(&output_file.into()) 28 - )) 25 + .summary(&format!("{} is ready", &output_file.into().pretty())) 29 26 .body(&format!( 30 27 "Encoded with {encoder_name} in {}", 31 - ui::format_duration(time_taken) 28 + time_taken.pretty() 32 29 )) 33 30 .show(); 34 31 ··· 43 40 self.initial_canvas.resolution_to_size_even(self.resolution); 44 41 45 42 let destination = output_path.into(); 43 + let pb = &self.progress_bars.encoding; 46 44 47 45 if destination.exists() { 48 46 std::fs::remove_file(&destination)?; ··· 60 58 "Selecting", 61 59 &format!( 62 60 "VGV encoder with HTML transcoding as {} ends with .vgv.html", 63 - ui::format_filepath(&destination), 61 + destination.pretty(), 64 62 ), 65 63 ); 66 64 ··· 77 75 "Selecting", 78 76 &format!( 79 77 "VGV encoder as {} ends with .vgv (use .vgv.html for HTML transcoding)", 80 - ui::format_filepath(&destination), 78 + destination.pretty(), 81 79 ), 82 80 ); 83 81 ··· 90 88 )?) 91 89 } 92 90 _ => { 93 - self.progress_bars 94 - .encoding 95 - .log("Selecting", &format!( 96 - "FFMpeg encoder, as {} doesn't end with .vgv or .vgv.html", 97 - ui::format_filepath(&destination), 98 - )); 91 + pb.log( 92 + "Selecting", 93 + &format!( 94 + "FFMpeg encoder as {} ends with {}", 95 + destination.pretty(), 96 + destination.full_extension() 97 + ), 98 + ); 99 + 99 100 self.initial_canvas.load_fonts()?; 100 101 Box::new(self.setup_ffmpeg_encoder(width, height, destination)?) 101 102 }
+11 -9
src/video/engine.rs
··· 1 1 use super::{Video, context::Context}; 2 - use crate::SVGRenderable; 3 2 use crate::rendering::svg; 4 - use crate::ui::{Log, format_duration, format_timestamp_range}; 3 + use crate::ui::{Log, Pretty}; 4 + use crate::{SVGRenderable, Timestamp}; 5 5 use anyhow::Result; 6 6 use measure_time::debug_time; 7 7 use std::sync::mpsc::SyncSender; ··· 25 25 pub fn engine_progression(&self) -> EngineProgression { 26 26 EngineProgression { 27 27 ms: self.ms, 28 - timestamp: self.timestamp(), 28 + timestamp: self.timestamp().pretty(), 29 29 scene_name: self.current_scene.clone(), 30 30 } 31 31 } ··· 89 89 90 90 pb.inc(1); 91 91 pb.set_message(match context.current_scene { 92 - Some(ref scene) => format!("{}: {}", context.timestamp(), scene), 93 - None => context.timestamp(), 92 + Some(ref scene) => format!("{}: {scene}", context.timestamp()), 93 + None => format!("{}", context.timestamp()), 94 94 }); 95 95 96 96 if context.marker().starts_with(':') { ··· 171 171 &format!( 172 172 "{} frames in {}", 173 173 context.rendered_frames, 174 - format_duration(pb.elapsed()) 174 + pb.elapsed().pretty() 175 175 ), 176 176 ); 177 177 self.progress.remove(&pb); ··· 218 218 output: SyncSender<EngineOutput>, 219 219 ) -> Result<usize> { 220 220 let actual_ms_range = self.constrained_ms_range(); 221 + 221 222 if actual_ms_range != self.total_ms_range() { 222 - self.progress_bars 223 - .rendering 224 - .log("Constrained", &format_timestamp_range(&actual_ms_range)); 223 + self.progress_bars.rendering.log( 224 + "Constrained", 225 + &Timestamp::from_ms_range(&actual_ms_range).pretty(), 226 + ); 225 227 } 226 228 227 229 self.render(output, |ctx| {
+11 -7
src/video/video.rs
··· 5 5 midi::MidiSynchronizer, 6 6 sync::{SyncData, Syncable}, 7 7 }, 8 - ui::{self, Log, display_counts, format_duration, format_filepath}, 8 + ui::{self, Log, Pretty}, 9 9 video::hooks::{AttachHooks, CommandAction, Hook}, 10 10 }; 11 11 use measure_time::debug_time; ··· 31 31 pub struct Timestamp(pub usize); 32 32 33 33 impl Timestamp { 34 + pub fn from_ms_range(range: &Range<usize>) -> Range<Self> { 35 + Self::from_ms(range.start)..Self::from_ms(range.end) 36 + } 37 + 34 38 pub fn ms(&self) -> usize { 35 39 self.0 36 40 } ··· 60 64 61 65 impl std::fmt::Display for Timestamp { 62 66 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 63 - write!(f, "{}", ui::format_timestamp(self.ms())) 67 + write!(f, "{}", self.pretty()) 64 68 } 65 69 } 66 70 ··· 153 157 if let Some(bpm) = syncdata.bpm { 154 158 pb.log( 155 159 "BPM", 156 - &format!("set to {bpm} from {}", format_filepath(&file_path)), 160 + &format!("set to {bpm} from {}", (&file_path).pretty()), 157 161 ); 158 162 } 159 163 ··· 161 165 "Loaded", 162 166 &format!( 163 167 "{things} from {path} in {elapsed}", 164 - path = format_filepath(&file_path), 165 - elapsed = format_duration(pb.elapsed()), 166 - things = display_counts(HashMap::from([ 168 + path = (&file_path).pretty(), 169 + elapsed = (pb.elapsed().pretty()), 170 + things = (HashMap::from([ 167 171 ("markers", syncdata.markers.len()), 168 172 ("stems", syncdata.stems.len()), 169 173 ( ··· 174 178 .map(|v| v.notes.len()) 175 179 .sum::<usize>() 176 180 ), 177 - ])), 181 + ])).pretty(), 178 182 ), 179 183 ); 180 184