A Save still running with the app in the background now posts a progress notice — how many files, the one it is on, a bar, Stop all and Open — and takes it down when the queue empties. It sits on its own low-importance channel so it can be silenced without silencing the player's card, and rides its own dataSync foreground service rather than the media one: a mediaPlayback service stops itself when the bar empties, a download is not playback, and nothing else was keeping the process alive for a Save with nothing playing — which is how the first real Save died, four tracks in. Stop all goes through the same cancel(id) a row's tap takes, and Transfers grew the matching button beside Clear finished. The walk pushes two rows straight into the transfer store and reads the real notification back out of `dumpsys notification`, without fetching anything.
110 lines
4.1 KiB
TOML
110 lines
4.1 KiB
TOML
[package]
|
|
name = "app"
|
|
version.workspace = true
|
|
description = "SoulStream — music player, downloader and streamer for the Soulseek network"
|
|
authors.workspace = true
|
|
edition.workspace = true
|
|
rust-version.workspace = true
|
|
|
|
[lib]
|
|
name = "app_lib"
|
|
crate-type = ["staticlib", "cdylib", "rlib"]
|
|
|
|
[build-dependencies]
|
|
tauri-build = { version = "2", features = [] }
|
|
|
|
[dev-dependencies]
|
|
# Import-apply tests build a whole source/pen/library bed on disk; already in
|
|
# the lock file via the dependency tree, so this adds no download.
|
|
tempfile = "3"
|
|
|
|
[dependencies]
|
|
tauri = { version = "2", features = [] }
|
|
tauri-plugin-log = "2"
|
|
tauri-plugin-dialog = "2"
|
|
serde.workspace = true
|
|
serde_json.workspace = true
|
|
log.workspace = true
|
|
image.workspace = true
|
|
tokio.workspace = true
|
|
|
|
base64 = "0.22"
|
|
bincode = "1"
|
|
bs58 = "0.5"
|
|
rand = "0.8"
|
|
# Shazam signature packets (shazam.rs) carry a CRC-32 of their body.
|
|
crc32fast = "1"
|
|
# Inflate for the deno release zip (ytdlp.rs) — already in the lock via the
|
|
# image stack, so this adds no download.
|
|
flate2 = "1"
|
|
# STFT/iSTFT for the vocal separator (vocal_sep.rs) — pure Rust, so the
|
|
# no-child-processes charter holds; wraps rustfft with real transforms.
|
|
realfft = "3"
|
|
# XSPF playlist import (playlist_formats.rs). quick-xml never resolves DTDs
|
|
# or external entities, which is exactly the safety posture the importer wants.
|
|
quick-xml = "0.37"
|
|
keyring = { version = "3", features = ["windows-native"] }
|
|
sysinfo = "0.33"
|
|
soulseek-proto = { path = "../crates/soulseek-proto" }
|
|
soulseek-client = { path = "../crates/soulseek-client" }
|
|
freenet-adapter = { path = "../crates/freenet-adapter" }
|
|
persona-state = { path = "../crates/persona-state" }
|
|
player = { path = "../crates/player" }
|
|
tagger = { path = "../crates/tagger" }
|
|
metadata = { path = "../crates/metadata" }
|
|
library = { path = "../crates/library" }
|
|
audio-formats = { path = "../crates/audio-formats" }
|
|
# The phone's lock-screen card and background playback (a Kotlin foreground
|
|
# service). Registered everywhere so the permission set resolves on every
|
|
# platform; on the desktop its commands answer "not here".
|
|
tauri-plugin-media-session = { path = "../crates/tauri-plugin-media-session" }
|
|
tauri-plugin-storage = { path = "../crates/tauri-plugin-storage" }
|
|
tauri-plugin-share = { path = "../crates/tauri-plugin-share" }
|
|
# The phone's downloads notice (a second Kotlin foreground service, dataSync).
|
|
# Registered everywhere so the permission set resolves on every platform; on
|
|
# the desktop its commands answer "not here".
|
|
tauri-plugin-transfer-notice = { path = "../crates/tauri-plugin-transfer-notice" }
|
|
semver = "1"
|
|
tauri-plugin-opener = "2.5.5"
|
|
|
|
# LRCLIB lyrics client (lyrics.rs). Already in the tree via the metadata crate.
|
|
# Desktop keeps the platform TLS (schannel on Windows); Android has no OpenSSL
|
|
# to build against, so it takes rustls with the bundled roots instead.
|
|
[target.'cfg(not(target_os = "android"))'.dependencies]
|
|
reqwest = { version = "0.12", features = ["json"] }
|
|
# Release checks and the silent install are a desktop story; the phone gets
|
|
# its builds from the store or a sideload, and the plugin is desktop-only.
|
|
tauri-plugin-updater = "2"
|
|
|
|
[target.'cfg(target_os = "android")'.dependencies]
|
|
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] }
|
|
# JNI_OnLoad (android_glue.rs): hands the JavaVM and the app Context to
|
|
# ndk-context, which cpal's AAudio backend reads and tao 0.35 never fills.
|
|
jni = "0.21"
|
|
ndk-context = "0.1"
|
|
|
|
[target.'cfg(windows)'.dependencies]
|
|
windows = { version = "0.61.3", features = [
|
|
"AI_MachineLearning",
|
|
"Foundation_Collections",
|
|
"Globalization",
|
|
"Graphics_Imaging",
|
|
# SystemMediaTransportControls — the OS media card (see src/smtc.rs).
|
|
"Media",
|
|
"Media_FaceAnalysis",
|
|
"Media_Ocr",
|
|
"Storage_Streams",
|
|
"Win32_Foundation",
|
|
# Taskbar thumbnail toolbar — ITaskbarList3 + the window subclass that
|
|
# hears its clicks, and the GDI/registry bits that draw its icons.
|
|
"Win32_Graphics_Gdi",
|
|
"Win32_System_Com",
|
|
"Win32_System_Registry",
|
|
"Win32_UI_Shell",
|
|
"Win32_UI_WindowsAndMessaging",
|
|
"Win32_System_Performance",
|
|
"Win32_System_ProcessStatus",
|
|
"Win32_System_Threading",
|
|
"Win32_System_WinRT",
|
|
] }
|