Giter VIP home page Giter VIP logo

ncspot's Introduction

ncspot logo

An ncurses Spotify client written in Rust using librespot

Crates.io Gitter

ncspot search tab

ncspot is an ncurses Spotify client written in Rust using librespot. It is heavily inspired by ncurses MPD clients, such as ncmpc. My motivation was to provide a simple and resource friendly alternative to the official client as well as to support platforms that currently don't have a Spotify client, such as the *BSDs.

ncspot only works with a Spotify premium account as it offers features that are not available for free accounts.

Features

  • Support for tracks, albums, playlists, genres, searching...
  • Small resource footprint
  • Support for a lot of platforms
  • Vim keybindings out of the box
  • IPC socket for remote control
  • Automatic authentication using a password manager

Installation

ncspot is available on macOS (Homebrew), Windows (Scoop, WinGet), Linux (native package, Flathub and Snapcraft) and the BSD's. Detailed installation instructions for each platform can be found here.

Configuration

A configuration file can be provided. The default location is ~/.config/ncspot. Detailed configuration information can be found here.

Building

Building ncspot requires a working Rust installation and a Python 3 installation. To compile ncspot, run cargo build. For detailed instructions on building ncspot, there is more information here.

Packaging

Information about provided files, how to generate some of them and current package status accross platforms can be found here.

ncspot's People

Contributors

algon-320 avatar andrewhalle avatar bettehem avatar cardosaum avatar cyqsimon avatar dann-merlin avatar dependabot-preview[bot] avatar dependabot[bot] avatar eprst avatar eulerfan271 avatar felipesere avatar github-actions[bot] avatar h-m-h avatar herbstein avatar hhsnopek avatar hrkfdn avatar inemajo avatar jirutka avatar kemyt avatar koffeinflummi avatar martinbjeldbak avatar medwards avatar mtshrmn avatar osm avatar qluxzz avatar r4v3n6101 avatar rashil2000 avatar rbuch avatar thomasfrans avatar treibholz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ncspot's Issues

Custom location for a cfg file - Building a snap package

Hi there, I'm currently building a snap package for ncspot. I have a successful build, however I need to put the config file in a custom location. RIght now when I run the command I get:

$ ncspot
thread 'main' panicked at 'can't create config folder: Os { code: 2, kind: NotFound, message: "No such file or directory" }', src/libcore/result.rs:997:5
note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.

But with the way snaps work (without classic confinement) I need to use an alternate location.

I also had a peek at ncspot --help and it looks like I cannot use a cli switch to target a different location. Any suggestions?

Thank you.

PS - using the --debug option I was able to see that it was trying to create a folder at /home/dustin/snap/ncspot/x1/.config/ncspot. I manually created that and I could get the login screen, but it was all funky.

ncspot-funk

Ultimately we would "like" it to write to $HOME/snap/ncspot/current/.config/ncspot/. I know some authors add logic to test if the binary is running as a snap and act as needed.

Implement Spotify's Token-based Auth

Spotify docs outline a way to provide auth without the need for the username and password. Using this would remove the need for either the config file or a login screen (as another issue/enhancement has suggested). This method would provide the user with a unique URL and upon accessing this and logging into Spotify the user would be given a token for subsequent auth attempts made by ncspot.

Using this method of auth would make this app more secure, eliminating the need to store credentials in plaintext or exposing credentials to this app at all. It would also remove the need to implement an initial login as suggested here.

Queue: Handle synchronization

Due to the event-based approach and the UI thread being separated from the rest, sometimes the queue view can run out of sync with the queue data.

Steps to reproduce:

  • Add many items to the queue
  • Hold 'd' to delete them

At some point, the UI will have more items than the data model. The next removal call will cause a panic.

The button callback uses the index of the currently selected TrackButton and passes it to queue.remove().

We either need to synchronize the data with the UI quicker or refer to queue entries by unique IDs.

More controls for the currently playing track

Right now there's a lot of options for opening various views for the currently selected track/item. That is useful, but being able to open those same pages for the currently playing track is a definite must imo. It'd be equivalent to clicking the song or band name in the official client.

The ability to add a track (playing or selected) to a playlist is also pretty important.

I'm thinking there should be a common style to this. Taking the sharing as an example: an action mapped to <key> should happen to the currently selected, while Shift-<key> should happen to the currently playing song (if any). Introducing this consistency would reduce overhead of learning two keybinds to do (logically) one action.

I'm not married to the key modifier or which (currently playing or selected) takes the action without the modifier, but a standard should be applied.

Put Cargo.lock into git repository

The program has a lot of dependencies (370 to be exact). It would be great to get everyone on the same page with this file. A package getting updated unexpectedly could lead to diverging behavior. This is especially true when winapi is pulled in as an git repository without being pinned - if there is an api change this binary will seize to build.

It would lead to some annoyance regarding people's own local versions, but I'd argue that small annoyance is alright. I do wonder how the AUR package handles something like that though.

Change queues to playlists

While it seemed like a good idea in the beginning, it might be necessary to move from queues to real playlists. Queues lose their entries during playback, which might be annoying if you want to save them as a playlist later on.

Instead, maybe the current behavior in the search result view should be changed to have Space append them to the playlist and use something like Shift-Space to add the selection at the top of the playlist.

Unnecessary deletion of saved credentials

File with credentials is being deleted in case of failed validation regardless of a reason. For example when client does not have a internet connection, forcing user to re-enter them.

F-keys don't work in Termite (and probably other VTE terminals)

In Termite (a VTE-based terminal emulator), I can't switch tabs with F-keys; ncspot works completely fine in urxvt, though. I'm assuming this has to do with some internals of Cursive, but it might be good to look into; I thought ncspot was broken until I tried a different terminal emulator.

Interestingly, forcing TERM=xterm makes everything work, so it might be terminal feature detection being screwed up?

New libs due to clipboard stuff

New libraries are required after sharing functionality has been merged. The readme should be updated. I'm talking about libxcb-* packages.

Should work with media keys

Official client responds to media keys (play/pause, fast foward, reverse) even when the window doesn't have focus, ideally the same thing could be done here.

Windows linker error on nightly Rust (unresolved external symbol __imp_ExtractIconW referenced in function get_app_icon)

Hey,

It seems like rust std will no longer link to shell32.dll, which is a dependency of pancurses (used through cursive for Windows support).

  = note: libpdcurses-b041d7947661b96d.rlib(pdcscrn.o) : error LNK2019: unresolved external symbol __imp_ExtractIconW referenced in function get_app_icon
          E:\work\repo\ncspot\target\debug\deps\ncspot-545a65ef205f4774.exe : fatal error LNK1120: 1 unresolved externals

Cursive and pancurses will need to be bumped once it has been fixed here:
ihalila/pdcurses-sys#5

A temporary workaround is to add a build.rs in ncspot with the following in it for Windows users:

fn main() {
    println!("cargo:rustc-link-lib=dylib=shell32");
}

License?

Hi,
Is this released under any license please?

Infinitely plays current track (suspend related?)

When coming back from suspend where a song was previously paused, I've noted that the song will play properly and un-pausing it, however when the song finishes the timer will just continue (ie 11:22 / 3:04) silently and not play the next song. It will honour pausing (so it will stop increasing if you "pause") when in this state.

Selecting other songs in the queue will result in the playback indicator updating, but no song will play. Restarting ncspot fixes this behaviour, but obviously resets the queue. I don't see anything notable in the log screen before restarting.

Change playlist saving functionality

I skimmed the new keyboard commands and thought s saved a specific song that was selected in the queue. This is my normal flow (play Discover Weekly for example and add stuff I like).

This resulted in me wiping out a 200+ song playlist.

I'd recommend changing it to add specific tracks to playlists or having a big-ass warning dialog if the playlist already has tracks.

I'm going to QQ somewhere now.

Improve logging facilities

Looking at the logs in the application for debugging is less than ideal. Since we can't log to stdout/stderr, we should probably provide a command line parameter that allows setting a log file.

Queue should remember currently selected item

As Cursive provides no mutable access to ListView entries, the entire list is re-drawn on queue changes, such as the player consuming the next track.

This moves the cursor back to the top. Before redraw, the queue should store the selected entry and restore selection after redrawing the list.

Windows Support

This is a tracking issue at this point.

I just tested after 41164df was commited, and #10 was closed.

Cursive linking and compilation seems to work well now.

The big issue is that right now librespot is configured to use pulseaudio as the backend. And, without fiddling with an MSYS2 installation, I don't think there's any way of making that work on Windows in a satisfactory way. However, it seems librespot want to move away from having their own internal playback implementation, and instead delegate it to the Rodio crate - discussed in librespot-org/librespot#195. This is being done in the librespot-org/librespot#277 pull request, though it seems progress has slowed a bit.

Looking at the main.rs file, I can also tell that you are making some assumptions about there being a $HOME environment variable, which you can't on Windows. Through a quick look around it seems app_dirs is a preferred way to find resource directories.

I didn't see anything else, but there might be some more lurking in there.

Show indicator for followed playlists

It would be really nice to see following playlists. In playlist page (F3) I see only playlists created by me. My humble suggestion is to create 2 tabs just like search page has.

    1. tab: My playlists
    1. tab: Following playlist

Verify login credentials

Currently, login credentials entered in the dialog are not tested before the main application starts.

Ideally, after input ncspot tests if the credentials are correct and then proceeds. If they aren't, repeat by showing the login dialog.

Use a two-queue system like the official clients

The official Spotify clients use, effectively, two queues. The first queue is the general playback queue, which would be what ncspot has now. The second queue is the user-handled queue. This is the queue a song is added to when you press "Add to Queue" in the official clients.

I took a screenshot from the Linux client to illustrate.

The user queue is emptied first, and then the playback queue is used.

It's a feature that is great when you're playing a playlist, but want to hear a specific song next. This could be because you saw it mentioned online, a friend mentioned it, or any other reason.

Running in the background

It would be nice if there was a way to quit while continuing to run it in the background, and having music still play, and then when ran again in the future the TUI would connect to the already running instance. I don't know how feasible this is but I figured it might be worth requesting.

Implement login dialog

Requiring new users to create a configuration themselves is not user-friendly.

Create a dialog asking for Spotify credentials on startup/when login credentials are missing.

Use streaming Futures for search requests

Currently, the search will download all the results in one result and then display them.
For playlists, this means that it will take a long time until the results are displayed.

Instead a Future could yield the downloaded playlist, which can then be displayed immediately while the search is still running.

On a side note, maybe playlists shouldn't be loaded entirely during search?

Question: Testing strategy

I understand this is still (?) a toy project, but I was wondering what the test strategy for it would be,
given that it is mostly "glue" between Spotify and Cursive?

Its fun to hack around, but there is a good chance I'll break something in a way the compiler doesn't catch.

An app like this would be an interesting project to explore how the Rust community factors/refactors/designs code to make it testable und understandable ๐Ÿ˜ƒ

Status bar

A status bar should be displayed at the bottom showing basic information:

  • Currently loaded track
  • Current player state (playing, paused, stopped)
  • Track position and duration

The status bar should be visible all the time.

Last.fm Scrobbling (and now-playing) Support

I thought Spotify now implements scrobbling at an account level, independent of device or client, but maybe I'm wrong, as playing with ncspot (which I'm very excited about, thank you!) doesn't seem to result in scrobbles or now-playing information available to Last.fm.

I don't personally care if ncspot implements scrobbling internally or finds a way to get Spotify servers to do so, but I really need a music player to scrobble one way or another for me to use it.

Arch Linux, installed from AUR ncspot-git 0.0.0.98.3d385af-1

Thanks for this project!

Basic playlist support

Implement loading/saving of playlists. Basic features that we want:

  • As Spotify supports playlist folders, we need a way to hierarchically navigate through folders (maybe with cursive_tree_view?) (the API doesn't offer folder information)
  • Load and display playlists
  • Playlists can be queued
  • Playlists should only be loaded on start-up
  • .. and if explicitly requested by user
  • Cache loaded playlists for next startup. Use snapshot_id field to check if a cached playlist's tracklist needs to be updated.
  • Queues can be saved to playlists
  • Playlists can be deleted

The playlist view should be an extra screen (like Search/Queue).

Implement track button

Currently, selectable tracks (e.g. in search results or the queue) are simple Cursive buttons with key event handlers (return to play, space to queue).

As they should have the same functionality and presentation in the whole app, a re-usable widget class should be implemented.

Surprising delay when playing tracks

The official client starts playing songs immediately, so the delay in this client and lack of any immediate response from the UI gives the impression to a first-time user that the client is broken.

Has anyone looked into removing the delay entirely, or what the official client does that this client doesn't?

Deal with Spotify Web API rate limiting

Users with a lot of playlists that contain a large amount of tracks may encounter rate limits imposed by Spotify.

We should respect the Retry-After header: https://developer.spotify.com/documentation/web-api/#rate-limiting

By quick look it seems that the Spotify Web API crate we use does not handle the 429 response. It does return an Error, though. If that contains the Retry-After header information we can kick off another request once the desired waiting time has passed.

Instructions to build with portaudio backend no longer work

When I use the provided portaudio with a clean cargo environment I get the below output.

error[E0599]: no function or associated item named `default` found for type `cursive::Cursive` in the current scope
   --> src/main.rs:148:32
    |
148 |     let mut cursive = Cursive::default();
    |                       ---------^^^^^^^
    |                       |
    |                       function or associated item not found in `cursive::Cursive`

error[E0599]: no function or associated item named `default` found for type `cursive::Cursive` in the current scope
  --> src/authentication.rs:12:38
   |
12 |     let mut login_cursive = Cursive::default();
   |                             ---------^^^^^^^
   |                             |
   |                             function or associated item not found in `cursive::Cursive`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0599`.
error: Could not compile `ncspot`.

To learn more, run the command again with --verbose.

I don't personally need the backend, but it's worth pointing out.

Renew web API tokens on expiration

Currently, web API tokens expire after 1 hour. This effectively breaks the search after 1 hour of runtime. API tokens need to be renewed and the request retried.

Recreating config dir

Currently on the master (83a394790):

thread 'main' panicked at 'can't create config folder: Os { code: 17, kind: AlreadyExists, message: "File exists" }', src/libcore/result.rs:1009:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.

Track Details View

It would be nice to be able to get some info on the currently playing track such as what album it's from, what year it was released, etc.

Move to strongly typed message passing

Right now the program uses a string-based message-passing system. The primary reasons for this is enabling exhaustive pattern matching, and avoiding having to box and unbox strings internally.

The current command system (e.g. :<command> <args>) slots neatly into the internal messages, which is currently a big plus. But I do think having a small command-translation layer is a small price to pay for otherwise proper internal message passing.

xdg crate is not supported on Windows

The xdg crate is not supported on Windows, and currently results in:

   Compiling ncspot v0.1.0 (E:\work\repo\ncspot)
error[E0433]: failed to resolve: could not find `BaseDirectories` in `xdg`
  --> src\playlists.rs:58:29
   |
58 |         let xdg_dirs = xdg::BaseDirectories::with_prefix("ncspot").unwrap();
   |                             ^^^^^^^^^^^^^^^ could not find `BaseDirectories` in `xdg`

error[E0433]: failed to resolve: could not find `BaseDirectories` in `xdg`
  --> src\playlists.rs:85:29
   |
85 |         let xdg_dirs = xdg::BaseDirectories::with_prefix("ncspot").unwrap();
   |                             ^^^^^^^^^^^^^^^ could not find `BaseDirectories` in `xdg`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0433`.
error: Could not compile `ncspot`.

To learn more, run the command again with --verbose.

This is due to this crate level cfg attribute:
https://github.com/whitequark/rust-xdg/blob/master/src/lib.rs#L1

The directories crate is a portable alternative to this crate:
https://docs.rs/directories/1.0.2/directories/

Can't get back to the search bar

Previously, after a search, I was able to get back to the search text input field by scrolling up or clicking on it, in the latest version (cb753ea), it doesn't seem to be working. It stops at the top of the search results, and doesn't get back into the text field. The only thing that works now is :search Rust Never Sleeps

Config (file)

I would like to kick off the config question where we can put key bindings, credentials, etc.

Are there any plans? Can I humbly vote for INI/Toml config file? I might help with some code.

Doesn't compile with rust 1.32 (which is still the latest on the most distros)

~/w/ncspot ยป cargo build --release                                                                                      101 develop?
   Compiling libdbus-sys v0.1.5
   Compiling cursive v0.11.0
   Compiling dbus v0.6.4
   Compiling ncspot v0.1.0 (/home/n1/workspace/ncspot)
error[E0658]: use of unstable library feature 'duration_as_u128' (see issue #50202)
   --> src/mpris.rs:164:60
    |
164 |                 iter.append(spotify.get_current_progress().as_micros() as i64);
    |                                                            ^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0658`.
error: Could not compile `ncspot`.

To learn more, run the command again with --verbose.

Media keys should mirror `<` and `>` functionality

When you're 50% through a song, pressing the "back" media key goes directly back to the previous track. The < key-bind goes to the beginning of the current song instead, which is the behavior I expect.

undefined symbol in backtrace

  = note: ld.lld: error: undefined symbol: __rbt_backtrace_pcinfo
          >>> referenced by 3lioxd67jyyi3u0x
          >>>               backtrace-36681ee09954db18.3lioxd67jyyi3u0x.rcgu.o:(backtrace::symbolize::resolve::h6724ff679d0bbb6a) in archive /home/e5ten/github/ncspot/target/release/deps/libbacktrace-36681ee09954db18.rlib

          ld.lld: error: undefined symbol: __rbt_backtrace_syminfo
          >>> referenced by 3lioxd67jyyi3u0x
          >>>               backtrace-36681ee09954db18.3lioxd67jyyi3u0x.rcgu.o:(backtrace::symbolize::resolve::h6724ff679d0bbb6a) in archive /home/e5ten/github/ncspot/target/release/deps/libbacktrace-36681ee09954db18.rlib

          ld.lld: error: undefined symbol: __rbt_backtrace_create_state
          >>> referenced by rz4uouepesiu5ut
          >>>               backtrace-36681ee09954db18.rz4uouepesiu5ut.rcgu.o:(std::sync::once::Once::call_once::_$u7b$$u7b$closure$u7d$$u7d$::hb27b51815f1d2917) in archive /home/e5ten/github/ncspot/target/release/deps/libbacktrace-36681ee09954db18.rlib

          ld.lld: error: undefined symbol: __rbt_backtrace_create_state
          >>> referenced by rz4uouepesiu5ut
          >>>               backtrace-36681ee09954db18.rz4uouepesiu5ut.rcgu.o:(core::ops::function::FnOnce::call_once::_$u7b$$u7b$vtable.shim$u7d$$u7d$::h213826a215e2c7b1) in archive /home/e5ten/github/ncspot/target/release/deps/libbacktrace-36681ee09954db18.rlib
          clang-9: error: linker command failed with exit code 1 (use -v to see invocation)


error: aborting due to previous error

error: Could not compile `ncspot`.

To learn more, run the command again with --verbose.

The final link command fails like this, based on an issue in another project with the same symbols I think the means somewhere in the dependency tree a different, incompatible version of backtrace is getting used?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.