Repository: aome510/spotify-player (language: rust)

Issue:
 Explicit Albums on Artists Page
Depending on the genre of music (like hip-hop), it's commonplace to release 2 versions of an album: an explicit version and an edited "radio" version. When using the Spotify desktop client, you'll see both albums under an Artist page and can pick the one you want. The Explicit songs are marked with an "E" icon.

With `spotify_player`, if I am viewing an Artist's page, I seem to only be shown the "radio" version. I noted I can do a **g**lobal **s**earch with the Album name to find both versions and play the explicit version there.

It would be convenient to access the explicit version from the Artists' Albums page too.


Discussion / hints:
@braheezy can you provide an example of such artist with both explicit/edited "radio" albums? This can be helpful to implement the feature
Yeah I think I got one here.

 Kendrick Lamar has the esteemed album "To Pimp A Butterfly". It's listed once here:
![Screenshot from 2023-01-18 12-10-57](https://user-images.githubusercontent.com/11700503/213284415-dbbab3fd-9125-4be1-a46b-3c597545b988.png)

About near the timestamp in the screenshot is where you can start to tell it's the clean version. 

---
Here's the result from the Global Search. One of those in the Albums view is the explicit version (maybe another feature? annotate the difference?).

![Screenshot from 2023-01-18 12-15-25](https://user-images.githubusercontent.com/11700503/213285443-5c2d146b-ad93-4675-8f0b-29cd88c85c3c.png)

Fix patch:
diff --git a/spotify_player/src/state/model.rs b/spotify_player/src/state/model.rs
index 2571480f..5a59a984 100644
--- a/spotify_player/src/state/model.rs
+++ b/spotify_player/src/state/model.rs
@@ -3,6 +3,7 @@ pub use rspotify::model::{AlbumId, ArtistId, Id, PlaylistId, TrackId, UserId};
 
 use crate::utils::{format_duration, map_join};
 use serde::Serialize;
+use std::borrow::Cow;
 
 #[derive(Serialize, Clone, Debug)]
 #[serde(untagged)]
@@ -118,6 +119,7 @@ pub struct Track {
     pub album: Option<Album>,
     #[serde(serialize_with = "serialize_duration")]
     pub duration: chrono::Duration,
+    pub explicit: bool,
     #[serde(skip)]
     pub added_at: u64,
 }
@@ -240,6 +242,15 @@ impl Track {
             .unwrap_or_default()
     }
 
+    /// gets the track's name, including an explicit label
+    pub fn display_name(&self) -> Cow<'_, str> {
+        if self.explicit {
+            Cow::Owned(format!("{} (E)", self.name))
+        } else {
+            Cow::Borrowed(self.name.as_str())
+        }
+    }
+
     /// tries to convert from a `rspotify_model::SimplifiedTrack` into `Track`
     pub fn try_from_simplified_track(track: rspotify_model::SimplifiedTrack) -> Option<Self> {
         if track.is_playable.unwrap_or(true) {
@@ -249,6 +260,7 @@ impl Track {
                 artists: from_simplified_artists_to_artists(track.artists),
                 album: None,
                 duration: track.duration,
+                explicit: track.explicit,
                 added_at: 0,
             })
         } else {
@@ -265,6 +277,7 @@ impl Track {
                 artists: from_simplified_artists_to_artists(track.artists),
                 album: Album::try_from_simplified_album(track.album),
                 duration: track.duration,
+                explicit: track.explicit,
                 added_at: 0,
             })
         } else {
@@ -278,7 +291,7 @@ impl std::fmt::Display for Track {
         write!(
             f,
             "{} • {} ▎ {}",
-            self.name,
+            self.display_name(),
             self.artists_info(),
             self.album_info(),
         )
diff --git a/spotify_player/src/ui/page.rs b/spotify_player/src/ui/page.rs
index 435a7a19..4fc2c80e 100644
--- a/spotify_player/src/ui/page.rs
+++ b/spotify_player/src/ui/page.rs
@@ -86,7 +86,12 @@ pub fn render_search_page(
             .map(|s| {
                 s.tracks
                     .iter()
-                    .map(|a| (format!("{} • {}", a.name, a.artists_info()), false))
+                    .map(|a| {
+                        (
+                            format!("{} • {}", a.display_name(), a.artists_info()),
+                            false,
+                        )
+                    })
                     .collect::<Vec<_>>()
             })
             .unwrap_or_default();
@@ -714,7 +719,7 @@ pub fn render_track_table_window(
                     ""
                 }),
                 Cell::from(id),
-                Cell::from(t.name.clone()),
+                Cell::from(t.display_name()),
                 Cell::from(t.artists_info()),
                 Cell::from(t.album_info()),
                 Cell::from(crate::utils::format_duration(&t.duration)),
diff --git a/spotify_player/src/ui/playback.rs b/spotify_player/src/ui/playback.rs
index 67173267..d1706383 100644
--- a/spotify_player/src/ui/playback.rs
+++ b/spotify_player/src/ui/playback.rs
@@ -184,7 +184,11 @@ fn render_playback_text(
                     } else {
                         &state.app_config.play_icon
                     },
-                    track.name,
+                    if track.explicit {
+                        format!("{} (E)", track.name)
+                    } else {
+                        track.name.clone()
+                    }
                 ),
                 ui.theme.playback_track(),
             ),


Test patch: