Skip to content

Commit

Permalink
Add a "playlist from playlist" option
Browse files Browse the repository at this point in the history
  • Loading branch information
Polochon-street committed Jun 13, 2024
1 parent 167fd24 commit c49a3e9
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 17 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Changelog

## blissify 0.3.12
* Make deduplicating songs the default, and add a --no-deduplication option
* Add a "playlist from playlist" feature (Thanks @SimonTeixidor!)
* Use window / offset to read the list of MPD files to avoid timeout errors.

## blissify 0.3.11
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ noisy_float = "0.2.0"
termion = "1.5.6"
serde = "1.0"
pretty_assertions = "1.2.1"
extended-isolation-forest = { version = "0.2.3", default-features = false }
93 changes: 76 additions & 17 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ use std::num::NonZeroUsize;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};

use extended_isolation_forest::ForestOptions;

use std::io;
use std::io::Write;
#[cfg(not(test))]
Expand Down Expand Up @@ -342,6 +344,43 @@ impl MPDLibrary {
Ok(())
}

fn queue_from_current_playlist<F>(
&self,
number_songs: usize,
distance: &dyn DistanceMetricBuilder,
mut sort_by: F,
dedup: bool,
) -> Result<()>
where
F: FnMut(&[LibrarySong<()>], &mut [LibrarySong<()>], &dyn DistanceMetricBuilder),
{
let mut mpd_conn = self.mpd_conn.lock().unwrap();
mpd_conn.random(false)?;
let mpd_songs = mpd_conn.queue()?;
let paths = mpd_songs
.iter()
.map(|s| {
self.mpd_to_bliss_path(s)
.map(|s| s.to_string_lossy().to_string())
})
.collect::<Result<Vec<String>, _>>()?;
let paths = paths.iter().map(|s| &**s).collect::<Vec<&str>>();

let playlist = self.library.playlist_from_custom(
&paths,
number_songs,
distance,
&mut sort_by,
dedup,
)?;

for song in &playlist[1..] {
let mpd_song = self.bliss_song_to_mpd(song)?;
mpd_conn.push(mpd_song)?;
}
Ok(())
}

fn queue_from_current_song_custom<F>(
&self,
number_songs: usize,
Expand Down Expand Up @@ -690,10 +729,11 @@ Useful to avoid a too heavy load on a machine.")
)
.takes_value(false)
)
.arg(Arg::with_name("dedup")
.long("deduplicate-songs")
.arg(Arg::with_name("no-dedup")
.long("no-deduplication")
.help(
"Deduplicate songs based both on the title / artist and their sheer proximity."
"Do not deduplicate songs based both on the title / artist and their\
sheer proximity."
)
.takes_value(false)
)
Expand All @@ -702,6 +742,13 @@ Useful to avoid a too heavy load on a machine.")
.help("Make a playlist of similar albums from the current album.")
.takes_value(false)
)
.arg(Arg::with_name("entire")
.long("from-entire-playlist")
.help("Make a playlist of songs similar to all the playlist's songs, \
instead of just the first one. Defaults to using the distance metric \
extended_isolation_forest, which give the best results.")
.takes_value(false)
)
)
.subcommand(
SubCommand::with_name("interactive-playlist")
Expand Down Expand Up @@ -787,33 +834,45 @@ Defaults to 3, cannot be more than 9."
if sub_m.is_present("album") {
library.queue_from_current_album(number_songs)?;
} else {
let distance_metric = if let Some(m) = sub_m.value_of("distance") {
// TODO let users customize options?
let forest_distance: &dyn DistanceMetricBuilder = &ForestOptions {
n_trees: 1000,
sample_size: 200,
max_tree_depth: None,
extension_level: 10,
};

let distance_metric: &dyn DistanceMetricBuilder = if let Some(m) =
sub_m.value_of("distance")
{
match m {
"euclidean" => euclidean_distance,
"cosine" => cosine_distance,
_ => bail!("Please choose a distance name, between 'euclidean' and 'cosine'."),
"euclidean" => &euclidean_distance,
"cosine" => &cosine_distance,
"extended_isolation_forest" => forest_distance,
_ => bail!("Please choose a distance name, between 'euclidean', 'cosine' and 'extended_isolation_forest'."),
}
} else {
euclidean_distance
&euclidean_distance
};

let sort = match sub_m.is_present("seed") {
let mut sort = match sub_m.is_present("seed") {
false => closest_to_songs,
true => song_to_song,
};
if sub_m.is_present("dedup") {
library.queue_from_current_song_custom(
let no_dedup = sub_m.is_present("no-dedup");
if sub_m.is_present("entire") {
library.queue_from_current_playlist(
number_songs,
&distance_metric,
sort,
true,
forest_distance,
&mut sort,
!no_dedup,
)?;
} else {
library.queue_from_current_song_custom(
number_songs,
&distance_metric,
sort,
false,
distance_metric,
&mut sort,
!no_dedup,
)?;
}
}
Expand Down

0 comments on commit c49a3e9

Please sign in to comment.