Replace browser-side pdfjs-dist canvas rendering with server-side MuPDF rendering for high-quality PDF booklet display. MuPDF renders pages to PNG at configurable DPI in Rust, producing much sharper results than the JavaScript canvas approach which had persistent JPEG 2000 WASM decoder issues. - Add mupdf crate with sys-lib features (avoid GTK symbol conflicts) - Create pdf_viewer.rs with v2_booklet_open/render_page/close commands - Download PDF to temp file, render pages on demand via MuPDF - Display rendered PNGs as img tags instead of canvas - DPI scales with zoom and devicePixelRatio for crisp output - Support rotation via MuPDF transformation matrix
162 lines
4.1 KiB
TOML
162 lines
4.1 KiB
TOML
[package]
|
|
name = "qbz-nix"
|
|
version = "1.1.18"
|
|
description = "Native high-fidelity client for Qobuz™ subscribers on Linux with Hi-Fi audio support (uses the Qobuz API; not certified by Qobuz)"
|
|
authors = ["blitzkriegfc"]
|
|
edition = "2021"
|
|
|
|
[lib]
|
|
name = "qbz_nix_lib"
|
|
crate-type = ["staticlib", "cdylib", "rlib"]
|
|
|
|
[[bin]]
|
|
name = "qbz"
|
|
path = "src/main.rs"
|
|
|
|
[build-dependencies]
|
|
tauri-build = { version = "2", features = [] }
|
|
|
|
[dependencies]
|
|
# QBZ Crates (extracted core functionality)
|
|
qbz-models = { path = "../crates/qbz-models" }
|
|
qbz-audio = { path = "../crates/qbz-audio" }
|
|
qbz-player = { path = "../crates/qbz-player" }
|
|
qbz-qobuz = { path = "../crates/qbz-qobuz" }
|
|
qbz-core = { path = "../crates/qbz-core" }
|
|
qbz-integrations = { path = "../crates/qbz-integrations" }
|
|
qbz-cache = { path = "../crates/qbz-cache" }
|
|
qbz-library = { path = "../crates/qbz-library" }
|
|
qbz-cast = { path = "../crates/qbz-cast" }
|
|
|
|
# Tauri
|
|
tauri = { version = "2", features = ["protocol-asset", "tray-icon"] }
|
|
tauri-plugin-opener = "2"
|
|
tauri-plugin-single-instance = "2"
|
|
|
|
# Serialization
|
|
serde = { version = "1", features = ["derive"] }
|
|
serde_json = "1"
|
|
|
|
# HTTP Client
|
|
reqwest = { version = "0.12", features = ["json", "cookies", "rustls-tls", "stream", "blocking", "multipart"], default-features = false }
|
|
|
|
# Async Runtime
|
|
tokio = { version = "1", features = ["full"] }
|
|
async-trait = "0.1"
|
|
tokio-stream = { version = "0.1", features = ["sync"] }
|
|
|
|
# Local API server
|
|
axum = { version = "0.7", features = ["ws"] }
|
|
axum-server = { version = "0.8", features = ["tls-rustls"] }
|
|
rustls = { version = "0.23", default-features = false, features = ["aws-lc-rs"] }
|
|
tower-http = { version = "0.5", features = ["cors"] }
|
|
qrcode-generator = "4.1"
|
|
rcgen = "0.12"
|
|
|
|
# Crypto (for API signatures and credential encryption)
|
|
md-5 = "0.10"
|
|
base64 = "0.22"
|
|
aes-gcm = "0.10"
|
|
sha2 = "0.10"
|
|
|
|
# Regex (for bundle parsing)
|
|
regex = "1"
|
|
lazy_static = "1.4"
|
|
|
|
# Time
|
|
chrono = "0.4"
|
|
|
|
# Error handling
|
|
thiserror = "2"
|
|
anyhow = "1"
|
|
|
|
# Logging
|
|
log = "0.4"
|
|
env_logger = "0.11"
|
|
|
|
# Random number generation (for shuffle)
|
|
rand = "0.8"
|
|
|
|
# Audio playback
|
|
rodio = { version = "0.19", features = ["symphonia-all"] }
|
|
symphonia = { version = "0.5", features = ["all"] }
|
|
|
|
# Audio visualization (FFT)
|
|
spectrum-analyzer = "1.5"
|
|
|
|
# EBU R128 loudness measurement (real-time normalization)
|
|
ebur128 = "0.1"
|
|
|
|
# Media controls (MPRIS on Linux)
|
|
souvlaki = "0.7"
|
|
|
|
# Desktop notifications
|
|
notify-rust = "4"
|
|
|
|
# Image processing (tray icon + thumbnails)
|
|
image = { version = "0.25", default-features = false, features = ["png", "jpeg", "webp"] }
|
|
|
|
# PDF rendering with MuPDF engine (high-quality rasterization for booklet viewer)
|
|
# NOTE: Use sys-lib-* features to link common libs from system, avoiding symbol
|
|
# conflicts with GTK/GdkPixbuf used by tauri-plugin-dialog on Linux.
|
|
mupdf = { version = "0.5", default-features = false, features = [
|
|
"system-fonts",
|
|
"sys-lib-libjpeg",
|
|
"sys-lib-zlib",
|
|
"sys-lib-harfbuzz",
|
|
"sys-lib-freetype",
|
|
] }
|
|
|
|
# URL opening
|
|
open = "5"
|
|
|
|
# Local library
|
|
walkdir = "2"
|
|
lofty = "0.18"
|
|
rusqlite = { version = "0.31", features = ["bundled"] }
|
|
dirs = "5"
|
|
filetime = "0.2"
|
|
glob = "0.3"
|
|
uuid = { version = "1", features = ["v4"] }
|
|
|
|
# File dialogs - platform specific (see target dependencies below)
|
|
|
|
# URL encoding
|
|
urlencoding = "2"
|
|
|
|
# Environment variables
|
|
dotenvy = "0.15"
|
|
|
|
# Secure credential storage (system keyring)
|
|
keyring = "3"
|
|
|
|
# Clipboard
|
|
tauri-plugin-clipboard-manager = "2"
|
|
|
|
# Casting: qbz-cast crate provides all casting functionality
|
|
# (Chromecast via rust_cast, AirPlay discovery, DLNA via rupnp)
|
|
|
|
# Async utilities (used across codebase)
|
|
futures-util = "0.3"
|
|
|
|
# Platform-specific dependencies
|
|
[target.'cfg(target_os = "linux")'.dependencies]
|
|
# Note: xdg-portal feature disabled due to ashpd/zbus version incompatibility
|
|
tauri-plugin-dialog = { version = "2.6.0" }
|
|
|
|
# Direct ALSA access for bit-perfect playback (bypasses CPAL limitations)
|
|
alsa = "0.9"
|
|
|
|
[target.'cfg(target_os = "macos")'.dependencies]
|
|
tauri-plugin-dialog = { version = "2.6.0" }
|
|
|
|
[target.'cfg(target_os = "windows")'.dependencies]
|
|
tauri-plugin-dialog = { version = "2.6.0" }
|
|
|
|
[dev-dependencies]
|
|
tempfile = "3"
|
|
|
|
[patch.crates-io]
|
|
cpal = { path = "vendor/cpal" }
|
|
rodio = { path = "vendor/rodio" }
|