Files
spotifast/Cargo.toml
T

217 lines
11 KiB
TOML

[package]
# Keep the Cargo package identity for existing cargo-install users.
name = "fastpotify"
default-run = "spotifast"
version = "0.8.0"
edition = "2024"
rust-version = "1.95"
license = "MIT"
description = "A native Spotify client"
repository = "https://github.com/crmne/spotifast"
keywords = ["spotify", "music", "egui", "librespot", "player"]
categories = ["multimedia::audio"]
[lib]
name = "fastpotify"
path = "src/lib.rs"
[[bin]]
name = "spotifast"
path = "src/spotifast.rs"
# Compatibility command for scripts and the updater in earlier releases.
[[bin]]
name = "fastpotify"
path = "src/main.rs"
[dependencies]
anyhow = "1"
thiserror = "2"
clap = { version = "4.5", features = ["derive"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
log = "0.4"
env_logger = { version = "0.11", default-features = false, features = ["auto-color", "humantime"] }
directories = "6"
# A small translation trait for catalogs generated from PO files at build time.
# No system libintl, global locale, or runtime catalog parsing is needed.
tr = { version = "0.1.11", default-features = false }
# One protected-store API, with only each target's native provider below.
# Durable Spotify grants must not be copied into ordinary state JSON.
keyring-core = "1"
# The whole UI. glow keeps the binary and the dependency tree small; wgpu is
# not needed for a 2D music client.
# AccessKit connects egui's control names, states, and actions to native screen readers.
eframe = { version = "0.36", default-features = false, features = ["accesskit", "glow", "default_fonts", "links", "wayland", "x11", "persistence"] }
egui = "0.36"
egui_extras = { version = "0.36", features = ["image", "svg"] }
# Reading what a system font covers, so the app can borrow a face for a script
# Inter cannot draw. skrifa is the parser epaint already rasterizes with, and
# the version has to track epaint's or the binary compiles two copies of it;
# memmap2 keeps the probe to the few pages of each font that answer the
# question.
skrifa = "0.44"
memmap2 = "0.9"
# bmp is for Winamp skins, whose bitmaps are BMP files.
image = { version = "0.25", default-features = false, features = ["jpeg", "png", "bmp"] }
# Inflating the zip a Winamp skin comes as (src/skin/zip.rs). Already
# compiled for reqwest's gzip support, so this adds no code to the build.
flate2 = "1"
# Filling glyph outlines with no anti-aliasing for the Winamp playlist's
# text (src/ui/winamp/pixel_text.rs). Already compiled for the SVG icons
# through egui_extras and resvg, so this adds no code to the build.
tiny-skia = "0.11"
# MilkDrop, as libprojectM reimplements it, for the MilkDrop window
# (src/milkdrop.rs). Built into the binary, so it stays one file.
projectm-sys = { version = "1.2.2", default-features = false, features = ["static"], optional = true }
# The MilkDrop window runs as a child process with its own winit event loop
# and OpenGL context (src/milkdrop/child.rs), because winit allows one event
# loop per process and eframe owns the app's. These are the same versions
# eframe already pulls in, so they add no build. Only compiled with the
# milkdrop feature.
winit = { version = "0.30", optional = true }
glutin = { version = "0.32", optional = true }
glutin-winit = { version = "0.5", optional = true }
# Detect the live window backend, including when MilkDrop is disabled.
# eframe already compiles this crate.
raw-window-handle = "0.6"
# Spotify playback and Connect. rustls everywhere so the client links one TLS
# stack and builds without OpenSSL on every platform.
#
# librespot-core depends on hyper-proxy2 for HTTP proxy support, whose only
# published release (0.1.0) pins rustls 0.22 and so drags in rustls-webpki
# 0.102, which carries advisories against its CRL and name-constraint
# handling. Spotifast never configures a proxy (SessionConfig.proxy stays
# None), so that TLS client is compiled in but never used to verify anything.
# Every connection this app actually makes (the Web API through reqwest, and
# librespot's own sessions) goes through rustls 0.23 with a patched
# rustls-webpki. Removing the old copy needs a release of hyper-proxy2, or a
# librespot that stops depending on it.
librespot-core = { version = "0.8", default-features = false, features = ["rustls-tls-native-roots"] }
librespot-playback = { version = "0.8", default-features = false, features = ["rodio-backend", "rustls-tls-native-roots"] }
librespot-connect = { version = "0.8", default-features = false }
librespot-metadata = { version = "0.8", default-features = false }
librespot-protocol = { version = "0.8", default-features = false }
# Parses the rootlist's playlist4 protobuf, the same crate librespot generates with.
protobuf = "3"
# Local playback's audio sink is this crate's own (src/sink.rs): librespot's
# rodio backend unwraps the device open on the player thread, and a release
# build aborts on panic. Same rodio and cpal versions librespot-playback uses,
# so nothing new is compiled.
rodio = { version = "0.21", default-features = false, features = ["playback"] }
cpal = "0.16"
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-native-roots", "json", "gzip", "http2", "blocking"] }
# `fs` is used by the playlist cache in `backend.rs`. On Linux the
# mpris-server dependency happens to turn it on, which is why leaving it out
# built there and nowhere else.
tokio = { version = "1", features = ["rt-multi-thread", "sync", "time", "macros", "fs"] }
sha1 = "0.10"
sha2 = "0.10"
base64 = "0.22"
rand = "0.9"
open = "5"
percent-encoding = "2"
urlencoding = "2"
jiff = "0.2"
mdns-sd = "0.21"
unicode-bidi = "0.3"
hmac = "0.12"
pbkdf2 = "0.12"
aes = "0.8"
ctr = "0.9"
[target.'cfg(not(target_os = "linux"))'.dependencies]
# The tray item and the desktop's media controls on Windows and macOS, so
# closing the window keeps the music playing there too. Linux has ksni and
# mpris-server below.
tray-icon = { version = "0.24", default-features = false }
souvlaki = { version = "0.8", default-features = false }
[target.'cfg(target_os = "macos")'.dependencies]
apple-native-keyring-store = { version = "1.0.2", features = ["keychain"] }
# Serving AppKit while no window exists: the status item and Dock reopen
# callback live on the main thread.
objc2 = "0.6"
objc2-app-kit = { version = "0.3", default-features = false, features = ["std", "NSApplication", "NSEvent", "NSMenu", "NSMenuItem", "NSResponder", "NSRunningApplication"] }
# NSAppleEventManager and NSAppleEventDescriptor carry the Spotify links
# macOS hands an app registered for the scheme (src/mac_links.rs).
objc2-foundation = { version = "0.3", default-features = false, features = ["std", "NSAppleEventDescriptor", "NSAppleEventManager", "NSDate", "NSObjCRuntime", "NSRunLoop", "NSString"] }
[target.'cfg(windows)'.dependencies]
windows-native-keyring-store = { version = "1.1", default-features = false }
# A hidden window for the media controls to belong to, and message loops.
windows-sys = { version = "0.60", features = ["Win32_Foundation", "Win32_Globalization", "Win32_Graphics_Gdi", "Win32_Storage_FileSystem", "Win32_System_Com", "Win32_System_LibraryLoader", "Win32_System_Registry", "Win32_System_Threading", "Win32_UI_Accessibility", "Win32_UI_HiDpi", "Win32_UI_Shell", "Win32_UI_WindowsAndMessaging"] }
[target.'cfg(target_os = "linux")'.dependencies]
# Reuses the zbus/Tokio stack already used for desktop integration.
zbus-secret-service-keyring-store = { version = "1.0.1", features = ["rt-tokio-crypto-rust"] }
ksni = { version = "0.3", features = ["blocking"] }
librespot-playback = { version = "0.8", default-features = false, features = ["rodio-backend", "pulseaudio-backend", "rustls-tls-native-roots"] }
mpris-server = { version = "0.10", features = ["tokio"] }
# The bus mpris-server already speaks, named directly so its interface macro
# resolves: the running instance answers `Open` on its own name for the
# launch a Spotify link makes (src/single_instance.rs). Same version, so
# nothing new is compiled.
zbus = { version = "5", default-features = false, features = ["tokio"] }
[build-dependencies]
# Validate/filter unfinished PO entries, then compile catalog text and gettext
# plural expressions to Rust. Ordinary builds do not need gettext tools.
polib = "0.3"
include-po = "0.2"
[dev-dependencies]
# Exercise the same PO compiler used by build.rs with partial catalogs.
polib = "0.3"
# The icon and version information Windows shows for the executable.
[target.'cfg(windows)'.build-dependencies]
winresource = "0.1"
[features]
default = ["milkdrop"]
# Sample data and screenshot flags; never part of a release build.
demo = []
# MilkDrop, through libprojectM: a C++ library that CMake builds into the
# binary at compile time, so building needs cmake, a C++ compiler, and
# libclang. `--no-default-features` leaves it out.
milkdrop = ["dep:projectm-sys", "dep:winit", "dep:glutin", "dep:glutin-winit"]
[profile.release]
lto = "thin"
codegen-units = 1
strip = true
panic = "abort"
# Audio decoding and immediate-mode layout are too slow at opt-level 0 to
# audition the app in development. Keep every dependency optimized while the
# application crate itself stays incremental.
[profile.dev.package."*"]
opt-level = 2
# projectm-sys names the library it links after Rust's profile (a `d` suffix
# for dev) but CMake names what it builds after the optimisation level, so an
# optimised dev build would look for a library that was never made. A debug
# build of libprojectM is fine to develop against; releases are optimised.
[profile.dev.package.projectm-sys]
opt-level = 0
# projectm-sys 1.2.2 hardcodes the Visual Studio 17 2022 CMake generator,
# which GitHub's windows-latest images no longer carry; the fork lets an
# explicit CMAKE_GENERATOR win. Drop when upstream takes the change.
[patch.crates-io]
projectm-sys = { git = "https://github.com/crmne/projectm-rs", branch = "respect-cmake-generator" }
# librespot 0.8.0 plus the small patches Spotifast needs: queue controls,
# normalisation-factor reporting for the visualisers, and a distinct event
# when Spotify refuses an audio key, bounded socket setup with DNS address
# fallback, plus an in-memory credential cache for platform storage.
# Every librespot crate comes from the
# fork so one copy exists. Drop patches as upstream takes them.
librespot-audio = { git = "https://github.com/crmne/librespot", branch = "fastpotify-0.8" }
librespot-connect = { git = "https://github.com/crmne/librespot", branch = "fastpotify-0.8" }
librespot-core = { git = "https://github.com/crmne/librespot", branch = "fastpotify-0.8" }
librespot-metadata = { git = "https://github.com/crmne/librespot", branch = "fastpotify-0.8" }
librespot-oauth = { git = "https://github.com/crmne/librespot", branch = "fastpotify-0.8" }
librespot-playback = { git = "https://github.com/crmne/librespot", branch = "fastpotify-0.8" }
librespot-protocol = { git = "https://github.com/crmne/librespot", branch = "fastpotify-0.8" }