203 lines
5.2 KiB
Rust
203 lines
5.2 KiB
Rust
use std::fmt;
|
|
use std::sync::Arc;
|
|
|
|
use rspotify::spotify::model::artist::{FullArtist, SimplifiedArtist};
|
|
|
|
use album::Album;
|
|
use library::Library;
|
|
use queue::Queue;
|
|
use spotify::Spotify;
|
|
use track::Track;
|
|
use traits::{IntoBoxedViewExt, ListItem, ViewExt};
|
|
use ui::artist::ArtistView;
|
|
|
|
#[derive(Clone, Deserialize, Serialize)]
|
|
pub struct Artist {
|
|
pub id: Option<String>,
|
|
pub name: String,
|
|
pub url: Option<String>,
|
|
pub albums: Option<Vec<Album>>,
|
|
pub tracks: Option<Vec<Track>>,
|
|
pub is_followed: bool,
|
|
}
|
|
|
|
impl Artist {
|
|
pub fn new(id: String, name: String) -> Self {
|
|
Self {
|
|
id: Some(id),
|
|
name,
|
|
url: None,
|
|
albums: None,
|
|
tracks: None,
|
|
is_followed: false,
|
|
}
|
|
}
|
|
|
|
pub fn load_albums(&mut self, spotify: Arc<Spotify>) {
|
|
if let Some(albums) = self.albums.as_mut() {
|
|
for album in albums {
|
|
album.load_tracks(spotify.clone());
|
|
}
|
|
return;
|
|
}
|
|
|
|
if let Some(ref artist_id) = self.id {
|
|
if let Some(sas) = spotify.artist_albums(artist_id, 50, 0) {
|
|
let mut albums: Vec<Album> = Vec::new();
|
|
|
|
for sa in sas.items {
|
|
if Some("appears_on".into()) == sa.album_group {
|
|
continue;
|
|
}
|
|
|
|
if let Some(album_id) = sa.id {
|
|
if let Some(fa) = spotify.full_album(&album_id).as_ref() {
|
|
albums.push(fa.into());
|
|
}
|
|
}
|
|
}
|
|
|
|
self.albums = Some(albums);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn tracks(&self) -> Option<Vec<&Track>> {
|
|
if let Some(tracks) = self.tracks.as_ref() {
|
|
Some(tracks.iter().collect())
|
|
} else if let Some(albums) = self.albums.as_ref() {
|
|
Some(
|
|
albums
|
|
.iter()
|
|
.map(|a| a.tracks.as_ref().unwrap())
|
|
.flatten()
|
|
.collect(),
|
|
)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<&SimplifiedArtist> for Artist {
|
|
fn from(sa: &SimplifiedArtist) -> Self {
|
|
Self {
|
|
id: sa.id.clone(),
|
|
name: sa.name.clone(),
|
|
url: sa.uri.clone(),
|
|
albums: None,
|
|
tracks: None,
|
|
is_followed: false,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<&FullArtist> for Artist {
|
|
fn from(fa: &FullArtist) -> Self {
|
|
Self {
|
|
id: Some(fa.id.clone()),
|
|
name: fa.name.clone(),
|
|
url: Some(fa.uri.clone()),
|
|
albums: None,
|
|
tracks: None,
|
|
is_followed: false,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for Artist {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "{}", self.name)
|
|
}
|
|
}
|
|
|
|
impl fmt::Debug for Artist {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "{} ({:?})", self.name, self.id)
|
|
}
|
|
}
|
|
|
|
impl ListItem for Artist {
|
|
fn is_playing(&self, queue: Arc<Queue>) -> bool {
|
|
if let Some(tracks) = self.tracks() {
|
|
let playing: Vec<String> = queue
|
|
.queue
|
|
.read()
|
|
.unwrap()
|
|
.iter()
|
|
.filter(|t| t.id.is_some())
|
|
.map(|t| t.id.clone().unwrap())
|
|
.collect();
|
|
let ids: Vec<String> = tracks
|
|
.iter()
|
|
.filter(|t| t.id.is_some())
|
|
.map(|t| t.id.clone().unwrap())
|
|
.collect();
|
|
!ids.is_empty() && playing == ids
|
|
} else {
|
|
false
|
|
}
|
|
}
|
|
|
|
fn display_left(&self) -> String {
|
|
format!("{}", self)
|
|
}
|
|
|
|
fn display_right(&self, library: Arc<Library>) -> String {
|
|
let followed = if library.is_followed_artist(self) {
|
|
if library.use_nerdfont {
|
|
"\u{f62b} "
|
|
} else {
|
|
"✓ "
|
|
}
|
|
} else {
|
|
""
|
|
};
|
|
|
|
let tracks = if let Some(tracks) = self.tracks.as_ref() {
|
|
format!("{:>3} saved tracks", tracks.len())
|
|
} else {
|
|
"".into()
|
|
};
|
|
|
|
format!("{}{}", followed, tracks)
|
|
}
|
|
|
|
fn play(&mut self, queue: Arc<Queue>) {
|
|
self.load_albums(queue.get_spotify());
|
|
|
|
if let Some(tracks) = self.tracks() {
|
|
let index = queue.append_next(tracks);
|
|
queue.play(index, true);
|
|
}
|
|
}
|
|
|
|
fn queue(&mut self, queue: Arc<Queue>) {
|
|
self.load_albums(queue.get_spotify());
|
|
|
|
if let Some(tracks) = self.tracks() {
|
|
for t in tracks {
|
|
queue.append(t);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn toggle_saved(&mut self, library: Arc<Library>) {
|
|
if library.is_followed_artist(self) {
|
|
library.unfollow_artist(self);
|
|
} else {
|
|
library.follow_artist(self);
|
|
}
|
|
}
|
|
|
|
fn open(&self, queue: Arc<Queue>, library: Arc<Library>) -> Option<Box<dyn ViewExt>> {
|
|
Some(ArtistView::new(queue, library, self).as_boxed_view_ext())
|
|
}
|
|
|
|
fn share_url(&self) -> Option<String> {
|
|
self.id
|
|
.clone()
|
|
.map(|id| format!("https://open.spotify.com/artist/{}", id))
|
|
}
|
|
}
|