podcast support (#203)
* implement search for shows/podcasts * create Playable supertype for queue to contain tracks and episodes * wip: implement playback of episodes * load spotify id from uri instead of raw id to fix podcast playback * show duration for podcast episodes * implement generic status bar for playables (tracks and episodes) omit saved indicator for now as the library does not yet support podcasts * instead of only the last 50 fetch all episodes of a show * refactor: extract Playable code to separate file * implement playback/queuing of shows + sharing url * implement podcast library * migrate mpris code to Playable supertype
This commit is contained in:
committed by
GitHub
parent
8bf06147e2
commit
1b1d392ab8
@@ -13,7 +13,9 @@ use crate::album::Album;
|
||||
use crate::artist::Artist;
|
||||
use crate::config;
|
||||
use crate::events::EventManager;
|
||||
use crate::playable::Playable;
|
||||
use crate::playlist::Playlist;
|
||||
use crate::show::Show;
|
||||
use crate::spotify::Spotify;
|
||||
use crate::track::Track;
|
||||
|
||||
@@ -28,6 +30,7 @@ pub struct Library {
|
||||
pub albums: Arc<RwLock<Vec<Album>>>,
|
||||
pub artists: Arc<RwLock<Vec<Artist>>>,
|
||||
pub playlists: Arc<RwLock<Vec<Playlist>>>,
|
||||
pub shows: Arc<RwLock<Vec<Show>>>,
|
||||
pub is_done: Arc<RwLock<bool>>,
|
||||
user_id: Option<String>,
|
||||
ev: EventManager,
|
||||
@@ -44,6 +47,7 @@ impl Library {
|
||||
albums: Arc::new(RwLock::new(Vec::new())),
|
||||
artists: Arc::new(RwLock::new(Vec::new())),
|
||||
playlists: Arc::new(RwLock::new(Vec::new())),
|
||||
shows: Arc::new(RwLock::new(Vec::new())),
|
||||
is_done: Arc::new(RwLock::new(false)),
|
||||
user_id,
|
||||
ev: ev.clone(),
|
||||
@@ -140,15 +144,15 @@ impl Library {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn overwrite_playlist(&self, id: &str, tracks: &[Track]) {
|
||||
debug!("saving {} tracks to {}", tracks.len(), id);
|
||||
pub fn overwrite_playlist(&self, id: &str, tracks: &[Playable]) {
|
||||
debug!("saving {} tracks to list {}", tracks.len(), id);
|
||||
self.spotify.overwrite_playlist(id, &tracks);
|
||||
|
||||
self.fetch_playlists();
|
||||
self.save_cache(config::cache_path(CACHE_PLAYLISTS), self.playlists.clone());
|
||||
}
|
||||
|
||||
pub fn save_playlist(&self, name: &str, tracks: &[Track]) {
|
||||
pub fn save_playlist(&self, name: &str, tracks: &[Playable]) {
|
||||
debug!("saving {} tracks to new list {}", tracks.len(), name);
|
||||
match self.spotify.create_playlist(name, None, None) {
|
||||
Some(id) => self.overwrite_playlist(&id, &tracks),
|
||||
@@ -202,6 +206,13 @@ impl Library {
|
||||
})
|
||||
};
|
||||
|
||||
let t_shows = {
|
||||
let library = library.clone();
|
||||
thread::spawn(move || {
|
||||
library.fetch_shows();
|
||||
})
|
||||
};
|
||||
|
||||
t_tracks.join().unwrap();
|
||||
t_artists.join().unwrap();
|
||||
|
||||
@@ -210,6 +221,7 @@ impl Library {
|
||||
|
||||
t_albums.join().unwrap();
|
||||
t_playlists.join().unwrap();
|
||||
t_shows.join().unwrap();
|
||||
|
||||
let mut is_done = library.is_done.write().unwrap();
|
||||
*is_done = true;
|
||||
@@ -218,6 +230,29 @@ impl Library {
|
||||
});
|
||||
}
|
||||
|
||||
fn fetch_shows(&self) {
|
||||
debug!("loading shows");
|
||||
|
||||
let mut saved_shows: Vec<Show> = Vec::new();
|
||||
let mut shows_result = self.spotify.get_saved_shows(0);
|
||||
|
||||
while let Some(shows) = shows_result.as_ref() {
|
||||
saved_shows.extend(shows.items.iter().map(|show| (&show.show).into()));
|
||||
|
||||
// load next batch if necessary
|
||||
shows_result = match shows.next {
|
||||
Some(_) => {
|
||||
debug!("requesting shows again..");
|
||||
self.spotify
|
||||
.get_saved_shows(shows.offset + shows.items.len() as u32)
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
*self.shows.write().unwrap() = saved_shows;
|
||||
}
|
||||
|
||||
fn fetch_playlists(&self) {
|
||||
debug!("loading playlists");
|
||||
let mut stale_lists = self.playlists.read().unwrap().clone();
|
||||
@@ -512,13 +547,13 @@ impl Library {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_saved_track(&self, track: &Track) -> bool {
|
||||
pub fn is_saved_track(&self, track: &Playable) -> bool {
|
||||
if !*self.is_done.read().unwrap() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let tracks = self.tracks.read().unwrap();
|
||||
tracks.iter().any(|t| t.id == track.id)
|
||||
tracks.iter().any(|t| t.id == track.id())
|
||||
}
|
||||
|
||||
pub fn save_tracks(&self, tracks: Vec<&Track>, api: bool) {
|
||||
@@ -773,6 +808,43 @@ impl Library {
|
||||
self.save_cache(config::cache_path(CACHE_PLAYLISTS), self.playlists.clone());
|
||||
}
|
||||
|
||||
pub fn is_saved_show(&self, show: &Show) -> bool {
|
||||
if !*self.is_done.read().unwrap() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let shows = self.shows.read().unwrap();
|
||||
shows.iter().any(|s| s.id == show.id)
|
||||
}
|
||||
|
||||
pub fn save_show(&self, show: &Show) {
|
||||
if !*self.is_done.read().unwrap() {
|
||||
return;
|
||||
}
|
||||
|
||||
if self.spotify.save_shows(vec![show.id.clone()]) {
|
||||
{
|
||||
let mut store = self.shows.write().unwrap();
|
||||
if !store.iter().any(|s| s.id == show.id) {
|
||||
store.insert(0, show.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unsave_show(&self, show: &Show) {
|
||||
if !*self.is_done.read().unwrap() {
|
||||
return;
|
||||
}
|
||||
|
||||
if self.spotify.unsave_shows(vec![show.id.clone()]) {
|
||||
{
|
||||
let mut store = self.shows.write().unwrap();
|
||||
*store = store.iter().filter(|s| s.id != show.id).cloned().collect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trigger_redraw(&self) {
|
||||
self.ev.trigger();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user