Skip to content

Commit

Permalink
Add track_format config option (#800)
Browse files Browse the repository at this point in the history
* Added track_name_first config option to allow choosing if artists' names should be shown before or after the track name.

* Added active_fields config option, which allows configuration of which columns are visible in Queue/Library view.
This also removes the need for a separate track_name_first and album_column option.

* Fixed README

* Made custom tracklist formatting more flexible.
Updated readme with new instructions.
Reformatted impl member order to match the definitions in traits.rs.

* Added track_name_first config option to allow choosing if artists' names should be shown before or after the track name.

* Added active_fields config option, which allows configuration of which columns are visible in Queue/Library view.
This also removes the need for a separate track_name_first and album_column option.

* Fixed README

* Made custom tracklist formatting more flexible.
Updated readme with new instructions.
Reformatted impl member order to match the definitions in traits.rs.

* Fetch formatting config from library config

Instead of the lazy static mutex

* Moved custom format function to Playable impl as it's a better location to handle both Tracks and Episodes

* Rename from `tracklist_formatting` to `track_format`

Also shorten `format_{left|center|right}` to `{left|center|right}`

Co-authored-by: Henrik Friedrichsen <henrik@affekt.org>
  • Loading branch information
Bettehem and hrkfdn authored May 28, 2022
1 parent 0e50466 commit 4ea3d4a
Show file tree
Hide file tree
Showing 12 changed files with 272 additions and 109 deletions.
61 changes: 61 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ as the \*BSDs.
- [Custom Keybindings](#custom-keybindings)
- [Proxy](#proxy)
- [Theming](#theming)
- [Tracklist Formatting](#tracklist-formatting)
- [Cover Drawing](#cover-drawing)
- [Authentication](#authentication)

Expand Down Expand Up @@ -328,6 +329,7 @@ Possible configuration values are:
| `repeat` | Set default repeat mode | `off`, `track`, `playlist` | `off` |
| `playback_state` | Set default playback state | `"Stopped"`, `"Paused"`, `"Playing"`, `"Default"` | `"Paused"` |
| `library_tabs` | Tabs to show in library screen | Array of `tracks`, `albums`, `artists`, `playlists`, `podcasts` | All tabs |
| `[track_format]` | Set active fields shown in Library/Queue views | See [track formatting](#track-formatting) | |
| `[theme]` | Custom theme | See [custom theme](#theming) | |
| `[keybindings]` | Custom keybindings | See [custom keybindings](#custom-keybindings) | |

Expand Down Expand Up @@ -385,6 +387,65 @@ search_match = "light red"

More examples can be found in [this pull request](https://github.com/hrkfdn/ncspot/pull/40).

### Track Formatting
It's possible to customize which fields are shown in Queue/Library views.
If you don't define `center` for example, the default value will be used.
Available options for tracks:
`%artists`, `%title`, `%album`, `%saved`, `%duration`
Default configuration:

```toml
[track_format]
left = "%artists - %title"
center = "%album"
right = "%saved %duration"
```

<details><summary>Examples: (Click to show/hide)</summary>


Example 1 - Show only album name and track name after it:

```toml
[track_format]
left = "%album"
center = "%title"
right = ""
```

Example 2 - Show track title before artists, and don't show album at all:

```toml
[track_format]
left = "%title - %artists"
center = ""
```

Example 3 - Show everything as default, but hide saved status and track length:

```toml
[track_format]
right = ""
```

Example 4 - Show everything as default, except show title before artists:

```toml
[track_format]
left = "%title - %artists"
```

Example 5 - Show saved status and duration first, followed by track title and artists, with the album last:

```toml
[track_format]
left = "|%saved| %duration | %title - %artists"
center = ""
right = "%album"
```

</details>

## Cover Drawing

When compiled with the `cover` feature, `ncspot` can draw the album art of the
Expand Down
19 changes: 18 additions & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,23 @@ pub enum LibraryTab {
Podcasts,
}

#[derive(Serialize, Deserialize, Debug, Default, Clone)]
pub struct TrackFormat {
pub left: Option<String>,
pub center: Option<String>,
pub right: Option<String>,
}

impl TrackFormat {
pub fn default() -> Self {
TrackFormat {
left: Some(String::from("%artists - %title")),
center: Some(String::from("%album")),
right: Some(String::from("%saved %duration")),
}
}
}

#[derive(Clone, Serialize, Deserialize, Debug, Default)]
pub struct ConfigValues {
pub command_key: Option<char>,
Expand All @@ -50,12 +67,12 @@ pub struct ConfigValues {
pub volnorm_pregain: Option<f64>,
pub notify: Option<bool>,
pub bitrate: Option<u32>,
pub album_column: Option<bool>,
pub gapless: Option<bool>,
pub shuffle: Option<bool>,
pub repeat: Option<queue::RepeatSetting>,
pub cover_max_scale: Option<f32>,
pub playback_state: Option<PlaybackState>,
pub track_format: Option<TrackFormat>,
pub library_tabs: Option<Vec<LibraryTab>>,
}

Expand Down
26 changes: 13 additions & 13 deletions src/model/album.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,7 @@ impl ListItem for Album {
}
}

fn as_listitem(&self) -> Box<dyn ListItem> {
Box::new(self.clone())
}

fn display_left(&self) -> String {
fn display_left(&self, _library: Arc<Library>) -> String {
format!("{}", self)
}

Expand Down Expand Up @@ -219,14 +215,6 @@ impl ListItem for Album {
}
}

fn save(&mut self, library: Arc<Library>) {
library.save_album(self);
}

fn unsave(&mut self, library: Arc<Library>) {
library.unsave_album(self);
}

fn toggle_saved(&mut self, library: Arc<Library>) {
if library.is_saved_album(self) {
library.unsave_album(self);
Expand All @@ -235,6 +223,14 @@ impl ListItem for Album {
}
}

fn save(&mut self, library: Arc<Library>) {
library.save_album(self);
}

fn unsave(&mut self, library: Arc<Library>) {
library.unsave_album(self);
}

fn open(&self, queue: Arc<Queue>, library: Arc<Library>) -> Option<Box<dyn ViewExt>> {
Some(AlbumView::new(queue, library, self).into_boxed_view_ext())
}
Expand Down Expand Up @@ -301,4 +297,8 @@ impl ListItem for Album {
.collect(),
)
}

fn as_listitem(&self) -> Box<dyn ListItem> {
Box::new(self.clone())
}
}
26 changes: 13 additions & 13 deletions src/model/artist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,7 @@ impl ListItem for Artist {
}
}

fn as_listitem(&self) -> Box<dyn ListItem> {
Box::new(self.clone())
}

fn display_left(&self) -> String {
fn display_left(&self, _library: Arc<Library>) -> String {
format!("{}", self)
}

Expand Down Expand Up @@ -155,14 +151,6 @@ impl ListItem for Artist {
}
}

fn save(&mut self, library: Arc<Library>) {
library.follow_artist(self);
}

fn unsave(&mut self, library: Arc<Library>) {
library.unfollow_artist(self);
}

fn toggle_saved(&mut self, library: Arc<Library>) {
if library.is_followed_artist(self) {
library.unfollow_artist(self);
Expand All @@ -171,6 +159,14 @@ impl ListItem for Artist {
}
}

fn save(&mut self, library: Arc<Library>) {
library.follow_artist(self);
}

fn unsave(&mut self, library: Arc<Library>) {
library.unfollow_artist(self);
}

fn open(&self, queue: Arc<Queue>, library: Arc<Library>) -> Option<Box<dyn ViewExt>> {
Some(ArtistView::new(queue, library, self).into_boxed_view_ext())
}
Expand Down Expand Up @@ -205,4 +201,8 @@ impl ListItem for Artist {
.clone()
.map(|id| format!("https://open.spotify.com/artist/{}", id))
}

fn as_listitem(&self) -> Box<dyn ListItem> {
Box::new(self.clone())
}
}
2 changes: 1 addition & 1 deletion src/model/episode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ impl ListItem for Episode {
.unwrap_or(false)
}

fn display_left(&self) -> String {
fn display_left(&self, _library: Arc<Library>) -> String {
self.name.clone()
}

Expand Down
53 changes: 51 additions & 2 deletions src/model/playable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,55 @@ pub enum Playable {
}

impl Playable {
pub fn format(playable: Playable, formatting: String, library: Arc<Library>) -> String {
formatting
.replace(
"%artists",
if let Some(artists) = playable.artists() {
artists
.iter()
.map(|artist| artist.clone().name)
.collect::<Vec<String>>()
.join(", ")
} else {
String::new()
}
.as_str(),
)
.replace(
"%title",
match playable.clone() {
Playable::Episode(episode) => episode.name,
Playable::Track(track) => track.title,
}
.as_str(),
)
.replace(
"%album",
match playable.clone() {
Playable::Track(track) => track.album.unwrap_or_default(),
_ => String::new(),
}
.as_str(),
)
.replace(
"%saved",
if library.is_saved_track(&match playable.clone() {
Playable::Episode(episode) => Playable::Episode(episode),
Playable::Track(track) => Playable::Track(track),
}) {
if library.cfg.values().use_nerdfont.unwrap_or_default() {
"\u{f62b}"
} else {
"✓"
}
} else {
""
},
)
.replace("%duration", playable.duration_str().as_str())
}

pub fn id(&self) -> Option<String> {
match self {
Playable::Track(track) => track.id.clone(),
Expand Down Expand Up @@ -106,8 +155,8 @@ impl ListItem for Playable {
self.as_listitem().is_playing(queue)
}

fn display_left(&self) -> String {
self.as_listitem().display_left()
fn display_left(&self, library: Arc<Library>) -> String {
self.as_listitem().display_left(library)
}

fn display_center(&self, library: Arc<Library>) -> String {
Expand Down
26 changes: 13 additions & 13 deletions src/model/playlist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,11 +191,7 @@ impl ListItem for Playlist {
}
}

fn as_listitem(&self) -> Box<dyn ListItem> {
Box::new(self.clone())
}

fn display_left(&self) -> String {
fn display_left(&self, _library: Arc<Library>) -> String {
match self.owner_name.as_ref() {
Some(owner) => format!("{} • {}", self.name, owner),
None => self.name.clone(),
Expand Down Expand Up @@ -251,14 +247,6 @@ impl ListItem for Playlist {
}
}

fn save(&mut self, library: Arc<Library>) {
library.follow_playlist(self);
}

fn unsave(&mut self, library: Arc<Library>) {
library.delete_playlist(&self.id);
}

fn toggle_saved(&mut self, library: Arc<Library>) {
// Don't allow users to unsave their own playlists with one keypress
if !library.is_followed_playlist(self) {
Expand All @@ -272,6 +260,14 @@ impl ListItem for Playlist {
}
}

fn save(&mut self, library: Arc<Library>) {
library.follow_playlist(self);
}

fn unsave(&mut self, library: Arc<Library>) {
library.delete_playlist(&self.id);
}

fn open(&self, queue: Arc<Queue>, library: Arc<Library>) -> Option<Box<dyn ViewExt>> {
Some(PlaylistView::new(queue, library, self).into_boxed_view_ext())
}
Expand Down Expand Up @@ -326,4 +322,8 @@ impl ListItem for Playlist {
self.owner_id, self.id
))
}

fn as_listitem(&self) -> Box<dyn ListItem> {
Box::new(self.clone())
}
}
2 changes: 1 addition & 1 deletion src/model/show.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ impl ListItem for Show {
false
}

fn display_left(&self) -> String {
fn display_left(&self, _library: Arc<Library>) -> String {
format!("{}", self)
}

Expand Down
Loading

0 comments on commit 4ea3d4a

Please sign in to comment.