[package] name = "fastpotify" version = "0.4.0-rc3" 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" # 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" # 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" 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] # 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"] } 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