Skip to content

Commit

Permalink
fix playlist entry remove not working when playing from directory
Browse files Browse the repository at this point in the history
  • Loading branch information
kamiyaa committed Oct 25, 2024
1 parent d5efbb2 commit f437d19
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 60 deletions.
46 changes: 32 additions & 14 deletions src/bin/server/audio/symphonia/player/impl_audio_player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,18 @@ impl AudioPlayer for SymphoniaPlayer {
fn play_next(&mut self) -> DiziResult {
let playlist = self.playlist_context.current_playlist_mut();

let song_entry = playlist.next_song_peak().ok_or_else(|| {
DiziError::new(DiziErrorKind::ParseError, "Playlist error".to_string())
})?;
playlist.order_index = Some(song_entry.order_index);

playlist.load_current_entry_metadata()?;
// keep going through playlist until we find a song that can
// be parsed and played
loop {
let song_entry = playlist.next_song_peak().ok_or_else(|| {
DiziError::new(DiziErrorKind::ParseError, "Playlist error".to_string())
})?;
playlist.order_index = Some(song_entry.order_index);

if playlist.load_current_entry_metadata().is_ok() {
break;
};
}
if let Some(entry) = playlist.current_entry() {
if let DiziSongEntry::Loaded(audio_file) = entry.entry {
self.play(&audio_file)?;
Expand All @@ -121,12 +127,22 @@ impl AudioPlayer for SymphoniaPlayer {
fn play_previous(&mut self) -> DiziResult {
let playlist = self.playlist_context.current_playlist_mut();

let song_entry = playlist.previous_song_peak().ok_or_else(|| {
DiziError::new(DiziErrorKind::ParseError, "Playlist error".to_string())
})?;
playlist.order_index = Some(song_entry.order_index);

playlist.load_current_entry_metadata()?;
// keep going through playlist until we find a song that can
// be parsed and played
loop {
let song_entry = playlist.previous_song_peak().ok_or_else(|| {
DiziError::new(DiziErrorKind::ParseError, "Playlist error".to_string())
})?;
playlist.order_index = Some(song_entry.order_index);

if playlist.load_current_entry_metadata().is_ok() {
break;
};
tracing::debug!(
"Skipping '{}' because we failed to parse it",
song_entry.entry.file_name()
);
}
if let Some(entry) = playlist.current_entry() {
if let DiziSongEntry::Loaded(audio_file) = entry.entry {
self.play(&audio_file)?;
Expand Down Expand Up @@ -215,9 +231,11 @@ impl AudioPlayer for SymphoniaPlayer {
self.state.shuffle = shuffle;

if self.shuffle_enabled() {
self.playlist_context.current_playlist_mut().shuffle();
self.playlist_context.directory_playlist.shuffle();
self.playlist_context.file_playlist.shuffle();
} else {
self.playlist_context.current_playlist_mut().unshuffle();
self.playlist_context.directory_playlist.unshuffle();
self.playlist_context.file_playlist.unshuffle();
}
}

Expand Down
23 changes: 13 additions & 10 deletions src/bin/server/playlist/impl_playlist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,13 @@ impl DiziPlaylistTrait for DiziPlaylist {
}

fn current_entry(&self) -> Option<DiziPlaylistEntry> {
let playlist_index = self.order_index?;
let song_index = self.order[playlist_index];
let order_index = self.order_index?;
let playlist_index = self.order[order_index];

Some(DiziPlaylistEntry {
entry_index: song_index,
order_index: playlist_index,
entry: self.entry_ref(song_index).clone(),
entry_index: playlist_index,
order_index,
entry: self.entry_ref(playlist_index).clone(),
})
}

Expand Down Expand Up @@ -88,22 +88,25 @@ impl DiziPlaylistTrait for DiziPlaylist {
}

fn shuffle(&mut self) {
let mut new_shuffle_order: Vec<usize> = (0..self.len()).collect();

// the current song being played should be the
// first value of the random order
match self.current_entry() {
Some(entry) => {
new_shuffle_order.remove(entry.entry_index);
let entry_index = entry.entry_index;
let mut new_shuffle_order: Vec<usize> =
(0..self.len()).filter(|i| *i != entry_index).collect();
new_shuffle_order.shuffle(&mut thread_rng());
new_shuffle_order.insert(0, entry.entry_index);
new_shuffle_order.insert(0, entry_index);

self.order = new_shuffle_order;
self.order_index = Some(0);
}
None => {
let mut new_shuffle_order: Vec<usize> = (0..self.len()).collect();
new_shuffle_order.shuffle(&mut thread_rng());
self.order = new_shuffle_order;
}
}
self.order = new_shuffle_order;
}

fn unshuffle(&mut self) {
Expand Down
17 changes: 17 additions & 0 deletions src/bin/server/playlist/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,23 @@ impl DiziPlaylist {
}
Ok(())
}

pub fn push_entry(&mut self, entry: DiziSongEntry) {
self.contents.push(entry);
self.order.push(self.contents.len() - 1);
}

pub fn remove_entry(&mut self, index: usize) {
self.contents.remove(index);
let new_len = self.contents.len();
let new_order: Vec<usize> = self
.order
.iter()
.filter(|i| **i < new_len)
.map(|i| *i)
.collect();
self.order = new_order;
}
}

impl std::default::Default for DiziPlaylist {
Expand Down
12 changes: 7 additions & 5 deletions src/bin/server/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ pub fn setup_socket(config: &AppConfig) -> DiziResult<UnixListener> {

pub fn serve(config: AppConfig) -> DiziResult {
let events = Events::new();
let event_tx2 = events.server_event_sender().clone();

let player = SymphoniaPlayer::new(&config, event_tx2)?;
let player = {
let server_event_tx = events.server_event_sender().clone();
SymphoniaPlayer::new(&config, server_event_tx)?
};

let mut context = AppContext {
events,
Expand All @@ -35,10 +37,10 @@ pub fn serve(config: AppConfig) -> DiziResult {
};

let listener = setup_socket(context.config_ref())?;
// thread for listening to new client connections
{
// thread for listening to new client connections
let server_tx2 = context.events.server_event_sender().clone();
thread::spawn(|| listen_for_clients(listener, server_tx2));
let server_event_tx = context.events.server_event_sender().clone();
thread::spawn(|| listen_for_clients(listener, server_event_tx));
}

while context.quit == QuitType::DoNot {
Expand Down
41 changes: 16 additions & 25 deletions src/bin/server/server_commands/playlist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,15 @@ pub fn playlist_play(context: &mut AppContext, index: usize) -> DiziResult {
}

pub fn playlist_load(context: &mut AppContext, cwd: &Path, path: &Path) -> DiziResult {
let shuffle_enabled = context.player.shuffle_enabled();
if !context
.player
.playlist_context_mut()
.file_playlist
.is_empty()
{
if !context.player.playlist_context.file_playlist.is_empty() {
return Err(DiziError::new(
DiziErrorKind::InvalidParameters,
"playlist cannot be loaded because current playlist is not empty".to_string(),
));
}

let mut new_playlist = DiziPlaylist::from_file(cwd, path)?;
let shuffle_enabled = context.player.shuffle_enabled();
if shuffle_enabled {
new_playlist.shuffle();
}
Expand All @@ -45,41 +40,37 @@ pub fn playlist_clear(context: &mut AppContext) -> DiziResult {
}

pub fn playlist_append(context: &mut AppContext, path: &Path) -> DiziResult<Vec<DiziAudioFile>> {
let playlist = &mut context.player.playlist_context_mut().file_playlist;
if path.is_dir() {
let audio_files = recursively_find_songs(path);
for audio_file in audio_files.iter() {
let entry = DiziSongEntry::Loaded(audio_file.clone());
context
.player
.playlist_context_mut()
.file_playlist
.push(entry);
playlist.push_entry(entry);
}
Ok(audio_files)
} else if is_playable(path)? {
let file = DiziFile::new(path);
let audio_file = DiziAudioFile::try_from(file)?;
let entry = DiziSongEntry::Loaded(audio_file.clone());
context
.player
.playlist_context_mut()
.file_playlist
.push(entry);
playlist.push_entry(entry);
Ok(vec![audio_file])
} else {
Ok(vec![])
Err(DiziError::new(
DiziErrorKind::InvalidParameters,
"File not playable".to_string(),
))
}
}

pub fn playlist_remove(context: &mut AppContext, index: usize) -> DiziResult {
let len = context.player.playlist_context.current_playlist_ref().len();
if index <= len {
context
.player
.playlist_context_mut()
.file_playlist
.remove(index);
let playlist = &mut context.player.playlist_context_mut().file_playlist;
if index >= playlist.len() {
return Err(DiziError::new(
DiziErrorKind::InvalidParameters,
"Playlist index out of range".to_string(),
));
}
playlist.remove_entry(index);
Ok(())
}

Expand Down
18 changes: 12 additions & 6 deletions src/bin/server/util/mimetype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,25 @@ pub fn get_mimetype(p: &Path) -> io::Result<String> {
.arg("--mime-type")
.arg(p)
.output()?;
let stdout = std::str::from_utf8(&output.stdout).unwrap();

let stdout = std::str::from_utf8(&output.stdout).expect("Failed to read from stdout");
let mimetype = stdout.to_string();

tracing::debug!("{:?} mimetype: {}", p, mimetype);

Ok(mimetype)
}

pub fn is_playable(p: &Path) -> io::Result<bool> {
let mimetype = get_mimetype(p)?;

Ok(is_mimetype_audio(&mimetype) || is_mimetype_video(&mimetype))
let is_audio_mimetype = is_mimetype_audio(&mimetype) || is_mimetype_video(&mimetype);
if is_audio_mimetype {
return Ok(true);
}
match p.extension() {
None => Ok(false),
Some(s) => match s.to_string_lossy().as_ref() {
"aac" | "flac" | "mp3" | "mp4" | "m4a" | "ogg" | "opus" | "wav" | "webm" => Ok(true),
_ => Ok(false),
},
}
}

pub fn is_mimetype_audio(s: &str) -> bool {
Expand Down
6 changes: 6 additions & 0 deletions src/playlist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ impl FilePlaylist {

pub fn remove_song(&mut self, index: usize) -> DiziSongEntry {
let song = self.list_mut().remove(index);

if let Some(playing_index) = self.playing_index {
if playing_index == index {
self.set_playing_index(None);
}
}
if self.list_ref().is_empty() {
self.set_cursor_index(None);
} else {
Expand Down

0 comments on commit f437d19

Please sign in to comment.