mirror of
https://github.com/Felitendo/spotifast.git
synced 2026-11-01 17:33:26 +01:00
Pinning already existed, but the order was append-only: the pin menu put a row at the end of the block and nothing could move it. Sidebar rows now sense drags the same way track rows do: past the threshold the row is in hand, while click, hover play, and the context menu keep their meaning. Liked Songs stays fixed on top. A dragged row lands between rows, in the slot nearest the pointer: rows part to open it, an accent line marks it, and the same 120 ms offsets ease everything back afterwards. Dropping inside the pinned block pins the row there, or moves it when it was already pinned, by rewriting settings.pinned_contexts anchored on the entry the drop lands in front of, so entries pinned from another shelf keep their place. Dropping below the block unpins. A row drag carries its own payload type, so it cannot be mistaken for a song drop, and the song release path is gated on its own payload because taking a payload of the wrong type would silently discard it. Claude-Session: https://claude.ai/code/session_013ACtBP4zDpAr7o2MPmnh9t
126 lines
5.5 KiB
TOML
126 lines
5.5 KiB
TOML
[package]
|
|
name = "fastpotify"
|
|
version = "0.3.0"
|
|
edition = "2024"
|
|
rust-version = "1.95"
|
|
license = "MIT"
|
|
description = "A fast, lightweight, native Spotify client built with Rust and egui"
|
|
repository = "https://github.com/crmne/fastpotify"
|
|
keywords = ["spotify", "music", "egui", "librespot", "player"]
|
|
categories = ["multimedia::audio"]
|
|
|
|
[lib]
|
|
name = "fastpotify"
|
|
path = "src/lib.rs"
|
|
|
|
[[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"
|
|
# The whole UI. glow keeps the binary and the dependency tree small; wgpu is
|
|
# not needed for a 2D music client.
|
|
eframe = { version = "0.36", default-features = false, features = ["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"
|
|
image = { version = "0.25", default-features = false, features = ["jpeg", "png"] }
|
|
# 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. Fastpotify 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 }
|
|
# 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"
|
|
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]
|
|
# Serving AppKit while no window exists (the status item lives on the main
|
|
# thread), and leaving the Dock while hidden.
|
|
objc2 = "0.6"
|
|
objc2-app-kit = { version = "0.3", default-features = false, features = ["std", "NSApplication", "NSEvent", "NSMenu", "NSMenuItem", "NSResponder", "NSRunningApplication"] }
|
|
objc2-foundation = { version = "0.3", default-features = false, features = ["std", "NSDate", "NSObjCRuntime", "NSRunLoop", "NSString"] }
|
|
|
|
[target.'cfg(windows)'.dependencies]
|
|
# A hidden window for the media controls to belong to, and message loops.
|
|
windows-sys = { version = "0.60", features = ["Win32_Foundation", "Win32_Graphics_Gdi", "Win32_System_Com", "Win32_System_LibraryLoader", "Win32_System_Threading", "Win32_UI_WindowsAndMessaging"] }
|
|
|
|
[target.'cfg(target_os = "linux")'.dependencies]
|
|
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 icon and version information Windows shows for the executable.
|
|
[target.'cfg(windows)'.build-dependencies]
|
|
winresource = "0.1"
|
|
|
|
[features]
|
|
# Sample data and screenshot flags; never part of a release build.
|
|
demo = []
|
|
|
|
[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
|