{"id":25664590,"url":"https://github.com/henriquesebastiao/downtify","last_synced_at":"2026-04-29T02:12:18.493Z","repository":{"id":276061472,"uuid":"927689692","full_name":"henriquesebastiao/downtify","owner":"henriquesebastiao","description":"Download your playlists and songs, along with album art and metadata, in a self-hosted format via Docker","archived":false,"fork":false,"pushed_at":"2026-04-24T00:08:16.000Z","size":1766,"stargazers_count":178,"open_issues_count":5,"forks_count":17,"subscribers_count":3,"default_branch":"main","last_synced_at":"2026-04-24T01:35:47.919Z","etag":null,"topics":["downloader","mp3","music","music-downloader","playlists","python","self-hosted","spotdl","spotify","spotify-downloader"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/henriquesebastiao.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["henriquesebastiao"]}},"created_at":"2025-02-05T11:31:59.000Z","updated_at":"2026-04-24T00:08:20.000Z","dependencies_parsed_at":"2025-10-17T10:16:33.621Z","dependency_job_id":"ddbc8ce1-4e34-43bb-bed9-783931710747","html_url":"https://github.com/henriquesebastiao/downtify","commit_stats":null,"previous_names":["henriquesebastiao/downtify"],"tags_count":24,"template":false,"template_full_name":null,"purl":"pkg:github/henriquesebastiao/downtify","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/henriquesebastiao%2Fdowntify","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/henriquesebastiao%2Fdowntify/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/henriquesebastiao%2Fdowntify/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/henriquesebastiao%2Fdowntify/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/henriquesebastiao","download_url":"https://codeload.github.com/henriquesebastiao/downtify/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/henriquesebastiao%2Fdowntify/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32407232,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-28T19:38:08.556Z","status":"online","status_checked_at":"2026-04-29T02:00:06.602Z","response_time":110,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["downloader","mp3","music","music-downloader","playlists","python","self-hosted","spotdl","spotify","spotify-downloader"],"created_at":"2025-02-24T06:29:16.275Z","updated_at":"2026-04-29T02:12:18.488Z","avatar_url":"https://github.com/henriquesebastiao.png","language":"Python","funding_links":["https://github.com/sponsors/henriquesebastiao"],"categories":["Python"],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e\n  \u003ca href=\"https://github.com/henriquesebastiao/downtify\" target=\"_blank\" rel=\"noopener noreferrer\"\u003e\n    \u003cpicture\u003e\n      \u003cimg width=\"80\" src=\"https://github.com/user-attachments/assets/628d4334-7326-446e-9f2a-4d3ab4fc95c3\"\u003e\n    \u003c/picture\u003e\n  \u003c/a\u003e\n  \u003cbr\u003e\n  Downtify\n\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003eSelf-hosted music downloader. Paste a Spotify link, get a perfectly tagged audio file — no API keys, no account, no hassle.\u003c/strong\u003e\n\u003c/p\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n[![Test](https://github.com/henriquesebastiao/downtify/actions/workflows/test.yml/badge.svg)](https://github.com/henriquesebastiao/downtify/actions/workflows/test.yml)\n[![GitHub Release](https://img.shields.io/github/v/release/henriquesebastiao/downtify?color=blue)](https://github.com/henriquesebastiao/downtify/releases)\n[![GitHub License](https://img.shields.io/github/license/henriquesebastiao/downtify?color=blue)](/LICENSE)\n[![Docker Pulls](https://img.shields.io/docker/pulls/henriquesebastiao/downtify?color=blue)](https://hub.docker.com/r/henriquesebastiao/downtify)\n[![Visitors](https://api.visitorbadge.io/api/visitors?path=henriquesebastiao%2Fdowntify\u0026label=repository%20visits\u0026countColor=%231182c3\u0026style=flat)](https://github.com/henriquesebastiao/downtify)\n\n\u003c/div\u003e\n\nhttps://github.com/user-attachments/assets/9711efe8-a960-4e1a-8d55-e0d1c20208f7\n\n---\n\n## ✨ What is Downtify?\n\nDowntify is a **self-hosted web app** that downloads music from Spotify — without touching the Spotify API, without needing an account, and without any Premium subscription. Just drop a link and get a fully-tagged audio file.\n\nIt resolves track metadata directly from Spotify's public embed pages, finds the best audio match on YouTube Music, downloads it with `yt-dlp`, converts it with `ffmpeg`, and embeds album art + all metadata with `mutagen`. The entire pipeline runs inside a single Docker container.\n\n---\n\n## 🚀 Features\n\n| Feature | Details |\n|---------|---------|\n| 🎵 **Tracks, albums \u0026 playlists** | Any Spotify link works — single track, full album, or entire playlist |\n| 👁️ **Playlist Monitor** | Watch playlists and **auto-download new songs** as they are added to Spotify |\n| 🎨 **Rich metadata** | Album art, title, artist, album, year — all embedded in every file |\n| 🎚️ **Multiple formats** | MP3 · FLAC · M4A · OGG · OPUS |\n| 🔎 **Free-text search** | Search YouTube Music directly — no Spotify link needed |\n| 🔑 **Zero credentials** | No Spotify API key, no account, no Premium required |\n| 🔔 **Real-time progress** | Live download progress via WebSocket — no page reload needed |\n| 🐳 **One Docker command** | Up and running in under a minute |\n| 🏠 **Home server platforms** | Available on Umbrel, CasaOS and HomeDock |\n| 🎧 **Built-in player** | Play your downloaded music straight from the web UI — progress bar, shuffle, repeat, volume |\n| 🌍 **Multi-language UI** | English (default), Spanish and Brazilian Portuguese — easy to add more |\n\n---\n\n## 🚀 Quick Start\n\n```bash\ndocker run -d -p 8000:8000 --name downtify \\\n  -v /path/to/downloads:/downloads \\\n  ghcr.io/henriquesebastiao/downtify\n```\n\nOpen [http://localhost:8000](http://localhost:8000), paste a Spotify link, and hit download.\n\n\u003e Change `/path/to/downloads` to wherever you want your music saved.\n\n### Docker Compose\n\n```yaml\nservices:\n  downtify:\n    container_name: downtify\n    image: ghcr.io/henriquesebastiao/downtify:latest\n    ports:\n      - '8000:8000'\n    volumes:\n      - ./downloads:/downloads\n    restart: unless-stopped\n```\n\nNeed a custom port? Use the `DOWNTIFY_PORT` environment variable:\n\n```yaml\nports:\n  - '8000:30321'\nenvironment:\n  - DOWNTIFY_PORT=30321\n```\n\n---\n\n## 🏠 One-Click Install on Home Servers\n\n| Platform | Link |\n|----------|------|\n| ☂️ Umbrel | [Install on Umbrel](https://apps.umbrel.com/app/downtify) |\n| 🏠 CasaOS | [Install on CasaOS](https://casaos.zimaspace.com/) |\n| ⚓ HomeDock OS | [Install on HomeDock](https://www.homedock.cloud/apps/downtify/) |\n\n---\n\n## ⚙️ How It Works\n\nDowntify's download pipeline has three stages:\n\n```\nSpotify embed page  →  YouTube Music search  →  yt-dlp + ffmpeg + mutagen\n   (metadata)             (audio match)            (download \u0026 tag)\n```\n\n1. **Metadata** — Track, album and playlist links are resolved by scraping the public `open.spotify.com/embed` pages. No Spotify credentials of any kind are required.\n2. **Audio match** — [`ytmusicapi`](https://ytmusicapi.readthedocs.io/) searches YouTube Music for the track and picks the best result by comparing audio duration. Free-text searches skip the Spotify step entirely.\n3. **Download \u0026 tag** — [`yt-dlp`](https://github.com/yt-dlp/yt-dlp) downloads the audio and `ffmpeg` converts it to your chosen format. [`mutagen`](https://mutagen.readthedocs.io/) embeds title, artist, album, year and cover art into the file.\n\n---\n\n## 👁️ Playlist Monitor\n\nThe **Playlist Monitor** lets Downtify watch your favorite Spotify playlists and automatically download any new songs added to them — hands-free.\n\n**How to use it:**\n\n1. Click the eye icon (👁) in the navigation bar\n2. Paste a Spotify playlist URL\n3. Choose how often Downtify should check for new tracks (every 15 min up to once a day)\n4. Click **Watch**\n\nFrom that point on, whenever a new song appears in the playlist on Spotify, Downtify will detect and download it on the next scheduled check. Tracks that were already in the playlist when you added it are skipped — only *new* additions are downloaded.\n\nYou can pause, resume, force an immediate check, or stop monitoring any playlist at any time from the same page.\n\n---\n\n## 🎛️ Download Settings\n\nAccess the settings panel (⚙️ icon) to configure:\n\n| Setting | Options |\n|---------|---------|\n| **Output format** | MP3 · FLAC · M4A · OGG · OPUS |\n| **Bitrate** | 128 · 192 · 256 · 320 kbps (ignored for FLAC) |\n| **Audio provider** | YouTube Music |\n\n---\n\n## 📦 What Spotify links are supported?\n\n| Link type | Supported |\n|-----------|-----------|\n| Spotify track | ✅ |\n| Spotify album | ✅ |\n| Spotify playlist | ✅ |\n| YouTube Music search (free text) | ✅ |\n| Direct YouTube link | ✅ |\n\n---\n\n## 📃 M3U playlist export\n\nDowntify writes a standard `EXTM3U` file alongside your audio whenever a playlist gets downloaded — both for **manual** playlist paste-downloads and for **Playlist Monitor** sweeps that fetched at least one new track:\n\n```\n\u003cdownloads\u003e/Playlists/\u003cplaylist-name\u003e.m3u\n```\n\nThe behaviour is governed by a single toggle in **Settings → Playlists → Generate M3U file for playlists** (on by default). Flip it off if you'd rather not produce M3Us at all; the rest of the download flow is unchanged.\n\nTracks that failed to download or had no YouTube Music match are skipped (and logged). The M3U is regenerated fresh on every run, so re-pasting the same playlist URL — or letting the Monitor add new tracks over time — always produces a complete, in-order file.\n\nTrack paths inside the M3U are written **relative to the M3U file itself**, so the same file works whether it's read from inside Downtify (where the library is mounted at `/downloads`) or from another consumer that mounts the same library at a different root — e.g. Jellyfin under `/nas/music`. Just point your media server at the same library mount and the playlist will appear as a single unit instead of a pile of loose files.\n\n---\n\n\u003e [!WARNING]\n\u003e Users are responsible for their actions and any legal consequences. Downtify does not support unauthorized downloading of copyrighted material and takes no responsibility for user actions.\n\n---\n\n## 🎧 Built-in Player\n\nDowntify ships with a clean web player so you don't need a separate app to listen to what you've downloaded. Open the headphones icon (🎧) in the navigation bar — or hit the play button next to any file in the **Library** — and Downtify will load every audio file from your downloads folder into a queue.\n\n**What's included:**\n\n- Big now-playing card with embedded **album art** and a progress bar (click or drag to seek)\n- Play / pause / previous / next\n- **Shuffle** with a stable random order across the whole queue\n- **Repeat** modes: off → all → one\n- Volume slider with mute toggle (volume is remembered between sessions)\n- Side queue listing every track in your library, each one with its own thumbnail and the currently playing one highlighted\n\nThe player parses `Artist - Title.ext` filenames so the now-playing card shows artist and title nicely, and pulls the cover art directly from the audio file's embedded tags (the same artwork Downtify wrote at download time). Playback uses your browser's native HTML5 audio element — no extra dependencies, no extra processes.\n\n---\n\n## 🌍 Internationalization\n\nDowntify's UI is fully translatable. The default language is **English**, with **Spanish** and **Brazilian Portuguese** included out of the box. You can switch languages from **Settings → Language**; your choice is saved in the browser's `localStorage` and applied instantly without a reload.\n\n### Contributing translations\n\nAdding a new language is a small, three-step change — no build tooling beyond the existing Vite setup is required.\n\n1. **Copy the English file as a starting point.** Locale files live in `frontend/src/i18n/locales/`. Each file exports a single object whose keys match the structure of `en.js` exactly. Pick an [IETF language tag](https://en.wikipedia.org/wiki/IETF_language_tag) for the file name (e.g. `fr.js`, `de.js`, `it.js`, `ja.js`, `pt-PT.js`).\n\n   ```bash\n   cp frontend/src/i18n/locales/en.js frontend/src/i18n/locales/fr.js\n   ```\n\n2. **Translate the values.** Keep the keys, the placeholder tokens (e.g. `{count}`, `{name}`, `{file}`) and the overall shape unchanged — only the strings on the right-hand side should change. Update the `language.name` field at the top of the file to the **native** name of the language (\"Français\", \"Deutsch\", \"Italiano\"…) — this is the label that appears in the language picker.\n\n3. **Register the locale** in `frontend/src/i18n/index.js`:\n\n   ```js\n   import fr from './locales/fr.js'\n\n   export const AVAILABLE_LOCALES = [\n     { code: 'en', name: 'English', messages: en },\n     { code: 'es', name: 'Español', messages: es },\n     { code: 'pt-BR', name: 'Português (BR)', messages: ptBR },\n     { code: 'fr', name: 'Français', messages: fr }, // new entry\n   ]\n   ```\n\nThat's it. Rebuild the frontend (`cd frontend \u0026\u0026 npm run build`) — your language will show up in **Settings → Language** automatically.\n\n**Tips for translators:**\n\n- Missing keys fall back to English, so partial translations still ship. You can submit a PR with only the strings you're confident about.\n- Placeholder tokens like `{count}` or `{file}` must be left as-is — they're substituted at runtime.\n- Keep strings concise: the UI is laid out tightly and very long translations may wrap awkwardly. If you need to rephrase to fit, that's fine.\n- After translating, run `npm run dev` from `frontend/` and click through every page in your language to spot anything that overflows or reads oddly in context.\n\nPull requests with new translations are very welcome — just open a PR against `main`.\n\n---\n\n## 🤝 Contributing\n\nContributions, issues and feature requests are welcome!\nCheck the [issues page](https://github.com/henriquesebastiao/downtify/issues) or open a pull request.\n\nIf Downtify has been useful to you, consider leaving a ⭐ — it helps the project grow and reach more people!\n\n---\n\n## 📄 License\n\nLicensed under the [GPL-3.0](https://github.com/henriquesebastiao/downtify?tab=GPL-3.0-1-ov-file#readme) License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhenriquesebastiao%2Fdowntify","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhenriquesebastiao%2Fdowntify","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhenriquesebastiao%2Fdowntify/lists"}