diff --git a/Cargo.lock b/Cargo.lock index 2305cdb..e470061 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,12 +32,32 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + [[package]] name = "arrayvec" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.3.0" @@ -76,6 +96,24 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "bumpalo" version = "3.16.0" @@ -142,6 +180,21 @@ dependencies = [ "libloading", ] +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "ansi_term", + "atty", + "bitflags 1.3.2", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + [[package]] name = "claxon" version = "0.4.3" @@ -207,12 +260,50 @@ dependencies = [ "windows", ] +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "dasp_sample" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f" +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", +] + [[package]] name = "either" version = "1.13.0" @@ -228,6 +319,19 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -240,24 +344,97 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af9673d8203fcb076b19dfd17e38b3d4ae9f44959416ea532ce72415a6020365" +[[package]] +name = "ffmpeg-next" +version = "7.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19a340e3d664ad5f530147cd6d4a86ece739a829fe2d81c369389ef903bd96f6" +dependencies = [ + "bitflags 2.6.0", + "ffmpeg-sys-next", + "libc", +] + +[[package]] +name = "ffmpeg-sys-next" +version = "7.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db1b7546e70609ead8c06b2b4c618a1ba352364675f81608f431dd4f321fe3f1" +dependencies = [ + "bindgen", + "cc", + "libc", + "num_cpus", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "glob" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "handlebars" +version = "3.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4498fc115fa7d34de968184e473529abb40eeb6be8bc5f7faba3d08c316cb3e3" +dependencies = [ + "log", + "pest", + "pest_derive", + "quick-error 2.0.1", + "serde", + "serde_json", +] + [[package]] name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + [[package]] name = "hound" version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62adaabb884c94955b19907d60019f4e145d091c75345379e70d1ee696f7854f" +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error 1.2.3", +] + [[package]] name = "indexmap" version = "2.3.0" @@ -277,6 +454,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + [[package]] name = "jni" version = "0.21.1" @@ -377,6 +560,26 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "metadata" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be565ed434922cb09ce7228a971495fa636842f042cb76f851f5e3a2a339ccc0" +dependencies = [ + "clap", + "digest 0.9.0", + "env_logger", + "ffmpeg-next", + "handlebars", + "lazy_static", + "libc", + "log", + "regex", + "serde", + "serde_derive", + "sha2 0.9.9", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -442,6 +645,16 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.9", + "libc", +] + [[package]] name = "num_enum" version = "0.7.3" @@ -501,6 +714,57 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "pest" +version = "2.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a548d2beca6773b1c244554d36fcf8548a8a58e74156968211567250e48e49a" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c93a82e8d145725dcbaf44e5ea887c8a869efdcc28706df2d08c69e17077183" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a941429fea7e08bedec25e4f6785b6ffaacc6b755da98df5ef3e7dcf4a124c4f" +dependencies = [ + "once_cell", + "pest", + "sha2 0.10.8", +] + [[package]] name = "pkg-config" version = "0.3.30" @@ -525,6 +789,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + [[package]] name = "quote" version = "1.0.36" @@ -583,6 +859,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + [[package]] name = "same-file" version = "1.0.6" @@ -592,16 +874,80 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "serde" +version = "1.0.206" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b3e4cd94123dd520a128bcd11e34d9e9e423e7e3e50425cb1b4b1e3549d0284" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.206" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabfb6138d2383ea8208cf98ccf69cdfb1aff4088460681d84189aa259762f97" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.122" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + [[package]] name = "sweetmusic" version = "0.1.0" dependencies = [ + "metadata", + "regex", "rodio", ] @@ -761,6 +1107,24 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + [[package]] name = "thiserror" version = "1.0.63" @@ -813,12 +1177,48 @@ dependencies = [ "winnow", ] +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-width" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + [[package]] name = "walkdir" version = "2.5.0" @@ -905,6 +1305,22 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + [[package]] name = "winapi-util" version = "0.1.9" @@ -914,6 +1330,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows" version = "0.54.0" diff --git a/Cargo.toml b/Cargo.toml index 6439390..ab0cb22 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,4 +4,6 @@ version = "0.1.0" edition = "2021" [dependencies] +metadata = "0.1.9" +regex = "1.10.6" rodio = { version = "0.19.0", features = ["symphonia-all"] } diff --git a/src/audioplayer.rs b/src/audioplayer.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/main.rs b/src/main.rs index 63d7526..ba1be04 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,45 +1,10 @@ -use std::fs::File; -use std::io::BufReader; -use std::path::{Path, PathBuf}; -use std::time::Duration; -use rodio::{Decoder, OutputStream, Sink, Source}; +pub mod songmeta; +use crate::songmeta::songmeta::*; -#[derive(Debug, Clone)] -struct SongMeta { - title: String, - artist: String, - album: String, - duration: Duration, - cover_path: Path, - path: Path, -} - -impl SongMeta { - fn new(filepath: Path) -> Self; -} - -#[derive(Debug, Clone)] -struct AudioPlayer { - sink: Sink, - playlist: Vec, -} - -#[derive(Debug, Clone)] -enum PlayerError { - IndexNotFound, - SomethingElse, -} - - -impl AudioPlayer { - fn new() -> Self; - fn from_playlist(playlist: Vec) -> Self; - fn add_playlist(&mut self, playlist: Vec); - fn skip_forward(&mut self); - fn skip_backwards(&mut self); - fn pause(&mut self); - fn play(&mut self); - fn set_vol(&mut self, vol: f32); - fn goto(&mut self; index: usize) -> Result<(), PlayerError>; -} +fn main() { + let mysong = SongMeta::frompath(&String::from("/home/justine/NAS/Musique/A_classer/Bleach/12 Big Cheese.mp3")); + dbg!(mysong); + let mysong2 = SongMeta::frompath(&String::from("/home/justine/NAS/Musique/Folk/Galaverna - Dodsdans/Galaverna - Dodsdans - 07 Smell of ember.flac")); + dbg!(mysong2); +} \ No newline at end of file diff --git a/src/playlist.rs b/src/playlist.rs new file mode 100644 index 0000000..4ca3e3b --- /dev/null +++ b/src/playlist.rs @@ -0,0 +1,31 @@ +pub mod songmeta; +use crate::songmeta::songmeta::*; + +///Stores a list of SongMetas +#[derive(Debug, Clone)] +struct Playlist { + songs: Vec, +} + +#[derive(Debug, Clone)] +enum PlaylistError { + IndexNotFound, + SomethingElse, +} + +impl Playlist { + ///Returns a new empty playlist. + fn new() -> Self { + Self { + songs: vec![], + } + } + + ///Returns a playlist from a file containing a list of audiofile paths. + fn from_file(path: &Path) -> Self; + + ///Removes a song at index (if possible) + fn pop() -> Result<(), PlayListError>; + + +} \ No newline at end of file diff --git a/src/proto.rs b/src/proto.rs new file mode 100644 index 0000000..c5bba47 --- /dev/null +++ b/src/proto.rs @@ -0,0 +1,97 @@ +use std::fs::File; +use std::io::BufReader; +use std::path::{Path, PathBuf}; +use std::time::Duration; +use rodio::{Decoder, OutputStream, Sink, Source}; + + +//-----------------------------------------Structs + + +///Stores a list of SongMetas +#[derive(Debug, Clone)] +struct Playlist { + songs: Vec, +} + +struct AudioPlayer { + sink: Sink, + playlist: Vec, +} + + +//-----------------------------------Errors +#[derive(Debug, Clone)] +enum PlayerError { + IndexNotFound, + SomethingElse, +} + + +#[derive(Debug, Clone)] +enum PlaylistError { + IndexNotFound, + SomethingElse, +} + + +//-------------------------------------Impls + + +impl Playlist { + ///Returns a new empty playlist. + fn new() -> Self { + Self { + songs: vec![], + } + } + + ///Returns a playlist from a file containing a list of audiofile paths. + fn from_file(path: &Path) -> Self; + + ///Removes a song at index (if possible) + fn pop() -> Result<(), PlayListError>; + + +} + +impl AudioPlayer { + + ///Returns a new empty player. + fn new() -> Self { + let (_stream, stream_handle) = OutputStream::try_default().unwrap(); + let sink = Sink::try_new(&stream_handle).unwrap(); + let playlist = vec![]; + + Self { + sink: sink, + playlist: playlist, + } + } + + ///Creates a new player from an existing playlist. + ///Does not consume the playlist. + fn from_playlist(playlist: &Playlist) -> Self { + let (_stream, stream_handle) = OutputStream::try_default().unwrap(); + let sink = Sink::try_new(&stream_handle).unwrap(); + + Self { + sink: sink, + playlist: playlist.clone(), + } + } + + + ///Appends a playlist to the current one, consuming it. + fn add_playlist(&mut self, playlist: Vec) { + self.playlist.append(&mut playlist); + } + + fn skip_forward(&mut self); + fn skip_backwards(&mut self); + fn pause(&mut self); + fn play(&mut self); + fn set_vol(&mut self, vol: f32); + fn goto(&mut self, index: usize) -> Result<(), PlayerError>; +} + diff --git a/src/songmeta.rs b/src/songmeta.rs new file mode 100644 index 0000000..86a9e15 --- /dev/null +++ b/src/songmeta.rs @@ -0,0 +1,146 @@ +pub mod songmeta { + + use std::path::{PathBuf, Path}; + use std::error::Error; + use std::fmt; + use regex::Regex; + use std::ffi::OsStr; + use metadata::media_file::MediaFileMetadata; + use std::time::Duration; + + ///Stores metadata about a song. + #[derive(Debug, Clone)] + pub struct SongMeta { + pub title: String, + pub artist: String, + pub album: String, + pub track: usize, + pub duration: Duration, + pub cover_path: Option, + pub path: String, + } + + #[derive(Debug)] + pub enum SongError { + ///Given path is not existing or is not a media file. + InvalidPath, + ///Given path is not an audio file + NotAudio, + } + + impl fmt::Display for SongError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + SongError::InvalidPath => write!(f, "Path does not exist or is not a media"), + SongError::NotAudio => write!(f, "Path exists but is not an audio file"), + } + } + } + + impl Error for SongError {} + + + impl SongMeta { + + ///Returns a SongMeta from the path of an audio file. + ///Returns an error if need be. + ///Also looks for the path of the cover, which may be None. + pub fn frompath(path: &String) -> Result> { + let fpath = Path::new(path); + let md = match MediaFileMetadata::new(&fpath) { + Ok(v) => v, + Err(e) => { + return Err(Box::new(SongError::InvalidPath)); + }, + }; + + //cover + let cover_path = match Self::find_cover_path(path.clone()) { + Some(v) => Some(v), + None => None, + }; + + //duration + let length = md._duration.clone().unwrap_or(0.0) as u64; + let duration = Duration::from_secs(length); + + //title + let filename = fpath.file_name().unwrap_or(&OsStr::new("Unkown title")); + let filename = String::from(filename.to_str().unwrap_or("Unkown")); + let title = md.title.clone().unwrap_or(filename.clone()); + + //other + let mut artist = String::from("Artist unkown"); + let mut album = String::from("Album unkown"); + let mut trackorder: usize = 0; + let mut track_in_name: usize = 0; + + //Find track order in filename first + if let Some(nbr) = Self::find_nbr_in_filename(&filename) { + track_in_name = nbr; + } + + for i in md.filtered_tags { + if i.0.to_lowercase() == "artist" { + artist = i.1.clone(); + } + if i.0.to_lowercase() == "album" { + album = i.1.clone(); + } + if i.0.to_lowercase() == "track" { + trackorder = i.1.clone().parse().unwrap_or(track_in_name); + } + } + + let val = SongMeta { + title: title, + artist: artist, + album: album, + track: trackorder, + duration: duration, + path: path.clone(), + cover_path: cover_path, + }; + Ok(val) + } + + + ///Looks for a cover path (cover.jpg or cover.png) + fn find_cover_path(path: String) -> Option { + let possible_paths = vec!["cover.jpg", "cover.png"]; + let mut foundpath = String::new(); + let mut found = false; + let mut p = PathBuf::from(&path); + if !p.pop() { + return None; + } + + //Search... + for poss in possible_paths { + let mut test = p.clone(); + test.push(Path::new(poss)); + if test.exists() { + foundpath = test.to_string_lossy().into_owned().clone(); + found = true; + } + } + + if found { + return Some(foundpath); + } + return None; + } + + ///Tries to find a logical track number in the filename, + ///at the beginning of it. + fn find_nbr_in_filename(filename: &String) -> Option { + //"^[0-9]+" + let regex = Regex::new(r"(?^[0-9]+)").unwrap(); + let cap = regex.captures(filename.as_str()); + if let Some(found) = cap { + return Some(found["tracknbr"].to_string().parse().unwrap_or(0) as usize); + } + return None; + } + } +}