mirror of
https://github.com/Felitendo/spotifast.git
synced 2026-11-01 17:33:26 +01:00
Restore the mini player position and clear inherited fullscreen and maximized state. Keep eframe from reading or overwriting the main window geometry for a mini-player window. Keep shade settings unchanged. Cover the view round trip and window persistence policy. Verified native X11 startup and preserved main-window storage; Wayland placement remains compositor-controlled. Refs #326
320 lines
14 KiB
Markdown
320 lines
14 KiB
Markdown
# Fastpotify
|
||
|
||
**Spotify, native and fast.** Fastpotify is a Spotify client written in
|
||
Rust with [egui](https://github.com/emilk/egui). It plays music through
|
||
[librespot](https://github.com/librespot-org/librespot). It typically uses
|
||
100–250 MB of RAM, while Spotify's desktop app often uses 600 MB to over 1 GB.
|
||
It runs on Linux, macOS, and Windows, starts in well under a second, and has no
|
||
browser engine.
|
||
|
||
**Playback needs Spotify Premium.** Free accounts can browse and search, but
|
||
cannot play music through Fastpotify on this computer or another device.
|
||
|
||

|
||
|
||
See [fastpotify.rocks](https://fastpotify.rocks/) for installation, setup,
|
||
everyday use, and connection details.
|
||
|
||
## What it does
|
||
|
||
- **Plays music on this computer.** Fastpotify appears as a Spotify Connect
|
||
device. Select it from your phone or play music in the app. Playback is
|
||
gapless and supports up to 320 kbps, with
|
||
optional volume normalisation and an on-disk audio cache.
|
||
Stalled Spotify connections time out after five seconds per attempt so
|
||
playback can try another endpoint.
|
||
- **Controls other devices.** Move playback to a speaker, a phone, or
|
||
another computer from the device picker, and keep controlling it: play,
|
||
pause, skip, seek, shuffle, repeat, volume.
|
||
- **Finds speakers on your network.** Fastpotify finds librespot, spotifyd,
|
||
and supported hardware receivers over mDNS. Once connected, they appear as
|
||
Spotify Connect devices.
|
||
- **Library.** Browse playlists, Liked Songs, saved albums, followed artists,
|
||
podcasts, and saved episodes. Filter, pin, and reorder sidebar items.
|
||
- **Search** across songs, artists, albums, playlists, podcasts, and episodes,
|
||
with a top result and per-type views.
|
||
- **Home** with Made for you, Recently played, your top artists and songs, and
|
||
recommendations.
|
||
- **Artist pages** with popular songs, a filterable discography, and related
|
||
artists. **Album**, **playlist**, and **podcast** pages support playback
|
||
from any row.
|
||
- **Edit your playlists.** Create, rename, describe, reorder, and delete them.
|
||
Add songs from a row menu, or drag a row or the currently playing song to a
|
||
playlist in the sidebar. A playlist a friend shared with you takes songs too,
|
||
as Spotify's own apps allow.
|
||
- **Opens Spotify links.** Fastpotify registers for `spotify:` links, so a
|
||
song, album, artist, playlist, or podcast shared from another app opens
|
||
in it, whether it is running or not. `open.spotify.com` addresses go
|
||
through the browser, which hands them to the same handler.
|
||
- **Queue** as a side panel or a page; add anything to it from a row menu.
|
||
- **Resumes the last session.** On startup, the last song is paused where it
|
||
stopped. Play resumes it, and the other playback controls work before it
|
||
starts.
|
||
- **Album-art colour.** Pages and the player bar take a tint from the cover
|
||
of what you are looking at or listening to. Turn it off in Settings.
|
||
- **Light and dark**, or follow the system.
|
||
- **Winamp mini player.** `Ctrl+M` opens a small player for classic `.wsz`
|
||
skins, drawn at 1x to 4x scale. It includes a spectrum analyser, playlist,
|
||
and equalizer. It keeps its shade mode and, where the desktop permits,
|
||
its own position when switching views. Drop a skin from the
|
||
[Winamp Skin Museum](https://skins.webamp.org) on either window to add it.
|
||
|
||

|
||
- **Equalizer.** Winamp's ten bands and presets over the music played on
|
||
this computer, in Settings and in the skin.
|
||
- **MilkDrop.** The visualiser, powered by
|
||
[projectM](https://github.com/projectM-visualizer/projectm), runs in its own
|
||
window and process. It supports fullscreen and automatically downloads more
|
||
than 10,000 `.milk` presets on first use (about 26 MB).
|
||
|
||
https://github.com/user-attachments/assets/12b31312-0e0c-4b34-9383-e8c66aabc58d
|
||
- **Keyboard-first.** Every common action has a shortcut (`Ctrl+/` or `?` lists
|
||
them).
|
||
- **Keeps playing when you close the window.** Fastpotify stays in the system
|
||
tray. Use the tray icon or media controls to reopen it, and quit from the
|
||
tray menu or with `Ctrl+Q`. You can make the close button quit in Settings.
|
||
On macOS, the Dock icon also reopens the window.
|
||
- **Visible network activity.** Pages show a spinner while loading. The top
|
||
bar also shows slow or rate-limited Spotify requests.
|
||
- **One instance.** Launching it again brings the existing window forward
|
||
instead of starting a second copy, on every platform.
|
||
- **Desktop integration.** MPRIS on Linux, so media keys, the shell, and
|
||
`playerctl` see Fastpotify like any other player. On macOS and Windows,
|
||
`fastpotify next` and its siblings drive the running app from a terminal,
|
||
a launcher, or a hotkey.
|
||
|
||
## Install
|
||
|
||
On Arch Linux, Fastpotify is in the AUR:
|
||
|
||
```bash
|
||
yay -S fastpotify-bin # the released build, ready made
|
||
yay -S fastpotify # the release, built from source
|
||
yay -S fastpotify-git # built from the latest commit
|
||
```
|
||
|
||
On macOS, with [Homebrew](https://brew.sh):
|
||
|
||
```sh
|
||
brew install --cask crmne/tap/fastpotify
|
||
```
|
||
|
||
Everywhere else, build the single binary with Rust 1.95 or newer:
|
||
|
||
```bash
|
||
cargo install --path . --locked
|
||
```
|
||
|
||
MilkDrop uses libprojectM, which is built from source. This needs CMake, a C++
|
||
compiler, and libclang. To build without MilkDrop or those tools, run
|
||
`cargo install --path . --locked --no-default-features`. On Linux, you also need the
|
||
development packages for ALSA, PulseAudio or PipeWire, and the windowing
|
||
libraries. On Arch:
|
||
|
||
```bash
|
||
sudo pacman -S --needed alsa-lib libpulse libxkbcommon wayland cmake clang
|
||
```
|
||
|
||
and on Debian or Ubuntu:
|
||
|
||
```bash
|
||
sudo apt install libasound2-dev libpulse-dev libxkbcommon-dev libwayland-dev \
|
||
cmake clang libclang-dev
|
||
```
|
||
|
||
and on Fedora:
|
||
|
||
```bash
|
||
sudo dnf install alsa-lib-devel pulseaudio-libs-devel libxkbcommon-devel \
|
||
wayland-devel cmake clang libclang-devel
|
||
```
|
||
|
||
On Windows, libprojectM is built with Visual Studio 2022, CMake, LLVM, and
|
||
vcpkg (`vcpkg install glew:x64-windows-static`, with
|
||
`VCPKG_INSTALLATION_ROOT` pointing at the vcpkg folder).
|
||
|
||
With [Nix](https://nixos.org), `nix develop` provides all of it, along with
|
||
the exact toolchain `rust-toolchain.toml` pins.
|
||
|
||
On macOS, the flake also exposes `packages.<system>.fastpotify-app`, an
|
||
ad-hoc signed `Fastpotify.app` bundle for the Dock, Launch Services, and
|
||
`spotify:` links. With nix-darwin, add it to `environment.systemPackages`
|
||
and link `"/Applications"` through `environment.pathsToLink`; with Home
|
||
Manager, `home.packages` is enough, as its darwin support links the bundle
|
||
into `~/Applications`.
|
||
|
||
Fastpotify uses system fonts for scripts not covered by its interface font,
|
||
including Chinese, Japanese, Korean, Arabic, Hebrew, Thai, and Indic scripts.
|
||
On macOS it draws each of them with the face the system itself uses, in the
|
||
language order set in System Settings, so Chinese titles follow the
|
||
Traditional or Simplified preference set there. Windows includes common
|
||
fonts. On Linux, install `noto-fonts` and `noto-fonts-cjk` (Arch) or
|
||
`fonts-noto` and `fonts-noto-cjk` (Debian or Ubuntu) if titles appear as
|
||
empty boxes.
|
||
|
||
A desktop entry is provided in `packaging/applications/fastpotify.desktop`.
|
||
It registers Fastpotify for `spotify:` links; `xdg-mime default
|
||
fastpotify.desktop x-scheme-handler/spotify` makes it the one the desktop
|
||
uses when another Spotify client is installed too.
|
||
|
||
## Sign in
|
||
|
||
Press **Sign in with Spotify**. Your browser opens Spotify's consent page
|
||
(Authorization Code with PKCE), so Fastpotify never sees your password. The
|
||
app stores a refresh token in the platform's state directory
|
||
(`~/.local/state/fastpotify` on Linux). You usually sign in once per machine.
|
||
|
||
Playing music **on this computer** needs a second, one-time browser approval.
|
||
Spotify handles streaming separately from library access. Start it from the
|
||
device menu (**Set up playback here**) or Settings. It needs Spotify
|
||
Premium, and librespot stores a reusable credential for later sessions.
|
||
|
||
The Web API uses a shared app by default. You can add a personal Spotify
|
||
Development Mode app in Settings → Account for a separate quota. Fastpotify
|
||
still uses the shared app for requests that personal apps do not support. If
|
||
Spotify stays busy and no personal app is configured, Fastpotify points you to
|
||
that setting at most once a day.
|
||
|
||
## Account safety
|
||
|
||
We are not aware of a Spotify account being suspended for using Fastpotify
|
||
or another librespot player with Premium. Sign-in happens on Spotify's own
|
||
pages, audio uses the quality included with Premium, DRM stays intact, and
|
||
Fastpotify does not rip tracks or block ads.
|
||
|
||
Reported suspensions usually involve modded apps that remove ads from free
|
||
accounts, track ripping, or stream manipulation. Fastpotify does none of
|
||
those things, and [CONTRIBUTING.md](CONTRIBUTING.md) prohibits them.
|
||
|
||
## Keyboard shortcuts
|
||
|
||
Hold `Shift` while turning the mouse wheel to scroll horizontal shelves,
|
||
including Made for you and Recently played on Home.
|
||
|
||
The main window exposes named playback controls, library and song rows,
|
||
menus, sliders, and settings switches to screen readers. Use `Tab` and
|
||
`Shift+Tab` to move focus, then `Enter` or `Space` to activate a control or
|
||
play a focused song. Left and right arrows adjust a focused volume or seek
|
||
slider. Windows testing with NVDA and accessibility for Winamp skins are
|
||
still in progress.
|
||
|
||
| Shortcut | What it does |
|
||
| --- | --- |
|
||
| `Space` | Play or pause |
|
||
| `Ctrl+←` / `Ctrl+→` | Previous or next |
|
||
| `Shift+←` / `Shift+→` | Seek 10 seconds |
|
||
| `Ctrl+↑` / `Ctrl+↓` | Volume |
|
||
| `M` | Mute |
|
||
| `B` | Like or unlike the playing song |
|
||
| `S` / `R` | Shuffle / cycle repeat |
|
||
| `Q` | Queue panel |
|
||
| `Ctrl+F` or `/` | Search |
|
||
| `Ctrl+B` | Show or hide the sidebar |
|
||
| `Alt+←` / `Alt+→` | Back or forward |
|
||
| `Ctrl+H` / `Ctrl+L` | Home / Liked Songs |
|
||
| `Ctrl+Shift+A` / `Ctrl+Shift+B` | Playing artist / album |
|
||
| `Ctrl+M` | Winamp mini player |
|
||
| `Ctrl+Shift+K` | MilkDrop |
|
||
| `Ctrl+,` | Settings |
|
||
| `Ctrl+/` or `?` | All shortcuts |
|
||
| `Ctrl+Q` | Quit |
|
||
|
||
On macOS, `Cmd` replaces `Ctrl`.
|
||
|
||
## Controlling it from outside
|
||
|
||
On Linux, Fastpotify is an MPRIS player, so `playerctl --player=fastpotify
|
||
play-pause` already works.
|
||
|
||
macOS and Windows have no such bus, so the same verbs are subcommands. They
|
||
talk to the instance already running and print nothing on success:
|
||
|
||
```
|
||
fastpotify play-pause fastpotify volume 40
|
||
fastpotify play fastpotify volume-up [percent]
|
||
fastpotify pause fastpotify volume-down [percent]
|
||
fastpotify next fastpotify mute
|
||
fastpotify previous fastpotify shuffle [on|off]
|
||
fastpotify seek 15 fastpotify repeat [off|context|track]
|
||
fastpotify seek -- -15 fastpotify like
|
||
fastpotify seek-to 90 fastpotify play-uri spotify:playlist:37i9…
|
||
fastpotify show fastpotify transfer <device-id>
|
||
fastpotify now-playing [--raw] fastpotify devices [--raw]
|
||
```
|
||
|
||
`shuffle` and `repeat` toggle when used without an argument. Pass a state to
|
||
set it directly. `like` adds or removes the playing track from your library.
|
||
|
||
`now-playing` prints one readable line. `--raw` prints tab-separated fields:
|
||
state, title, artists, album, position_ms, duration_ms, volume, shuffle,
|
||
repeat, art_url, saved, and device. `saved` is `yes`, `no`, or `unknown` while
|
||
loading. New fields are appended to keep older scripts working.
|
||
|
||
`devices` lists Spotify Connect devices with the ID first and the active one
|
||
marked with `*`. `--raw` prints JSON. The command refreshes the device list,
|
||
so the first call after startup may be empty. Run it again if needed.
|
||
|
||
A verb exits non-zero when Fastpotify is not running.
|
||
|
||
On every platform, `fastpotify <link>` opens a Spotify link, a `spotify:`
|
||
URI or an `open.spotify.com` address, in the running app, or starts the
|
||
app on it. This is what the desktop runs when a link is clicked.
|
||
|
||
Launchers such as Raycast or Alfred can use these commands. The Stream Deck
|
||
plugin uses the same interface.
|
||
|
||
## Settings
|
||
|
||
Settings live in one readable JSON file (`~/.config/fastpotify/settings.json`
|
||
on Linux). They include the Connect device name, bitrate, normalisation,
|
||
autoplay, gapless playback, the audio backend (PulseAudio/PipeWire or ALSA on
|
||
Linux), audio cache size, theme, sidebar state, whether pages take colour
|
||
from artwork, and the mini player's skin and size.
|
||
Playback settings apply when you press **Apply and restart playback**.
|
||
You can also check for a new release from Settings. On macOS, the same command
|
||
is in the application menu.
|
||
|
||
Caches (audio, artwork) live under the cache directory and can be deleted at
|
||
any time without signing you out.
|
||
|
||
## How it is built
|
||
|
||
- `src/player.rs`: librespot playback, mixing, and Spotify Connect state.
|
||
- `src/api/`: shared and personal Web API sessions, routing, concurrency, and
|
||
rate limits.
|
||
- `src/backend.rs`: the tokio runtime and channels used by the interface.
|
||
- `src/images.rs`: album art loading, caching, and accent-colour extraction.
|
||
- `src/app.rs`, `src/model.rs`, `src/ui/`: state, navigation, and views.
|
||
- `src/mpris.rs`: Linux media controls.
|
||
|
||
Fastpotify pins its Rust toolchain in `rust-toolchain.toml`; `cargo test`
|
||
covers the API models, dual-session routing, PKCE, the player state machine,
|
||
and a headless render of every page, panel, and dialog.
|
||
|
||
To look at the interface without a Spotify account, build with the `demo`
|
||
feature and start it with sample data:
|
||
|
||
```bash
|
||
cargo run --features demo -- --demo --demo-page playlist:pl1 --demo-show queue
|
||
```
|
||
|
||
Demo mode never writes settings. `--demo-shot <PATH>` writes the window to a
|
||
PNG and exits, which is useful for reproducible interface screenshots.
|
||
`--demo-size WIDTHxHEIGHT` sets the window size for that shot.
|
||
|
||
## Contributing
|
||
|
||
Read [CONTRIBUTING.md](CONTRIBUTING.md) before opening an issue or pull
|
||
request. It covers project scope and required checks.
|
||
|
||
## Acknowledgements
|
||
|
||
Fastpotify uses [librespot](https://github.com/librespot-org/librespot),
|
||
[egui](https://github.com/emilk/egui), the [Inter](https://rsms.me/inter/)
|
||
typeface (OFL), and [Lucide](https://lucide.dev) icons (ISC).
|
||
|
||
Fastpotify is an independent project and is not affiliated with Spotify.
|
||
Spotify is a trademark of Spotify AB.
|
||
|
||
Licensed under the [MIT License](LICENSE).
|