Files
ncspot/src/artist.rs

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))
}
}