A command driven spotify player

Overview

spotify-player

Table of Contents

Introduction

  • spotify-player is a fast, easy to use, and configurable terminal music player.
  • spotify-player is designed to be a player, not a fully-fledged Spotify clone, so it does not aim to support all Spotify features. Its main goal is to provide a quick and intuitive way to control music using commands.
  • spotify-player is built on top of awesome libraries such as tui-rs, rspotify, librespot, and many more. It's highly inspired by spotify-tui and ncspot.
  • spotify-player can be used as either a remote player to control another Spotify client or a local player with an integrated Spotify client. If you are familiar with other Spotify terminal applications, spotify-player can be viewed as a combination of spotify-tui (remote player) and ncspot (local player).
  • On startup, the application will connect to a running Spotify client. If there is no such client, user will need to use Spotify connect to connect to an available client.

Examples

Demo

A demo of spotify-player v0.5.0-pre-release on youtube or on asciicast:

asciicast

Playlist

Playlist context example

Artist

Artist context example

Album

Album context example

Search

Search page example

Installation

Requirements

A Spotify Premium account is recommended to enable all application's supported features.

To build and run the application, besides Rust and cargo as the build requirements, Linux users will also need to install additional dependencies such as openssl and alsa-lib.

Cargo

Run cargo install spotify_player to install the application from crates.io.

AUR

Run yay -S spotify-player to install the application as an AUR package.

NetBSD

Using the package manager, run pkgin install spotify-player to install from the official repositories.

Building from source,

cd /usr/pkgsrc/audio/spotify-player
make install

Docker

Note: streaming feature is disabled when using the docker image.

You can download the binary image of the latest build from the master branch by running

docker pull aome510/spotify_player:latest

then run

docker run --rm -it aome510/spotify_player:latest

to run the application.

You can also use your local config folder to configure the application or your local cache folder to store the application's cache data when running the docker image:

docker run --rm \
-v $APP_CONFIG_FOLDER:/app/config/ \
-v $APP_CACHE_FOLDER:/app/cache/ \
-it aome510/spotify_player:latest

Spotify Connect

To enable full Spotify connect support, user will need to register a Spotify application and specify their own client_id in the application's general configuration file as described in the configuration documentation.

More details on registering a Spotify application can be found in the Spotify documentation.

If spotify_player runs with your own client_id, press D (default shortcut for SwitchDevice command) to get the list of available devices, then press enter (default shortcut for ChooseSelected command) to connect to the selected device.

An example of using Spotify connect to interact with Spotify's official client:

Spotify Connect Example

Streaming

spotify-player supports streaming. It uses librespot library to create an integrated Spotify client while running. The integrated client will register a Spotify speaker device under the spotify-player name.

spotify-player uses rodio as the default audio backend. List of available backends:

  • alsa-backend
  • pulseaudio-backend
  • rodio-backend
  • portaudio-backend
  • jackaudio-backend
  • rodiojack-backend
  • sdl-backend
  • gstreamer-backend

User can change the audio backend when building the application by specifying the --features option. For example, to build spotify-player with pulseaudio-backend, run

cargo build --release --no-default-features --features pulseaudio-backend

Note: user will need additional dependencies depending on the selected audio backend. More details can be found in the Librespot documentation.

The streaming feature can be disabled by running (to use the application as a remote player only)

cargo build --release --no-default-features

Commands

To open a shortcut help popup, press ? or C-h (default shortcuts for OpenCommandHelp command).

List of supported commands:

Command Description Default shortcuts
NextTrack next track n
PreviousTrack previous track p
ResumePause resume/pause based on the current playback space
PlayRandom play a random track in the current context .
Repeat cycle the repeat mode C-r
Shuffle toggle the shuffle mode C-s
VolumeUp increase playback volume by 5% +
VolumeDown decrease playback volume by 5% -
Quit quit the application C-c, q
OpenCommandHelp open a command help popup ?, C-h
ClosePopup close a popup esc
SelectNextOrScrollDown select the next item in a list/table or scroll down j, C-j, down
SelectPreviousOrScrollUp select the previous item in a list/table or scroll up k, C-k, up
ChooseSelected choose the selected item enter
RefreshPlayback manually refresh the current playback r
ShowActionsOnSelectedItem open a popup showing actions on a selected item g a, C-space
ShowActionsOnCurrentTrack open a popup showing actions on the currently playing track a
FocusNextWindow focus the next focusable window (if any) tab
FocusPreviousWindow focus the previous focusable window (if any) backtab
SwitchTheme open a popup for switching theme T
SwitchDevice open a popup for switching device D
Search open a popup for searching in the current page /
BrowseUserPlaylists open a popup for browsing user's playlists u p
BrowseUserFollowedArtists open a popup for browsing user's followed artists u a
BrowseUserSavedAlbums open a popup for browsing user's saved albums u A
BrowsePlayingContext browse the current playing context g space
LibraryPage go to the user library page g l
SearchPage go to the search page g s
PreviousPage go to the previous page backspace, C-p
SortTrackByTitle sort the track table (if any) by track's title s t
SortTrackByArtists sort the track table (if any) by track's artists s a
SortTrackByAlbum sort the track table (if any) by track's album s A
SortTrackByDuration sort the track table (if any) by track's duration s d
SortTrackByAddedDate sort the track table (if any) by track's added date s D
ReverseOrder reverse the order of the track table (if any) s r

To add new shortcuts or modify the default shortcuts, please refer to the keymaps section in the configuration documentation.

Actions

There will be a list of possible actions depending on the type of the corresponding Spotify item (track, album, artist, or playlist). For example, the list of available actions on a track is [BrowseAlbum, BrowseArtist, BrowseRecommandations, AddTrackToPlaylist, SaveToLibrary].

To get the list of actions on an item, call the ShowActionsOnCurrentTrack command or ShowActionsOnSelectedItem command.

Search Page

When first entering the search page, the application focuses on the search input. User can then input text, delete one character backward using backspace, or search the text using enter.

To move the focus from the search input to the other windows such as track results, album results, etc, use FocusNextWindow or FocusPreviousWindow.

Mouse support

Currently, the only use case of mouse is to seek to a position of the current playback by left-clicking to such position in the playback's progress bar.

Configurations

By default, spotify-player will look into $HOME/.config/spotify-player for application's configuration files. This can be changed by either specifying -c <FOLDER_PATH> or --config-folder <FOLDER_PATH> option.

Please refer to the configuration documentation for more details on the configuration options.

Caches

By default, spotify-player will look into $HOME/.cache/spotify-player for application's cache files, which include log file, spotify's authorization credentials, audio cache files, etc. This can be changed by either specifying -C <FOLDER_PATH> or --cache-folder <FOLDER_PATH> option.

Logging

spotify-player uses RUST_LOG environment variable to define the application's logging level (default to be INFO). The application stores logs inside the $APP_CACHE_FOLDER/spotify-player.log file which can be configured by specifying the -l <FILE_PATH> or --log-file <FILE_PATH> option.

Roadmap

  • integrate Spotify's search APIs
  • integrate Spotify's recommendation API
  • add supports for add track to playlist, save album, follow artist, and related commands.
  • integrate Spotify's recently played API
  • handle networking error when running
  • add a (optional?) integrated spotify client (possibly use librespot)
    • implement a custom connection logic to replace librespot's spirc.
  • add mpris (dbus) support
Comments
  • spotify_player fails to play any track, Spotify changes?

    spotify_player fails to play any track, Spotify changes?

    @aome510

    The player jumps through songs and when reaching the end of the list it starts over again. Killing the app is the only way out of this loop.

    Attached the log file, although it generates several of these one after the other.

    Backtraces are empty :(

    ClientID has been hidden on the log file.

    If you need to check my configurations see, https://codeberg.org/pin/leftwm-netbsd/src/branch/main/.config/spotify-player

    spotify-player-22-08-04-09:32.log

    EDIT: Downgraded to 0.9.3 and the bug is already present there. I've been on holiday and just pushed the updates. Downgraded to 0.9.2 and it's the same, then downgraded to 0.9.0 and the same happens.

    I'm lost, I start to think that something else is causing this. I've also built 0.8.0 just to be sure, as I know this one worked before and it does the same :( I've no clue how to fix this or what is causing it.

    opened by 0323pin 22
  • Integrated device not shown up

    Integrated device not shown up "fast enough" on startup

    Lately I've noticed that spotify-player is starting without picking the default device (Which is itself). In the config file is like this:

    default_device = "artorias"
    
    [device]
    name = "artorias"
    device_type = "computer"
    volume = 100
    bitrate = 320
    audio_cache = false
    

    So whenever I open the player, I have to choose a device manually (There it's listed) and then I can play music. Is there some kind of race condition or something for picking the default device maybe?

    bug 
    opened by alosarjos 14
  • StreamError - not working

    StreamError - not working

    I have installed player from AUR (btw it is still 0.5.1 version) and it is not working. This is what i see (look at the playlist - was not able to copy this error): image

    opened by elkrien 12
  • MPRIS support?

    MPRIS support?

    Hi there! Just found this project. It looks great! Congratulations on it.

    Do you plan on adding MPRIS support so it can be controlled with media keys on Linux?

    enhancement 
    opened by alosarjos 11
  • Play/Pause icon

    Play/Pause icon

    I noticed recently spotify-player switched to this icon for me? Im not sure if im able to configure an option to switch the icon or not, just noticed it one day. I'll keep digging to see if I can change it but figured I'd ask to see if theres an easy fix. 29-07-2022-21-08-34

    enhancement 
    opened by Selmer443 7
  • Not working after update to 0.9.0

    Not working after update to 0.9.0

    Hi, Unfortunately after updating to newest release 0.9.0 player freezes after start. Before updating everything worked fine. This is what I see now: image

    When I press any key it is not working. Here is backtrace log:

    Got a panic: PanicInfo {
        payload: Any { .. },
        message: Some(
            invalid playing context URI: InvalidType,
        ),
        location: Location {
            file: "spotify_player/src/state/player.rs",
            line: 65,
            col: 60,
        },
        can_unwind: true,
    }
    
    Stack backtrace:
       0: <unknown>
       1: <unknown>
       2: <unknown>
       3: <unknown>
       4: <unknown>
       5: <unknown>
       6: <unknown>
       7: <unknown>
       8: <unknown>
       9: <unknown>
      10: <unknown>
      11: <unknown>
      12: <unknown>
      13: <unknown>
      14: <unknown>
      15: <unknown>
      16: <unknown>
      17: <unknown>
      18: <unknown>
      19: <unknown>
      20: clone
    

    and log (I have deleted client ID after pasting here):

    2022-06-19T17:44:07.311698Z  INFO spotify_player::state: General configurations: AppConfig { theme: "Catppuccin-mocha", client_id: "", app_refresh_duration_in_ms: 32, playback_refresh_duration_in_ms: 0, track_table_item_max_len: 32, enable_media_control: true, default_device: "spotify-player", device: DeviceConfig { name: "spotify-player", device_type: "speaker", volume: 100, bitrate: 160, audio_cache: false } }
    2022-06-19T17:44:07.311882Z  INFO spotify_player::state: Theme configurations: ThemeConfig { themes: [Theme { name: "dracula", palette: Palette { background: Color { color: Rgb(30, 31, 41) }, foreground: Color { color: Rgb(248, 248, 242) }, selection_background: Color { color: Rgb(68, 71, 90) }, selection_foreground: Color { color: Rgb(255, 255, 255) }, black: Color { color: Rgb(0, 0, 0) }, blue: Color { color: Rgb(189, 147, 249) }, cyan: Color { color: Rgb(139, 233, 253) }, green: Color { color: Rgb(80, 250, 123) }, magenta: Color { color: Rgb(255, 121, 198) }, red: Color { color: Rgb(255, 85, 85) }, white: Color { color: Rgb(187, 187, 187) }, yellow: Color { color: Rgb(241, 250, 140) }, bright_black: Color { color: Rgb(85, 85, 85) }, bright_white: Color { color: Rgb(255, 255, 255) }, bright_red: Color { color: Rgb(255, 85, 85) }, bright_magenta: Color { color: Rgb(255, 121, 198) }, bright_green: Color { color: Rgb(80, 250, 123) }, bright_cyan: Color { color: Rgb(139, 233, 253) }, bright_blue: Color { color: Rgb(189, 147, 249) }, bright_yellow: Color { color: Rgb(241, 250, 140) } }, component_style: ComponentStyle { block_title: Style { fg: Some(Magenta), bg: None, modifiers: [] }, playback_track: Style { fg: Some(Cyan), bg: None, modifiers: [Bold] }, playback_album: Style { fg: Some(Yellow), bg: None, modifiers: [] }, playback_metadata: Style { fg: Some(BrightBlack), bg: None, modifiers: [] }, playback_progress_bar: Style { fg: Some(Green), bg: Some(SelectionBackground), modifiers: [] }, current_playing: Style { fg: Some(Green), bg: None, modifiers: [Bold] }, page_desc: Style { fg: Some(Cyan), bg: None, modifiers: [Bold] }, table_header: Style { fg: Some(Blue), bg: None, modifiers: [] } } }, Theme { name: "ayu_light", palette: Palette { background: Color { color: Rgb(250, 250, 250) }, foreground: Color { color: Rgb(92, 103, 115) }, selection_background: Color { color: Rgb(240, 238, 228) }, selection_foreground: Color { color: Rgb(92, 103, 115) }, black: Color { color: Rgb(0, 0, 0) }, blue: Color { color: Rgb(65, 166, 217) }, cyan: Color { color: Rgb(77, 191, 153) }, green: Color { color: Rgb(134, 179, 0) }, magenta: Color { color: Rgb(240, 113, 120) }, red: Color { color: Rgb(255, 51, 51) }, white: Color { color: Rgb(255, 255, 255) }, yellow: Color { color: Rgb(242, 151, 24) }, bright_black: Color { color: Rgb(50, 50, 50) }, bright_white: Color { color: Rgb(255, 255, 255) }, bright_red: Color { color: Rgb(255, 101, 101) }, bright_magenta: Color { color: Rgb(255, 163, 170) }, bright_green: Color { color: Rgb(184, 229, 50) }, bright_cyan: Color { color: Rgb(127, 241, 203) }, bright_blue: Color { color: Rgb(115, 216, 255) }, bright_yellow: Color { color: Rgb(255, 201, 74) } }, component_style: ComponentStyle { block_title: Style { fg: Some(Magenta), bg: None, modifiers: [] }, playback_track: Style { fg: Some(Cyan), bg: None, modifiers: [Bold] }, playback_album: Style { fg: Some(Yellow), bg: None, modifiers: [] }, playback_metadata: Style { fg: Some(BrightBlack), bg: None, modifiers: [] }, playback_progress_bar: Style { fg: Some(Green), bg: Some(SelectionBackground), modifiers: [] }, current_playing: Style { fg: Some(Green), bg: None, modifiers: [Bold] }, page_desc: Style { fg: Some(Cyan), bg: None, modifiers: [Bold] }, table_header: Style { fg: Some(Blue), bg: None, modifiers: [] } } }, Theme { name: "gruvbox_dark", palette: Palette { background: Color { color: Rgb(30, 30, 30) }, foreground: Color { color: Rgb(230, 212, 163) }, selection_background: Color { color: Rgb(230, 212, 163) }, selection_foreground: Color { color: Rgb(83, 74, 66) }, black: Color { color: Rgb(30, 30, 30) }, blue: Color { color: Rgb(55, 115, 117) }, cyan: Color { color: Rgb(87, 142, 87) }, green: Color { color: Rgb(134, 135, 21) }, magenta: Color { color: Rgb(160, 75, 115) }, red: Color { color: Rgb(190, 15, 23) }, white: Color { color: Rgb(151, 135, 113) }, yellow: Color { color: Rgb(204, 136, 26) }, bright_black: Color { color: Rgb(127, 112, 97) }, bright_white: Color { color: Rgb(230, 212, 163) }, bright_red: Color { color: Rgb(247, 48, 40) }, bright_magenta: Color { color: Rgb(199, 112, 137) }, bright_green: Color { color: Rgb(170, 176, 30) }, bright_cyan: Color { color: Rgb(125, 182, 105) }, bright_blue: Color { color: Rgb(113, 149, 134) }, bright_yellow: Color { color: Rgb(247, 177, 37) } }, component_style: ComponentStyle { block_title: Style { fg: Some(Magenta), bg: None, modifiers: [] }, playback_track: Style { fg: Some(Cyan), bg: None, modifiers: [Bold] }, playback_album: Style { fg: Some(Yellow), bg: None, modifiers: [] }, playback_metadata: Style { fg: Some(BrightBlack), bg: None, modifiers: [] }, playback_progress_bar: Style { fg: Some(Green), bg: Some(SelectionBackground), modifiers: [] }, current_playing: Style { fg: Some(Green), bg: None, modifiers: [Bold] }, page_desc: Style { fg: Some(Cyan), bg: None, modifiers: [Bold] }, table_header: Style { fg: Some(Blue), bg: None, modifiers: [] } } }, Theme { name: "solarized_light", palette: Palette { background: Color { color: Rgb(253, 246, 227) }, foreground: Color { color: Rgb(101, 123, 131) }, selection_background: Color { color: Rgb(238, 232, 213) }, selection_foreground: Color { color: Rgb(88, 110, 117) }, black: Color { color: Rgb(7, 54, 66) }, blue: Color { color: Rgb(38, 139, 210) }, cyan: Color { color: Rgb(42, 161, 152) }, green: Color { color: Rgb(133, 153, 0) }, magenta: Color { color: Rgb(211, 54, 130) }, red: Color { color: Rgb(220, 50, 47) }, white: Color { color: Rgb(238, 232, 213) }, yellow: Color { color: Rgb(181, 137, 0) }, bright_black: Color { color: Rgb(0, 43, 54) }, bright_white: Color { color: Rgb(253, 246, 227) }, bright_red: Color { color: Rgb(203, 75, 22) }, bright_magenta: Color { color: Rgb(108, 113, 196) }, bright_green: Color { color: Rgb(88, 110, 117) }, bright_cyan: Color { color: Rgb(147, 161, 161) }, bright_blue: Color { color: Rgb(131, 148, 150) }, bright_yellow: Color { color: Rgb(101, 123, 131) } }, component_style: ComponentStyle { block_title: Style { fg: Some(Magenta), bg: None, modifiers: [] }, playback_track: Style { fg: Some(Cyan), bg: None, modifiers: [Bold] }, playback_album: Style { fg: Some(Yellow), bg: None, modifiers: [] }, playback_metadata: Style { fg: Some(BrightBlack), bg: None, modifiers: [] }, playback_progress_bar: Style { fg: Some(Green), bg: Some(SelectionBackground), modifiers: [] }, current_playing: Style { fg: Some(Green), bg: None, modifiers: [Bold] }, page_desc: Style { fg: Some(Cyan), bg: None, modifiers: [Bold] }, table_header: Style { fg: Some(Blue), bg: None, modifiers: [] } } }, Theme { name: "Catppuccin-mocha", palette: Palette { background: Color { color: Rgb(30, 30, 46) }, foreground: Color { color: Rgb(205, 214, 244) }, selection_background: Color { color: Rgb(49, 50, 68) }, selection_foreground: Color { color: Rgb(205, 214, 244) }, black: Color { color: Rgb(30, 30, 46) }, blue: Color { color: Rgb(137, 180, 250) }, cyan: Color { color: Rgb(137, 220, 235) }, green: Color { color: Rgb(166, 227, 161) }, magenta: Color { color: Rgb(203, 166, 247) }, red: Color { color: Rgb(243, 139, 168) }, white: Color { color: Rgb(205, 214, 244) }, yellow: Color { color: Rgb(249, 226, 175) }, bright_black: Color { color: Rgb(30, 30, 46) }, bright_white: Color { color: Rgb(205, 214, 244) }, bright_red: Color { color: Rgb(243, 139, 168) }, bright_magenta: Color { color: Rgb(203, 166, 247) }, bright_green: Color { color: Rgb(166, 227, 161) }, bright_cyan: Color { color: Rgb(137, 220, 235) }, bright_blue: Color { color: Rgb(137, 180, 250) }, bright_yellow: Color { color: Rgb(249, 226, 175) } }, component_style: ComponentStyle { block_title: Style { fg: Some(Magenta), bg: None, modifiers: [] }, playback_track: Style { fg: Some(Cyan), bg: None, modifiers: [Bold] }, playback_album: Style { fg: Some(Yellow), bg: None, modifiers: [] }, playback_metadata: Style { fg: Some(BrightBlack), bg: None, modifiers: [] }, playback_progress_bar: Style { fg: Some(Green), bg: Some(SelectionBackground), modifiers: [] }, current_playing: Style { fg: Some(Green), bg: None, modifiers: [Bold] }, page_desc: Style { fg: Some(Cyan), bg: None, modifiers: [Bold] }, table_header: Style { fg: Some(Blue), bg: None, modifiers: [] } } }, Theme { name: "Catppuccin-latte", palette: Palette { background: Color { color: Rgb(239, 241, 245) }, foreground: Color { color: Rgb(76, 79, 105) }, selection_background: Color { color: Rgb(204, 208, 218) }, selection_foreground: Color { color: Rgb(76, 79, 105) }, black: Color { color: Rgb(239, 241, 245) }, blue: Color { color: Rgb(30, 102, 245) }, cyan: Color { color: Rgb(4, 165, 229) }, green: Color { color: Rgb(64, 160, 43) }, magenta: Color { color: Rgb(136, 57, 239) }, red: Color { color: Rgb(210, 15, 57) }, white: Color { color: Rgb(76, 79, 105) }, yellow: Color { color: Rgb(223, 142, 29) }, bright_black: Color { color: Rgb(239, 241, 245) }, bright_white: Color { color: Rgb(76, 79, 105) }, bright_red: Color { color: Rgb(210, 15, 57) }, bright_magenta: Color { color: Rgb(136, 57, 239) }, bright_green: Color { color: Rgb(64, 160, 43) }, bright_cyan: Color { color: Rgb(4, 165, 229) }, bright_blue: Color { color: Rgb(30, 102, 245) }, bright_yellow: Color { color: Rgb(223, 142, 29) } }, component_style: ComponentStyle { block_title: Style { fg: Some(Magenta), bg: None, modifiers: [] }, playback_track: Style { fg: Some(Cyan), bg: None, modifiers: [Bold] }, playback_album: Style { fg: Some(Yellow), bg: None, modifiers: [] }, playback_metadata: Style { fg: Some(BrightBlack), bg: None, modifiers: [] }, playback_progress_bar: Style { fg: Some(Green), bg: Some(SelectionBackground), modifiers: [] }, current_playing: Style { fg: Some(Green), bg: None, modifiers: [Bold] }, page_desc: Style { fg: Some(Cyan), bg: None, modifiers: [Bold] }, table_header: Style { fg: Some(Blue), bg: None, modifiers: [] } } }, Theme { name: "Catppuccin-frappe", palette: Palette { background: Color { color: Rgb(48, 52, 70) }, foreground: Color { color: Rgb(198, 208, 245) }, selection_background: Color { color: Rgb(65, 69, 89) }, selection_foreground: Color { color: Rgb(198, 208, 245) }, black: Color { color: Rgb(48, 52, 70) }, blue: Color { color: Rgb(140, 170, 238) }, cyan: Color { color: Rgb(137, 220, 235) }, green: Color { color: Rgb(166, 209, 137) }, magenta: Color { color: Rgb(202, 158, 230) }, red: Color { color: Rgb(231, 130, 132) }, white: Color { color: Rgb(198, 208, 245) }, yellow: Color { color: Rgb(229, 200, 144) }, bright_black: Color { color: Rgb(48, 52, 70) }, bright_white: Color { color: Rgb(198, 208, 245) }, bright_red: Color { color: Rgb(231, 130, 132) }, bright_magenta: Color { color: Rgb(202, 158, 230) }, bright_green: Color { color: Rgb(166, 209, 137) }, bright_cyan: Color { color: Rgb(137, 220, 235) }, bright_blue: Color { color: Rgb(140, 170, 238) }, bright_yellow: Color { color: Rgb(229, 200, 144) } }, component_style: ComponentStyle { block_title: Style { fg: Some(Magenta), bg: None, modifiers: [] }, playback_track: Style { fg: Some(Cyan), bg: None, modifiers: [Bold] }, playback_album: Style { fg: Some(Yellow), bg: None, modifiers: [] }, playback_metadata: Style { fg: Some(BrightBlack), bg: None, modifiers: [] }, playback_progress_bar: Style { fg: Some(Green), bg: Some(SelectionBackground), modifiers: [] }, current_playing: Style { fg: Some(Green), bg: None, modifiers: [Bold] }, page_desc: Style { fg: Some(Cyan), bg: None, modifiers: [Bold] }, table_header: Style { fg: Some(Blue), bg: None, modifiers: [] } } }, Theme { name: "Catppuccin-macchiato", palette: Palette { background: Color { color: Rgb(36, 39, 58) }, foreground: Color { color: Rgb(202, 211, 245) }, selection_background: Color { color: Rgb(54, 58, 79) }, selection_foreground: Color { color: Rgb(202, 211, 245) }, black: Color { color: Rgb(36, 39, 58) }, blue: Color { color: Rgb(138, 173, 244) }, cyan: Color { color: Rgb(145, 215, 227) }, green: Color { color: Rgb(166, 218, 149) }, magenta: Color { color: Rgb(198, 160, 246) }, red: Color { color: Rgb(237, 135, 150) }, white: Color { color: Rgb(202, 211, 245) }, yellow: Color { color: Rgb(238, 212, 159) }, bright_black: Color { color: Rgb(36, 39, 58) }, bright_white: Color { color: Rgb(202, 211, 245) }, bright_red: Color { color: Rgb(237, 135, 150) }, bright_magenta: Color { color: Rgb(198, 160, 246) }, bright_green: Color { color: Rgb(166, 218, 149) }, bright_cyan: Color { color: Rgb(145, 215, 227) }, bright_blue: Color { color: Rgb(138, 173, 244) }, bright_yellow: Color { color: Rgb(238, 212, 159) } }, component_style: ComponentStyle { block_title: Style { fg: Some(Magenta), bg: None, modifiers: [] }, playback_track: Style { fg: Some(Cyan), bg: None, modifiers: [Bold] }, playback_album: Style { fg: Some(Yellow), bg: None, modifiers: [] }, playback_metadata: Style { fg: Some(BrightBlack), bg: None, modifiers: [] }, playback_progress_bar: Style { fg: Some(Green), bg: Some(SelectionBackground), modifiers: [] }, current_playing: Style { fg: Some(Green), bg: None, modifiers: [Bold] }, page_desc: Style { fg: Some(Cyan), bg: None, modifiers: [Bold] }, table_header: Style { fg: Some(Blue), bg: None, modifiers: [] } } }] }
    2022-06-19T17:44:07.311939Z  WARN spotify_player::config::keymap: Failed to open the keymap config file (path="/home/mm/.config/spotify-player/keymap.toml"): No such file or directory (os error 2). Use the default configurations instead
    2022-06-19T17:44:07.311944Z  INFO spotify_player::state: Keymap configurations: KeymapConfig { keymaps: [Keymap { key_sequence: KeySequence { keys: [None(Char('n'))] }, command: NextTrack }, Keymap { key_sequence: KeySequence { keys: [None(Char('p'))] }, command: PreviousTrack }, Keymap { key_sequence: KeySequence { keys: [None(Char('.'))] }, command: PlayRandom }, Keymap { key_sequence: KeySequence { keys: [None(Char(' '))] }, command: ResumePause }, Keymap { key_sequence: KeySequence { keys: [Ctrl(Char('r'))] }, command: Repeat }, Keymap { key_sequence: KeySequence { keys: [Ctrl(Char('s'))] }, command: Shuffle }, Keymap { key_sequence: KeySequence { keys: [None(Char('+'))] }, command: VolumeUp }, Keymap { key_sequence: KeySequence { keys: [None(Char('-'))] }, command: VolumeDown }, Keymap { key_sequence: KeySequence { keys: [None(Enter)] }, command: ChooseSelected }, Keymap { key_sequence: KeySequence { keys: [None(Char('r'))] }, command: RefreshPlayback }, Keymap { key_sequence: KeySequence { keys: [None(Char('/'))] }, command: Search }, Keymap { key_sequence: KeySequence { keys: [Ctrl(Char(' '))] }, command: ShowActionsOnSelectedItem }, Keymap { key_sequence: KeySequence { keys: [None(Char('g')), None(Char('a'))] }, command: ShowActionsOnSelectedItem }, Keymap { key_sequence: KeySequence { keys: [None(Char('a'))] }, command: ShowActionsOnCurrentTrack }, Keymap { key_sequence: KeySequence { keys: [None(Char('R'))] }, command: RestartIntegratedClient }, Keymap { key_sequence: KeySequence { keys: [None(Tab)] }, command: FocusNextWindow }, Keymap { key_sequence: KeySequence { keys: [None(BackTab)] }, command: FocusPreviousWindow }, Keymap { key_sequence: KeySequence { keys: [None(Char('T'))] }, command: SwitchTheme }, Keymap { key_sequence: KeySequence { keys: [None(Char('D'))] }, command: SwitchDevice }, Keymap { key_sequence: KeySequence { keys: [None(Char('u')), None(Char('p'))] }, command: BrowseUserPlaylists }, Keymap { key_sequence: KeySequence { keys: [None(Char('u')), None(Char('a'))] }, command: BrowseUserFollowedArtists }, Keymap { key_sequence: KeySequence { keys: [None(Char('u')), None(Char('A'))] }, command: BrowseUserSavedAlbums }, Keymap { key_sequence: KeySequence { keys: [None(Char('g')), None(Char(' '))] }, command: CurrentlyPlayingContextPage }, Keymap { key_sequence: KeySequence { keys: [None(Char('g')), None(Char('t'))] }, command: TopTrackPage }, Keymap { key_sequence: KeySequence { keys: [None(Char('g')), None(Char('r'))] }, command: RecentlyPlayedTrackPage }, Keymap { key_sequence: KeySequence { keys: [None(Char('g')), None(Char('y'))] }, command: LikedTrackPage }, Keymap { key_sequence: KeySequence { keys: [None(Char('g')), None(Char('l'))] }, command: LibraryPage }, Keymap { key_sequence: KeySequence { keys: [None(Char('g')), None(Char('s'))] }, command: SearchPage }, Keymap { key_sequence: KeySequence { keys: [None(Backspace)] }, command: PreviousPage }, Keymap { key_sequence: KeySequence { keys: [Ctrl(Char('q'))] }, command: PreviousPage }, Keymap { key_sequence: KeySequence { keys: [None(Char('?'))] }, command: OpenCommandHelp }, Keymap { key_sequence: KeySequence { keys: [Ctrl(Char('h'))] }, command: OpenCommandHelp }, Keymap { key_sequence: KeySequence { keys: [None(Char('q'))] }, command: Quit }, Keymap { key_sequence: KeySequence { keys: [Ctrl(Char('c'))] }, command: Quit }, Keymap { key_sequence: KeySequence { keys: [None(Esc)] }, command: ClosePopup }, Keymap { key_sequence: KeySequence { keys: [None(Char('j'))] }, command: SelectNextOrScrollDown }, Keymap { key_sequence: KeySequence { keys: [Ctrl(Char('n'))] }, command: SelectNextOrScrollDown }, Keymap { key_sequence: KeySequence { keys: [None(Down)] }, command: SelectNextOrScrollDown }, Keymap { key_sequence: KeySequence { keys: [None(Char('k'))] }, command: SelectPreviousOrScrollUp }, Keymap { key_sequence: KeySequence { keys: [Ctrl(Char('p'))] }, command: SelectPreviousOrScrollUp }, Keymap { key_sequence: KeySequence { keys: [None(Up)] }, command: SelectPreviousOrScrollUp }, Keymap { key_sequence: KeySequence { keys: [None(Char('s')), None(Char('t'))] }, command: SortTrackByTitle }, Keymap { key_sequence: KeySequence { keys: [None(Char('s')), None(Char('a'))] }, command: SortTrackByArtists }, Keymap { key_sequence: KeySequence { keys: [None(Char('s')), None(Char('A'))] }, command: SortTrackByAlbum }, Keymap { key_sequence: KeySequence { keys: [None(Char('s')), None(Char('d'))] }, command: SortTrackByDuration }, Keymap { key_sequence: KeySequence { keys: [None(Char('s')), None(Char('D'))] }, command: SortTrackByAddedDate }, Keymap { key_sequence: KeySequence { keys: [None(Char('s')), None(Char('r'))] }, command: ReverseTrackOrder }] }
    2022-06-19T17:44:07.587468Z  INFO spotify_player::auth: Use the cached credentials
    2022-06-19T17:44:07.603639Z  INFO spotify_player::token: Getting new authentication token...
    2022-06-19T17:44:07.749257Z  INFO spotify_player::token: Got new token: Token { access_token: "BQD6l3udfWGDBd6agpCCnvsjD9h7_fI7TPv_s4DJlesyV7xyBO4jhssN-GVhJAAA47Id32fIo3RnD0oynlh4nehCU4FFg1yn5KI9WdzEPBuieTy8y8P9XDUbcFNgcWnfVHIb-IdAPsPPHnrnCARjKzj9314WV-8nNMuKIj2MSegi0ak0YXjkQw1sctapoqyuPmpfXXq8W100DPh8OKJGLa1sihzdvXSUIEgJzMf72Jrop4tuoONfL2XDooRqXdqzxUo6uB2NOOqxHDiFPvZ6qgR8PPaujaTh5ScKhCnzkhbkwYXMegILLWc", expires_in: Duration { secs: 3600, nanos: 0 }, expires_at: Some(2022-06-19T18:44:07.749255155Z), refresh_token: None, scopes: {} }
    2022-06-19T17:44:07.749285Z  INFO spotify_player::streaming: Application's connect configurations: ConnectConfig { name: "spotify-player", device_type: Speaker, initial_volume: Some(65535), has_volume_ctrl: true, autoplay: false }
    2022-06-19T17:44:07.749301Z  INFO spotify_player::streaming: Initializing a new integrated player with device_id=bec59faf-81e9-45c2-bd89-7d198649c74a
    2022-06-19T17:44:07.749346Z  INFO spotify_player::streaming: Starting an integrated Spotify player using librespot's spirc protocol
    2022-06-19T17:44:07.888671Z  INFO spotify_player: No playing device found on startup, trying to connect to an available device
    2022-06-19T17:44:07.953870Z  INFO spotify_player::client: Available devices: [Device { id: Some("53151708a54fdc8c7022f0469236644793d75e83"), is_active: false, is_private_session: false, is_restricted: false, name: "SONY KD-65XH9096", _type: Tv, volume_percent: Some(0) }, Device { id: Some("9508fd4e797ec74f0e569750c492d42f3764b108"), is_active: false, is_private_session: false, is_restricted: false, name: "Denon AVR-X1300W", _type: Avr, volume_percent: Some(50) }, Device { id: Some("bec59faf-81e9-45c2-bd89-7d198649c74a"), is_active: false, is_private_session: false, is_restricted: false, name: "spotify-player", _type: Speaker, volume_percent: Some(100) }, Device { id: Some("db7508f61a6fe30e1de35a21a26e08469058a872"), is_active: false, is_private_session: false, is_restricted: false, name: "Maciej's 2nd Fire TV", _type: Tv, volume_percent: Some(100) }]
    2022-06-19T17:44:07.953890Z  INFO spotify_player::client: Found an available device: Device { id: Some("bec59faf-81e9-45c2-bd89-7d198649c74a"), is_active: false, is_private_session: false, is_restricted: false, name: "spotify-player", _type: Speaker, volume_percent: Some(100) }
    2022-06-19T17:44:07.954171Z  INFO spotify_player::media_control: Initializing application's media control event watcher...
    2022-06-19T17:44:08.004573Z  INFO spotify_player::streaming: Got an event from the integrated player: VolumeSet { volume: 65535 }
    2022-06-19T17:44:08.104388Z  INFO Client_request{request=GetCurrentUser}: spotify_player::client: successfully handled the client request, took: 149ms
    2022-06-19T17:44:08.113469Z  INFO Client_request{request=GetCurrentPlayback}: spotify_player::client: successfully handled the client request, took: 159ms
    2022-06-19T17:44:08.118630Z  INFO Client_request{request=GetUserFollowedArtists}: spotify_player::client: successfully handled the client request, took: 164ms
    2022-06-19T17:44:08.161509Z  INFO Client_request{request=GetCurrentPlayback}: spotify_player::client: successfully handled the client request, took: 156ms
    2022-06-19T17:44:08.184191Z  INFO spotify_player::streaming: Got an event from the integrated player: Started { play_request_id: 0, track_id: SpotifyId { id: 266562458141538119225433542773929850682, audio_type: Track }, position_ms: 80189 }
    2022-06-19T17:44:08.184203Z  INFO spotify_player::streaming: Got an event from the integrated player: Loading { play_request_id: 0, track_id: SpotifyId { id: 266562458141538119225433542773929850682, audio_type: Track }, position_ms: 80189 }
    2022-06-19T17:44:08.185875Z  INFO Client_request{request=GetUserPlaylists}: spotify_player::client: successfully handled the client request, took: 231ms
    2022-06-19T17:44:08.187375Z  INFO Client_request{request=Player(TransferPlayback("bec59faf-81e9-45c2-bd89-7d198649c74a", false))}: spotify_player::client: Transfered the playback to device with bec59faf-81e9-45c2-bd89-7d198649c74a id
    2022-06-19T17:44:08.187386Z  INFO Client_request{request=Player(TransferPlayback("bec59faf-81e9-45c2-bd89-7d198649c74a", false))}: spotify_player::client: successfully handled the client request, took: 233ms
    2022-06-19T17:44:08.212503Z  INFO Client_request{request=GetUserSavedAlbums}: spotify_player::client: successfully handled the client request, took: 257ms
    2022-06-19T17:44:08.291245Z  INFO Client_request{request=GetCurrentPlayback}: spotify_player::client: successfully handled the client request, took: 107ms
    2022-06-19T17:44:08.313411Z  INFO Client_request{request=GetCurrentPlayback}: spotify_player::client: successfully handled the client request, took: 129ms
    2022-06-19T17:44:16.887892Z ERROR Terminal_event{event=Key(KeyEvent { code: Char('s'), modifiers: CONTROL })}: spotify_player::event: Failed to handle event: sending on a closed channel
    2022-06-19T17:44:35.026998Z ERROR Terminal_event{event=Key(KeyEvent { code: Char('D'), modifiers: SHIFT })}: spotify_player::event: Failed to handle event: sending on a closed channel
    
    opened by elkrien 7
  • media-control is not really cross platform

    media-control is not really cross platform

    Hi @aome510

    I've finally enabled the lyric-finder option and built the package locally. It works really well, thanks! I've asked internally if https://genius.com/ is an acceptable source of lyrics or, if we have any license concerns with it. If all is ok, I'll merge an update later enabling this feature.

    As for media-control, it will need to be off and not even possible to enable as an optional build feature for now. Although we do support dbus, souvlaki does not support our OS, according to Cargo-toml,

    [target.'cfg(target_os = "windows")'.dependencies]
    raw-window-handle = "0.3.3"
    
    [target.'cfg(target_os = "windows")'.dependencies.windows]
    version = "0.29.0"
    features = [
        "alloc",
    	"Foundation",
    	"Media",
    	"Win32_Foundation",
    	"Win32_System_WinRT",
    	"Storage_Streams",
    ]
    
    [target.'cfg(target_os = "macos")'.dependencies]
    block = "0.1.6"
    cocoa = "0.24.0"
    core-graphics = "0.22.2"
    dispatch = "0.2.0"
    objc = "0.2.7"
    
    [target.'cfg(target_os = "linux")'.dependencies]
    dbus = "0.9.5"
    dbus-crossroads = "0.5.0"
    

    It's probably possible to fix this by simply adding a target definition but, I haven't looked into this yet. Looking forward to the cover feature, the viuer and image crates work on NetBSD and should not be a problem to enable this option.

    Please keep media-control as an optional feature. Thanks

    opened by 0323pin 7
  • Looking for new maintainer for `spotify_player` AUR package

    Looking for new maintainer for `spotify_player` AUR package

    I'm the maintainer of the AUR spotify_player package. However, I'm no longer have access to an Arch machine. I'm looking for a new maintainer for this package.

    Anyone if interested, please reply to this issue.

    help wanted 
    opened by aome510 7
  • Prepare for `v0.5.0` release

    Prepare for `v0.5.0` release

    spotify-player has changed a lot since the version v0.1.0.

    As the application has gradually become quite usable, v0.5.0 is going to be the release to be announced on public forums such as HN and Reddit.

    To prepare for this release, things probably need to do:

    • [x] add a file logger.
    • [x] add a library page and use it as the welcoming page.
    • [x] handle playback change events not from interactions with the application's integrated client but from interactions with other clients through Spotify connect.
    • [x] improve README and documentations in general. Add a new demo/examples for v0.5.0-pre-release.
    enhancement 
    opened by aome510 7
  • Release `v0.3.0`

    Release `v0.3.0`

    TODO List for v0.3.0

    • [x] improve search page usability
    • [x] add scroll shortcuts for the shortcut help page (#11)
    • [x] clean up event handler codes (#12)

    Background

    Hi,

    I couldn't wait for a new release to try the search functionality, so I've built the software from the git-HEAD on my NetBSD system.

    I'm having trouble using the search function on my keyboard layout, though. "g / " is an easy shortcut on an us keyboard but, on a Swedish keyboard it's kind of hard as " / " needs a modifier and " g Shift 7 " doesn't do it.

    Yes, "Shift 7" outputs " / " on my keyboard.

    Guess, I can define custom key-bindings but, I haven't done that yet and thought I'd let you know anyway.

    Regards, [email protected]

    opened by 0323pin 7
  • [Feature request] Artist / album / track radio

    [Feature request] Artist / album / track radio

    Hi,

    really love the client. However, I really miss the ability to play artist / album / track radios. To me these are really one of the top spotify features, and it would be nice if these could be added.

    Thanks!

    enhancement 
    opened by tobiasrenkin 5
  • Add sharing functionality

    Add sharing functionality

    A way to copy a link to both currently playing & currently selected track/album/artist/etc(podcast support?) would be nice. Maybe keybinds or adding the option to the action menu

    enhancement 
    opened by noelpilled 1
  • Show correct track position on MPRIS

    Show correct track position on MPRIS

    Hi :) It looks like MPRIS always shows the track position as 0, is it possible to output the correct position to MPRIS? image Track position is always a value similar to this.

    bug 
    opened by noelpilled 1
  • very high cpu usage??

    very high cpu usage??

    i have noticed that with spotify_player, it causes the cpu usage to increase and my computer fans ramp up the speed due to the usage.

    image

    what the fuck is spotify_player doing? i'm not even doing anything.

    question 
    opened by wael444 8
  • terminal ansi colors

    terminal ansi colors

    by default, it seems that spotify_player uses it's own colors. for a CLI/TUI application i don't think this is a very good idea. spotify_player should use the terminal's colors - aka ANSI colors.

    enhancement 
    opened by wael444 4
  •  Explicit Albums on Artists Page

    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 global search 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.

    enhancement 
    opened by braheezy 0
  • dynamic config/theme reload?

    dynamic config/theme reload?

    I was wondering if there is a way to have the config/theme of spotify-player reload when the app.toml file is changed? particularly when a theme is changed. I know the SwitchTheme command works great, however if there is any option to repeatedly scan for the theme and update it would be nice

    enhancement 
    opened by Selmer443 3
Releases(v0.10.0)
Owner
Thang Pham
Keep learning... It's never enough
Thang Pham
Client for spotify's apt repository in Rust for Arch Linux

spotify-launcher Spotify has a free linux client but prohibits re-distribution, so this is a freely distributable opensource program that manages a sp

null 93 Jun 20, 2023
policy-driven signing service

SigningService (maybe we'll have a more clever name one day!) What is this? This repo has a little "serverless" (runs on lambda and some other service

null 4 Jul 15, 2022
Make data-driven table rendering easy with Dioxus

Dioxus Table Make data-driven table rendering easy with Dioxus Installation Until the next release of Dioxus this requires Dioxus nightly from git. Th

null 9 Oct 9, 2022
gfold is a CLI-driven application that helps you keep track of multiple Git repositories.

gfold is a CLI-driven application that helps you keep track of multiple Git repositories.

Nick Gerace 215 Jan 4, 2023
Open-source Rust framework for building event-driven live-trading & backtesting systems

Barter Barter is an open-source Rust framework for building event-driven live-trading & backtesting systems. Algorithmic trade with the peace of mind

Barter 157 Feb 18, 2023
Holo is a suite of routing protocols designed to support high-scale and automation-driven networks.

Holo is a suite of routing protocols designed to support high-scale and automation-driven networks. For a description of what a routing protocol is, p

Renato Westphal 42 Apr 16, 2023
A CLI tool to drive test-driven Rust workshops

wr A Rust workshop runner wr is a CLI to drive test-driven workshops written in Rust. It is designed to be used in conjunction with a workshop reposit

Mainmatter 7 Oct 16, 2023
Calculate a player's skill level using Elo, DWZ, Ingo, TrueSkill, Glicko and Glicko-2 algorithms known from their usage in chess and online games.

skillratings Skillratings allows you to calculate the player's skill instantly in 1v1 matches or after tournaments/rating periods with a list of resul

null 10 Dec 30, 2022
Yet another phigros chart player.

prpr - P hig R os P layer, written in R ust Usage To begin with, clone the repo: git clone https://github.com/Mivik/prpr.git && cd prpr For compactnes

Mivik 6 Jan 1, 2023
Intuitive GTK4/LibAdwaita music player

Resonance Harmonize your listening experience with Resonance. Resonance is an intuitive music player application written in Rust & Python, with a clea

Nathanael 25 Apr 7, 2023
A terminal ASCII media player. View images, gifs, videos, webcam, YouTube, etc.. directly in the terminal as ASCII art.

Terminal Media Player View images, videos (files or YouTube links), webcam, etc directly in the terminal as ASCII. All images you see below are just m

Max Curzi 36 May 8, 2023
Media player with Youtube search, download, and playback functionality.

Pomelo 0.2.0 Pomelo is a desktop media player with Youtube search, playback, and download functionality. Current features Play videos locally from the

null 3 Sep 29, 2024
CarLI is a framework for creating single-command and multi-command CLI applications in Rust

CarLI is a framework for creating single-command and multi-command CLI applications in Rust. The framework provides error and IO types better suited for the command line environment, especially in cases where unit testing is needed.

Kevin Herrera 3 Jan 21, 2022
Small command-line tool to switch monitor inputs from command line

swmon Small command-line tool to switch monitor inputs from command line Installation git clone https://github.com/cr1901/swmon cargo install --path .

William D. Jones 5 Aug 20, 2022
REC2 (Rusty External Command and Control) is client and server tool allowing auditor to execute command from VirusTotal and Mastodon APIs written in Rust. 🦀

Information: REC2 is an old personal project (early 2023) that I didn't continue development on. It's part of a list of projects that helped me to lea

Quentin Texier (g0h4n) 104 Oct 7, 2023
Pink is a command-line tool inspired by the Unix man command.

Pink is a command-line tool inspired by the Unix man command. It displays custom-formatted text pages in the terminal using a subset of HTML-like tags.

null 3 Nov 2, 2023
A full featured, fast Command Line Argument Parser for Rust

clap Command Line Argument Parser for Rust It is a simple-to-use, efficient, and full-featured library for parsing command line arguments and subcomma

null 10.4k Jan 10, 2023
Docopt for Rust (command line argument parser).

THIS CRATE IS UNMAINTAINED This crate is unlikely to see significant future evolution. The primary reason to choose this crate for a new project is if

null 743 Jan 1, 2023
Parse command line arguments by defining a struct.

StructOpt Parse command line arguments by defining a struct. It combines clap with custom derive. Documentation Find it on Docs.rs. You can also check

Guillaume P. 2.6k Jan 5, 2023