mirror of
https://github.com/Felitendo/spotifast.git
synced 2026-11-01 17:33:26 +01:00
Checking for, downloading, verifying and installing an update now go through fastframe-update, configured for Spotifast: its repository and names, Fastpotify's legacy names and Windows location, the macOS bundle ids and renamed executables, and no publisher key until releases are signed (checksums.txt alone, as before). The crate's reqwest transport runs on Spotifast's blocking client with its proxy. fastframe_update::intercept runs first in main: `--apply-update <job>` makes the process the helper, which exits before anything else, and `--update-receipt` and `--update-error` are taken out before clap parses the rest, so the hidden flags leave Cli. The handoff and receipt formats are unchanged (the crate's compat tests read Spotifast 0.10.1's), the update interface and its tests stay, and a new test checks that both commands accept the update flags and that the helper runs before the app. The updater tests of the deleted modules move to the crate. Behaviour changes: - The macOS helper runs from a copy of the whole bundle in the staging folder, not from the installed bundle, so moving and restoring the installed bundle never touches the helper's own code. - A Nix install says "Update this installation with Nix." and a Homebrew one "Update this installation with Homebrew.", where both said "with Nix or Homebrew". - The old portable layout of 0.8.0 and 0.9.0 is no longer recognised in a downloaded archive; no release older than 0.10 can be offered. - Before the Windows setup program left a marker, its current default location Programs/Spotifast/spotifast.exe is recognised as well as Programs/Fastpotify/fastpotify.exe. - The release check runs on the blocking client like the download, with the updater's own headers and redirect rules.
274 lines
16 KiB
TOML
274 lines
16 KiB
TOML
[package]
|
|
name = "spotifast"
|
|
default-run = "spotifast"
|
|
version = "0.10.2"
|
|
edition = "2024"
|
|
rust-version = "1.98"
|
|
license = "MIT"
|
|
description = "A native Spotify client"
|
|
repository = "https://github.com/crmne/spotifast"
|
|
keywords = ["spotify", "music", "egui", "librespot", "player"]
|
|
categories = ["multimedia::audio"]
|
|
|
|
[lib]
|
|
name = "spotifast"
|
|
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"
|
|
directories = "6"
|
|
# 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"] }
|
|
# The shared foundation of Spotifast, ZapFast, RekordFlash and TonePush
|
|
# (crmne/fastframe). Every crate comes from the same revision; move them
|
|
# together.
|
|
fastframe-text = { git = "https://github.com/crmne/fastframe", rev = "81e7d2d310052c360f0827957461da7e4ca80f7c" }
|
|
fastframe-fonts = { git = "https://github.com/crmne/fastframe", rev = "81e7d2d310052c360f0827957461da7e4ca80f7c" }
|
|
fastframe-icons = { git = "https://github.com/crmne/fastframe", rev = "81e7d2d310052c360f0827957461da7e4ca80f7c" }
|
|
fastframe-theme = { git = "https://github.com/crmne/fastframe", rev = "81e7d2d310052c360f0827957461da7e4ca80f7c" }
|
|
# Catalogs compiled from PO files at build time (see build.rs) and the
|
|
# system's preferred languages. No libintl or runtime catalog parsing.
|
|
fastframe-i18n = { git = "https://github.com/crmne/fastframe", rev = "81e7d2d310052c360f0827957461da7e4ca80f7c" }
|
|
# The log file for bug reports and the panic log (env_logger underneath).
|
|
fastframe-log = { git = "https://github.com/crmne/fastframe", rev = "81e7d2d310052c360f0827957461da7e4ca80f7c" }
|
|
# The tray item, so closing the window can keep the music playing:
|
|
# StatusNotifier on Linux, the notification area on Windows, the menu bar
|
|
# on macOS.
|
|
fastframe-tray = { git = "https://github.com/crmne/fastframe", rev = "81e7d2d310052c360f0827957461da7e4ca80f7c" }
|
|
# Keeps the app running without a window around eframe::run_native.
|
|
fastframe-shell = { git = "https://github.com/crmne/fastframe", rev = "81e7d2d310052c360f0827957461da7e4ca80f7c" }
|
|
# The macOS title-bar double-click setting (does nothing elsewhere).
|
|
fastframe-macos = { git = "https://github.com/crmne/fastframe", rev = "81e7d2d310052c360f0827957461da7e4ca80f7c" }
|
|
# Self-update from GitHub releases, on the reqwest client below.
|
|
fastframe-update = { git = "https://github.com/crmne/fastframe", rev = "81e7d2d310052c360f0827957461da7e4ca80f7c", features = ["reqwest"] }
|
|
# Reading installed fonts for MilkDrop's overlays, the Winamp playlist's
|
|
# pixel text, and the playlist face. 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 search for the playlist face
|
|
# to the few pages of each font that name it. fastframe-fonts uses both.
|
|
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. The
|
|
# published 0.1.0 release pins rustls 0.22 / rustls-webpki 0.102; we patch
|
|
# it (see [patch.crates-io]) onto rustls 0.23 so CONNECT-then-TLS uses the
|
|
# same stack as the rest of the client. SOCKS5 still covers the Web API but
|
|
# not the engine: librespot only speaks HTTP CONNECT.
|
|
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"
|
|
# `socks` is SOCKS5 proxy support for the Web API, artwork, lyrics, and
|
|
# update checks. HTTP proxies work without it. `system-proxy` reads the OS
|
|
# proxy on macOS and Windows when the mode is System; Linux uses environment
|
|
# variables either way.
|
|
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-native-roots", "json", "gzip", "http2", "blocking", "socks", "system-proxy"] }
|
|
# Same System-proxy matcher reqwest uses, so local playback follows the same
|
|
# HTTP proxy (environment, and the OS proxy on macOS and Windows).
|
|
hyper-util = { version = "0.1", default-features = false, features = ["client-proxy", "client-proxy-system"] }
|
|
http = "1"
|
|
# `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. `net` is the local HTTP-proxy tests.
|
|
tokio = { version = "1", features = ["rt-multi-thread", "sync", "time", "macros", "fs", "net", "io-util"] }
|
|
sha1 = "0.10"
|
|
sha2 = "0.10"
|
|
base64 = "0.22"
|
|
# Native asynchronous file selection on macOS, Windows and Linux desktop portals.
|
|
rfd = "0.17.2"
|
|
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 desktop's media controls on Windows and macOS, so closing the window
|
|
# keeps the music playing there too. Linux has mpris-server below.
|
|
souvlaki = { version = "0.8", default-features = false }
|
|
|
|
[target.'cfg(target_os = "macos")'.dependencies]
|
|
apple-native-keyring-store = { version = "1.0.2", features = ["keychain"] }
|
|
# The application menus and Dock menu (src/mac_menu.rs). "exception" lets
|
|
# src/mac_touchbar_crash_guard.rs catch a specific AppKit Objective-C
|
|
# exception instead of letting it abort the process.
|
|
objc2 = { version = "0.6", features = ["exception"] }
|
|
objc2-app-kit = { version = "0.3", default-features = false, features = ["std", "NSApplication", "NSEvent", "NSMenu", "NSMenuItem", "NSResponder", "NSRunningApplication", "NSWindow"] }
|
|
# NSAppleEventManager and NSAppleEventDescriptor carry the Spotify links
|
|
# macOS hands an app registered for the scheme (src/mac_links.rs), and
|
|
# NSRunLoop has the delayed perform the title bar uses (src/window.rs).
|
|
objc2-foundation = { version = "0.3", default-features = false, features = ["std", "NSAppleEventDescriptor", "NSAppleEventManager", "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"] }
|
|
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"] }
|
|
# Keeps the X11 mini player out of the taskbar with _NET_WM_STATE_SKIP_TASKBAR
|
|
# (src/window.rs), which winit only offers on Windows. winit already
|
|
# compiles this version.
|
|
x11rb = { version = "0.13", default-features = false }
|
|
|
|
[build-dependencies]
|
|
# Drops unfinished PO entries and compiles catalog text and gettext plural
|
|
# expressions to Rust. Ordinary builds do not need gettext tools.
|
|
fastframe-i18n = { git = "https://github.com/crmne/fastframe", rev = "81e7d2d310052c360f0827957461da7e4ca80f7c", features = ["build"] }
|
|
|
|
[dev-dependencies]
|
|
# Checks that every catalog covers the template and keeps its placeholders.
|
|
polib = "0.3"
|
|
# Run connection-deadline regressions with a virtual clock.
|
|
tokio = { version = "1", features = ["test-util"] }
|
|
|
|
# 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
|
|
|
|
[patch.crates-io]
|
|
# crmne/egui apps-0.36, shared with ZapFast, RekordFlash and TonePush: egui
|
|
# 0.36.1 with right-to-left runs shaped in their bidi direction and digits
|
|
# shaped left to right in text without right-to-left letters
|
|
# (emilk/egui#8577), egui's busy-loop fix (emilk/egui#8398), and eframe pacing
|
|
# Wayland frames by the compositor's frame callbacks so a window the
|
|
# compositor stops showing never blocks in a vsync swap (emilk/egui#8631,
|
|
# #266). Every egui crate comes from the same revision so they share one emath
|
|
# and epaint. Drop this once egui releases all three.
|
|
ecolor = { git = "https://github.com/crmne/egui", rev = "0b431145c22ee27b20b0aff7243d74f4b32e9a79" }
|
|
eframe = { git = "https://github.com/crmne/egui", rev = "0b431145c22ee27b20b0aff7243d74f4b32e9a79" }
|
|
egui = { git = "https://github.com/crmne/egui", rev = "0b431145c22ee27b20b0aff7243d74f4b32e9a79" }
|
|
egui-wgpu = { git = "https://github.com/crmne/egui", rev = "0b431145c22ee27b20b0aff7243d74f4b32e9a79" }
|
|
egui-winit = { git = "https://github.com/crmne/egui", rev = "0b431145c22ee27b20b0aff7243d74f4b32e9a79" }
|
|
egui_extras = { git = "https://github.com/crmne/egui", rev = "0b431145c22ee27b20b0aff7243d74f4b32e9a79" }
|
|
egui_glow = { git = "https://github.com/crmne/egui", rev = "0b431145c22ee27b20b0aff7243d74f4b32e9a79" }
|
|
emath = { git = "https://github.com/crmne/egui", rev = "0b431145c22ee27b20b0aff7243d74f4b32e9a79" }
|
|
epaint = { git = "https://github.com/crmne/egui", rev = "0b431145c22ee27b20b0aff7243d74f4b32e9a79" }
|
|
epaint_default_fonts = { git = "https://github.com/crmne/egui", rev = "0b431145c22ee27b20b0aff7243d74f4b32e9a79" }
|
|
# crmne/winit apps-0.30, shared with the same apps: winit 0.30.13 plus Wayland
|
|
# `Occluded` for the xdg-shell suspended state with commits on the app's behalf
|
|
# while it isn't presenting (rust-windowing/winit#4709, #4710), macOS Quit
|
|
# through close requests behind a feature Spotifast leaves off (winit#4692),
|
|
# and file drag and drop on Wayland. eframe from the fork above calls the
|
|
# Occluded API. Move both forks together with the other apps.
|
|
winit = { git = "https://github.com/crmne/winit", rev = "fc4f39ff0993dd235952b749dd16b856c0194e1f" }
|
|
# 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.
|
|
projectm-sys = { git = "https://github.com/crmne/projectm-rs", branch = "respect-cmake-generator" }
|
|
# hyper-proxy2's unreleased rustls 0.23 update plus our upstream provider
|
|
# compatibility fix. Drop this fork when a release includes both changes.
|
|
hyper-proxy2 = { git = "https://github.com/crmne/hyper-proxy2", rev = "efca4811371ddae81c06be168de54194938d70b1" }
|
|
# 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, an in-memory credential cache for platform storage, and full
|
|
# playback-state recovery after a session disconnect.
|
|
# Recovery is proposed upstream in librespot-org/librespot#1765.
|
|
# 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", rev = "669e004ec7a79e6eea0f87779efc69680793d3b7" }
|
|
librespot-connect = { git = "https://github.com/crmne/librespot", rev = "669e004ec7a79e6eea0f87779efc69680793d3b7" }
|
|
librespot-core = { git = "https://github.com/crmne/librespot", rev = "669e004ec7a79e6eea0f87779efc69680793d3b7" }
|
|
librespot-metadata = { git = "https://github.com/crmne/librespot", rev = "669e004ec7a79e6eea0f87779efc69680793d3b7" }
|
|
librespot-oauth = { git = "https://github.com/crmne/librespot", rev = "669e004ec7a79e6eea0f87779efc69680793d3b7" }
|
|
librespot-playback = { git = "https://github.com/crmne/librespot", rev = "669e004ec7a79e6eea0f87779efc69680793d3b7" }
|
|
librespot-protocol = { git = "https://github.com/crmne/librespot", rev = "669e004ec7a79e6eea0f87779efc69680793d3b7" }
|