DNDeezer — Deezer Source Plugin for DroppedNeedle
DNDeezer is a plugin for DroppedNeedle, a self-hosted music library manager, built against its Plugin API v1. It registers Deezer as a complete source — both an indexer and a download client — so the host can search for missing music and have the plugin fetch it end to end. Download quality is limited by the user's own Deezer subscription, and everything runs locally: your ARL cookie, your library, your machine.
Architecture
The plugin has two connected paths. The indexer authenticates against Deezer's gateway, searches the public API, converts JSON responses into immutable typed models, scores candidates, and returns results carrying payloads like album:302127 or track:3135555. The download backend turns a selected payload into files: it owns the async job lifecycle (validation, state, progress, cancellation), while a media service handles the acquisition pipeline — session and license token exchange, per-track media resolution, a signed CDN URL, a streamed download, and chunk-level decryption of encrypted formats. Quality is negotiated in order: FLAC, then MP3 320, then MP3 128.
Reliability
Every Deezer call goes through a single client per job that caches its authenticated session, throttles outgoing requests, and retries transient failures (429/503 and friends) with exponential backoff and jitter. At most two download jobs run concurrently per instance; the rest queue. Progress reporting uses a monotonic high-water mark of materialized bytes so the host can tell queued work from a stalled transfer. Job state lives in SQLite: completed jobs survive restarts and remain inspectable, previously running jobs are marked interrupted rather than silently lost, and failed deletions retain ownership for retry. Decryption and disk writes run in sequential worker-thread batches, keeping blocking work off the host's event loop.
Albums
Album downloads reuse the track pipeline with one shared authentication: the full tracklist is fetched with pagination, tracks download sequentially into a sanitized 'Artist - Album' directory with zero-padded filenames, per-track progress is rescaled to the whole album, and a single failed track is skipped — the job only fails if the album produces no files at all.
Testing & CI
The project is managed with uv on Python 3.13, linted with ruff, and tested with pytest. The test suite fakes only the HTTP transport, so the client, media service, and backend all run for real — including end-to-end tests that drive track and album payloads through the entire stack. A separate script runs a live smoke test against the real Deezer API, and CI runs lint and tests on every push and pull request.