diff --git a/CHANGELOG.md b/CHANGELOG.md index 70001eb..02365e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## bliss 0.4.2 +* Add a binary example to easily make playlists. + ## bliss 0.4.1 * Add a function to make album playlists. diff --git a/Cargo.lock b/Cargo.lock index d6c1560..eace266 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,6 +26,15 @@ dependencies = [ "memchr 2.4.1", ] +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "anyhow" version = "1.0.45" @@ -77,10 +86,11 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bliss-audio" -version = "0.4.1" +version = "0.4.2" dependencies = [ "anyhow", "bliss-audio-aubio-rs", + "clap", "crossbeam", "env_logger", "ffmpeg-next", @@ -236,6 +246,21 @@ dependencies = [ "libloading", ] +[[package]] +name = "clap" +version = "2.33.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + [[package]] name = "crc32fast" version = "1.2.1" @@ -1111,6 +1136,12 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3ff2f71c82567c565ba4b3009a9350a96a7269eaa4001ebedae926230bc2254" +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + [[package]] name = "strum" version = "0.21.0" @@ -1149,6 +1180,15 @@ 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.29" @@ -1235,6 +1275,12 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + [[package]] name = "unicode-xid" version = "0.2.2" @@ -1253,6 +1299,12 @@ 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.3" diff --git a/Cargo.toml b/Cargo.toml index 2024ea4..fa3c5bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bliss-audio" -version = "0.4.1" +version = "0.4.2" authors = ["Polochon-street "] edition = "2018" license = "GPL-3.0-only" @@ -50,3 +50,4 @@ mime_guess = "2.0.3" glob = "0.3.0" anyhow = "1.0.45" serde_json = "1.0.59" +clap = "2.33.3" diff --git a/README.md b/README.md index e4587b5..b3b8a95 100644 --- a/README.md +++ b/README.md @@ -23,10 +23,25 @@ different, more accurate values, based on [actual literature](https://lelele.io/thesis.pdf). It is also faster. ## Examples -For simple analysis / distance computing, a look at `examples/distance.rs` and +For simple analysis / distance computing, take a look at `examples/distance.rs` and `examples/analyse.rs`. -Ready to use examples: +If you simply want to try out making playlists from a folder containing songs, +[this example](https://github.com/Polochon-street/bliss-rs/blob/master/examples/playlist.rs) +contains all you need. Usage: + + cargo run --features=serde --release --example=playlist /path/to/folder /path/to/first/song + +Don't forget the `--release` flag! + +By default, it outputs the playlist to stdout, but you can use `-o ` +to output it to a specific path. + +To avoid having to analyze the entire folder +several times, it also stores the analysis in `/tmp/analysis.json`. You can customize +this behavior by using `-a ` to store this file in a specific place. + +Ready to use code examples: ### Compute the distance between two songs ``` @@ -72,7 +87,7 @@ fn main() -> Result<(), BlissError> { Instead of reinventing ways to fetch a user library, play songs, etc, and embed that into bliss, it is easier to look at the -[Library](https://github.com/Polochon-street/bliss-rs/blob/master/src/library.rs#L12) +[Library](https://docs.rs/bliss-audio/0.4.1/bliss_audio/library/trait.Library.html) trait. By implementing a few functions to get songs from a media library, and store diff --git a/examples/playlist.rs b/examples/playlist.rs index c8c24b5..99e009f 100644 --- a/examples/playlist.rs +++ b/examples/playlist.rs @@ -1,6 +1,7 @@ use anyhow::Result; use bliss_audio::distance::{closest_to_first_song, dedup_playlist, euclidean_distance}; use bliss_audio::{library::analyze_paths_streaming, Song}; +use clap::{App, Arg}; use glob::glob; use mime_guess; use serde_json; @@ -11,28 +12,34 @@ use std::path::{Path, PathBuf}; /* Analyzes a folder recursively, and make a playlist out of the file * provided by the user. */ -// TODO still: -// * Mention it in the README -// * Make the output file configurable -// * Allow to choose between outputing to stdout and a file +// How to use: ./playlist [-o file.m3u] [-a analysis.json] #[cfg(feature = "serde")] fn main() -> Result<()> { - let args: Vec = env::args().skip(1).collect(); - if args.len() > 3 || args.len() < 2 { - println!("Usage: ./playlist "); - println!( - "Creates a playlist of all audio files in a folder (recursively), \ - starting with , and outputs the result both to stdout and \ - a `playlist.m3u` file in the current folder." - ); - return Ok(()); - } - let folder = &args[0]; - let file = fs::canonicalize(&args[1])?; + let matches = App::new("playlist") + .version(env!("CARGO_PKG_VERSION")) + .author("Polochon_street") + .about("Analyze a folder and make a playlist from a target song") + .arg(Arg::with_name("output-playlist").short("o").long("output-playlist") + .value_name("PLAYLIST.M3U") + .help("Outputs the playlist to a file.") + .takes_value(true)) + .arg(Arg::with_name("analysis-file").short("a").long("analysis-file") + .value_name("ANALYSIS.JSON") + .help("Use the songs that have been analyzed in , and appends newly analyzed songs to it. Defaults to /tmp/analysis.json.") + .takes_value(true)) + .arg(Arg::with_name("FOLDER").help("Folders containing some songs.").required(true)) + .arg(Arg::with_name("FIRST-SONG").help("Song to start from (can be outside of FOLDER).").required(true)) + .get_matches(); + + let folder = matches.value_of("FOLDER").unwrap(); + let file = fs::canonicalize(matches.value_of("FIRST-SONG").unwrap())?; let pattern = Path::new(folder).join("**").join("*"); let mut songs: Vec = Vec::new(); - let analysis_file = fs::File::open("./songs.json"); + let analysis_path = matches + .value_of("analysis-file") + .unwrap_or("/tmp/analysis.json"); + let analysis_file = fs::File::open(analysis_path); if let Ok(f) = analysis_file { let reader = BufReader::new(f); songs = serde_json::from_reader(reader)?; @@ -75,14 +82,18 @@ fn main() -> Result<()> { .collect(); closest_to_first_song(&first_song, &mut songs_to_chose_from, euclidean_distance); dedup_playlist(&mut songs_to_chose_from, None); - fs::write("./songs.json", serialized)?; + + fs::write(analysis_path, serialized)?; let playlist = songs_to_chose_from .iter() .map(|s| s.path.to_string_lossy().to_string()) .collect::>() .join("\n"); - println!("{}", playlist); - fs::write("./playlist.m3u", playlist)?; + if let Some(m) = matches.value_of("output-playlist") { + fs::write(m, playlist)?; + } else { + println!("{}", playlist); + } Ok(()) }