1extern crate sfml;
2extern crate sfml_modstream;
3
4use sfml::audio::{SoundStatus, SoundStreamPlayer};
5use sfml_modstream::{Metadata, ModStream};
6use std::fmt;
7use std::io::Write;
8use std::path::Path;
9
10struct HrTime {
11 seconds: f64,
12}
13
14impl fmt::Display for HrTime {
15 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
16 write!(
17 f,
18 "{:02.0}:{:04.1}",
19 (self.seconds / 60.).floor(),
20 self.seconds % 60.
21 )
22 }
23}
24
25struct OptStrFmt<'a> {
26 str: &'a str,
27 prepend: &'static str,
28 append: &'static str,
29}
30
31impl<'a> OptStrFmt<'a> {
32 fn new(prepend: &'static str, str: &'a str, append: &'static str) -> Self {
33 Self {
34 str,
35 prepend,
36 append,
37 }
38 }
39}
40
41impl<'a> std::fmt::Display for OptStrFmt<'a> {
42 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
43 if !self.str.is_empty() {
44 write!(f, "{}{}{}", self.prepend, self.str, self.append)
45 } else {
46 Ok(())
47 }
48 }
49}
50
51fn play_song(path: &Path) {
52 let mut stream = ModStream::from_file(path).unwrap();
53 let duration = HrTime {
54 seconds: stream.get_duration_seconds(),
55 };
56 let filename = path.file_name().unwrap().to_string_lossy();
57 let title = stream.metadata(Metadata::Title).unwrap();
58 let artist = stream.metadata(Metadata::Artist).unwrap();
59 let date = stream.metadata(Metadata::Date).unwrap();
60 let message = stream.metadata(Metadata::Message).unwrap();
61 let tracker = stream.metadata(Metadata::Tracker).unwrap();
62 let made_in_string = match (tracker.as_str().is_empty(), date.as_str().is_empty()) {
63 (true, true) => String::new(),
64 (false, true) => format!("Made in {}\n", tracker),
65 (true, false) => format!("Made in {}\n", date),
66 (false, false) => format!("Made in {} on {}\n", tracker, date),
67 };
68 println!(
69 "Playing {} {}[{}]\n\
70 {}\
71 {}",
72 title,
73 OptStrFmt::new(" by ", artist.as_str(), " "),
74 filename,
75 made_in_string,
76 message
77 );
78 let mut player = SoundStreamPlayer::new(&mut stream);
79 player.play();
80 while player.status() == SoundStatus::PLAYING {
81 let offset = HrTime {
82 seconds: f64::from(player.playing_offset().as_seconds()),
83 };
84 print!("{}/{}\r", offset, duration);
85 let _ = std::io::stdout().flush();
86 std::thread::sleep(std::time::Duration::from_millis(100));
87 }
88 println!()
90}
91
92fn main() {
93 let args = std::env::args_os().skip(1);
94
95 if args.len() == 0 {
96 println!("You might want to supply some song paths as arguments. Just saying.");
97 }
98
99 for arg in args {
100 play_song(arg.as_ref());
101 }
102}