3.8 KiB
Votify Download System
Overview
Votify is the primary Spotify download backend. It invokes the votify-fix CLI tool (a third-party Python package) as a subprocess, streams its output to the job log, and post-processes the resulting files.
How It Works
- User submits Spotify URLs and options via
POST /api/download. - A job is created and a background thread runs
run_download(). run_download()builds avotifyCLI command and launches it viasubprocess.Popen.- stdout is streamed line-by-line into the job's output log.
- On completion, post-processing runs:
- Flatten nested directories
- Rename files from embedded metadata
- Wrap single-track downloads in a folder
- Convert to MP3 if requested
Authentication
Votify authenticates with Spotify using a cookies.txt file in Netscape format. This file must be uploaded by an admin via the Settings page before any downloads will succeed.
Path: /config/cookies.txt (configurable via COOKIES_PATH env var)
A Widevine device certificate (device.wvd) may also be required depending on the content. It is uploaded separately via Settings.
Path: /config/device.wvd (configurable via WVD_PATH env var)
Download Options
| Option | Values | Description |
|---|---|---|
audio_quality |
aac-medium, aac-high, vorbis-low, vorbis-medium, vorbis-high |
Audio quality |
output_format |
original, mp3 |
Keep original format or convert to MP3 |
download_mode |
ytdlp, aria2c |
Download backend |
save_cover |
bool | Save cover art as a separate image file |
save_playlist |
bool | Save playlist metadata file |
overwrite |
bool | Re-download if file already exists |
download_music_videos |
bool | Include music video downloads |
no_lrc |
bool | Skip LRC (lyrics) file generation |
video_format |
mp4, webm |
Format for music videos |
cover_size |
small, medium, large, extra-large |
Cover art resolution |
truncate |
int (optional) | Limit number of tracks to download |
MP3 Conversion
If output_format is set to mp3, files are converted after download using ffmpeg at 320 kbps. The conversion preserves embedded metadata. Original files are deleted after successful conversion.
Cancellation
The Popen process handle is stored on the job dict. POST /api/jobs/<id>/cancel calls process.terminate(), which sends SIGTERM to the votify subprocess.
Post-Processing Detail
After the subprocess exits, post_process_votify_files() runs:
- Snapshot before — records which audio files existed before the download started (to identify new files).
- Flatten — collapses single-subdirectory chains into the parent folder.
- Rename — calls
rename_from_metadata()to produceTitle - Artist.extfilenames. - Wrap singles — if exactly one file downloaded with no enclosing folder, wraps it in a folder named after the file.
- Cleanup — removes leftover empty directories.
External Dependencies
| Dependency | Purpose |
|---|---|
votify-fix (GitHub: GladistonXD/votify-fix) |
Spotify download CLI |
ffmpeg |
MP3 conversion |
aria2c |
Optional download manager |
yt-dlp |
Default download manager |
mp4decrypt (Bento4) |
MP4 DRM decryption |
Limitations
- Requires valid Spotify cookies (must be refreshed periodically when they expire).
- DRM-protected content requires a Widevine device certificate.
- Quality options are limited to what Votify and the Spotify API expose.
Key Files
| File | Relevance |
|---|---|
| app.py | run_download(), post_process_votify_files(), route /api/download |
| utils.py | rename_from_metadata(), cleanup_empty_dirs() |
| Dockerfile | Installation of votify-fix, ffmpeg, aria2, Bento4 |