Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
nick42d committed Aug 25, 2024
1 parent 2a0e139 commit e1ec143
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 10 deletions.
13 changes: 11 additions & 2 deletions youtui/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,14 @@ pub enum AppCallback {
GetProgress(ListSongID),
Quit,
ChangeContext(WindowContext),
// Perhaps shiould not be here.
IncreaseVolume(i8),
SearchArtist(String),
GetSearchSuggestions(String),
GetArtistSongs(ChannelID<'static>),
AddSongsToPlaylist(Vec<ListSong>),
AddSongsToPlaylistAndPlay(Vec<ListSong>),
PlaySong(Arc<InMemSong>, ListSongID),
QueueSong(Arc<InMemSong>, ListSongID),
AutoplaySong(Arc<InMemSong>, ListSongID),
PausePlay(ListSongID),
Stop(ListSongID),
Expand Down Expand Up @@ -208,7 +208,16 @@ impl Youtui {
.send_spawn_request(AppRequest::PlaySong(song, id))
.await;
}

AppCallback::QueueSong(song, id) => {
self.task_manager
.send_spawn_request(AppRequest::QueueSong(song, id))
.await;
}
AppCallback::AutoplaySong(song, id) => {
self.task_manager
.send_spawn_request(AppRequest::AutoplaySong(song, id))
.await;
}
AppCallback::PausePlay(id) => {
self.task_manager
.send_spawn_request(AppRequest::PausePlay(id))
Expand Down
19 changes: 17 additions & 2 deletions youtui/src/app/server/player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ use crate::core::oneshot_send_or_error;
use crate::core::send_or_error;
use crate::Result;
use rodio::decoder::DecoderError;
use rodio::source::PeriodicAccess;
use rodio::source::TrackPosition;
use rodio::Decoder;
use rodio::Source;
use std::io::Cursor;
use std::sync::Arc;
use std::time::Duration;
use tokio::sync::mpsc;
Expand All @@ -22,6 +26,7 @@ use tracing::info;
use tracing::warn;

const PLAYER_MSG_QUEUE_SIZE: usize = 256;
const PROGRESS_UPDATE_DELAY: Duration = Duration::from_millis(100);

#[derive(Debug)]
pub struct SongTypeNew {
Expand Down Expand Up @@ -292,6 +297,7 @@ fn spawn_rodio_thread(mut msg_rx: mpsc::Receiver<RodioMessage>) {
}
RodioMessage::QueueSong(song_pointer, song_id, tx, done_tx) => {
// DUPLICATE FROM PLAYSONG
// TEST CODE
let source = match try_decode(song_pointer, song_id, done_tx) {
Ok(source) => source,
Err(e) => {
Expand Down Expand Up @@ -423,16 +429,25 @@ fn spawn_rodio_thread(mut msg_rx: mpsc::Receiver<RodioMessage>) {
fn try_decode(
song: Arc<InMemSong>,
song_id: ListSongID,
progress_stream_tx: mpsc::Sender<Duration>,
done_tx: RodioOneshot<()>,
) -> std::result::Result<rodio::Decoder<std::io::Cursor<DroppableSong>>, DecoderError> {
) -> std::result::Result<
TrackPosition<PeriodicAccess<Decoder<Cursor<DroppableSong>>>, impl FnMut(Source)>,
DecoderError,
> {
// DUPLICATE FROM PLAYSONG
let sp = DroppableSong {
song,
song_id,
dropped_channel: Some(done_tx),
};
let cur = std::io::Cursor::new(sp);
rodio::Decoder::new(cur)
rodio::Decoder::new(cur).map(move |s| {
s.track_position()
.periodic_access(PROGRESS_UPDATE_DELAY, move |s| {
progress_stream_tx.clone().blocking_send(s.get_pos());
})
})
}

async fn autoplay_song(
Expand Down
4 changes: 3 additions & 1 deletion youtui/src/app/taskmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ pub enum AppRequest {
Download(VideoID<'static>, ListSongID),
IncreaseVolume(i8),
PlaySong(Arc<InMemSong>, ListSongID),
AutoplaySong(Arc<InMemSong>, ListSongID),
Queueong(Arc<InMemSong>, ListSongID),
GetPlayProgress(ListSongID),
Stop(ListSongID),
PausePlay(ListSongID),
Expand Down Expand Up @@ -239,7 +241,7 @@ impl TaskManager {
match msg {
downloader::Response::DownloadProgressUpdate(update_type, song_id) => {
ui_state
.handle_set_song_download_progress(update_type, song_id)
.handle_song_download_progress_update(update_type, song_id)
.await;
}
}
Expand Down
4 changes: 2 additions & 2 deletions youtui/src/app/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,13 +365,13 @@ impl YoutuiWindow {
pub fn handle_set_song_play_progress(&mut self, d: Duration, id: ListSongID) {
self.playlist.handle_set_song_play_progress(d, id);
}
pub async fn handle_set_song_download_progress(
pub async fn handle_song_download_progress_update(
&mut self,
update: DownloadProgressUpdateType,
playlist_id: ListSongID,
) {
self.playlist
.handle_song_progress_update(update, playlist_id)
.handle_song_download_progress_update(update, playlist_id)
.await
}
pub async fn handle_replace_search_suggestions(
Expand Down
42 changes: 39 additions & 3 deletions youtui/src/app/ui/playlist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ use tracing::{error, info, warn};

const SONGS_AHEAD_TO_BUFFER: usize = 3;
const SONGS_BEHIND_TO_SAVE: usize = 1;
// How soon to trigger gapless playback
const GAPLESS_PLAYBACK_THRESHOLD: Duration = Duration::from_secs(1);

pub struct Playlist {
pub list: AlbumSongsList,
Expand Down Expand Up @@ -406,7 +408,7 @@ impl Playlist {
.and_then(|i| self.get_id_from_index(i));
match next_song_id {
Some(id) => {
self.play_song_id(id).await;
self.autoplay_song_id(id).await;
}
None => {
info!("No next song - resetting play status");
Expand Down Expand Up @@ -464,6 +466,15 @@ impl Playlist {
PlayState::NotPlaying | PlayState::Stopped => None,
}
}
pub fn get_cur_playing_song(&self) -> Option<&ListSong> {
self.get_cur_playing_id()
.and_then(|id| self.get_song_from_id(id))
}
pub fn get_next_song(&self) -> Option<&ListSong> {
self.get_cur_playing_id()
.and_then(|id| self.get_index_from_id(id))
.and_then(|idx| self.list.get_list_iter().nth(idx + 1))
}
pub fn get_index_from_id(&self, id: ListSongID) -> Option<usize> {
self.list.get_list_iter().position(|s| s.id == id)
}
Expand Down Expand Up @@ -572,7 +583,7 @@ impl Playlist {
// Server handlers
impl Playlist {
/// Handle song progress update from server.
pub async fn handle_song_progress_update(
pub async fn handle_song_download_progress_update(
&mut self,
update: DownloadProgressUpdateType,
id: ListSongID,
Expand Down Expand Up @@ -635,6 +646,31 @@ impl Playlist {
return;
}
self.cur_played_dur = Some(d);
// If less than the gapless playback threshold remaining, queue up the next
// song, if it's downloaded, and hasn't already been queued.
if let Some(duration_dif) = {
let cur_dur = self
.get_cur_playing_song()
.and_then(|song| song.actual_duration);
self.cur_played_dur
.as_ref()
.zip(cur_dur)
.map(|(d1, d2)| d2.saturating_sub(*d1))
} {
if duration_dif
.saturating_sub(GAPLESS_PLAYBACK_THRESHOLD)
.is_zero()
&& !matches!(self.queue_status, QueueState::Queued(_))
{
if let Some(next_song) = self.get_next_song() {
if let DownloadStatus::Downloaded(song) = &next_song.download_status {
self.ui_tx
.send(AppCallback::QueueSong(song.clone(), next_song.id));
self.queue_status = QueueState::Queued(next_song.id)
}
}
}
}
}
/// Handle set to paused message from server
pub async fn handle_set_to_paused(&mut self, s_id: ListSongID) {
Expand All @@ -649,7 +685,7 @@ impl Playlist {
if !self.check_id_is_cur(id) {
return;
}
self.play_next_or_set_stopped(id).await;
self.autoplay_next_or_stop(id).await;
}
/// Handle queued message from server
pub fn handle_queued(&mut self, duration: Option<Duration>, id: ListSongID) {
Expand Down

0 comments on commit e1ec143

Please sign in to comment.