fm-dlp 2.3.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
fm_dlp-2.3.3/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 kernel
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
fm_dlp-2.3.3/PKG-INFO ADDED
@@ -0,0 +1,436 @@
1
+ Metadata-Version: 2.4
2
+ Name: fm-dlp
3
+ Version: 2.3.3
4
+ Summary: fm-dlp is a CLI tool for searching YouTube/YTMusic and downloading audio/video from 1000+ platforms
5
+ Requires-Python: >=3.10
6
+ Description-Content-Type: text/markdown
7
+ License-File: LICENSE
8
+ Requires-Dist: cyclopts
9
+ Requires-Dist: yt-dlp
10
+ Requires-Dist: ytmusicapi
11
+ Requires-Dist: mutagen
12
+ Dynamic: license-file
13
+
14
+ # fm-dlp is a CLI tool for searching YouTube/YTMusic and downloading audio/video from 1000+ platforms
15
+
16
+ [![Python](https://img.shields.io/badge/python-3.10+-blue.svg)](https://python.org)
17
+ [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
18
+ [![Platform](https://img.shields.io/badge/platform-linux%20%7C%20macOS%20%7C%20windows-lightgrey)]()
19
+ [![Ruff](https://img.shields.io/badge/code%20style-ruff-261230?logo=ruff&logoColor=white)](https://docs.astral.sh/ruff/)
20
+
21
+ Download and tag high-quality music and video from YouTube, YouTube Music, and 1000+ sites — all from your terminal.
22
+
23
+ ## ✨ Features
24
+
25
+ - **Multi-platform Search** — YouTube, YouTube Music
26
+ - **Search by Type** — Tracks or albums
27
+ - **Parallel Downloads** — Async support for multiple URLs
28
+ - **1000+ Supported Sites** — Any site yt-dlp supports (YouTube, SoundCloud, Bandcamp, etc.)
29
+ - **Audio Formats** — MP3, AAC, FLAC, M4A, Opus, Vorbis, WAV with configurable bitrate
30
+ - **Video Formats** — MP4, MKV, WebM, MOV, AVI, FLV with automatic audio codec selection
31
+ - **Metadata Embedding** — Title, artist, album tags + thumbnail (audio only)
32
+ - **Proxy Support** — HTTP, HTTPS, SOCKS4, SOCKS5, SOCKS5h for all requests (download supports all protocols; search via yt-music requires HTTP/HTTPS)
33
+ - **Cookie Support** — Browser cookies for restricted content
34
+ - **Self-updating** — Built-in update mechanism via Git
35
+
36
+ ## 🚀 Quick Start
37
+
38
+ ### Prerequisites
39
+ - Python 3.10+ & FFmpeg & Git
40
+
41
+ ### Installation
42
+
43
+ #### 1. Clone Repository
44
+
45
+ ```bash
46
+ git clone https://github.com/Fkernel653/fm-dlp.git && cd fm-dlp
47
+ ```
48
+
49
+ #### 2. Install Dependencies
50
+
51
+ **uv** (recommended)
52
+ ```bash
53
+ uv sync
54
+ ```
55
+
56
+ **pip**
57
+ ```bash
58
+ pip install .
59
+ ```
60
+
61
+ **Poetry**
62
+ ```bash
63
+ poetry install
64
+ ```
65
+
66
+ **PDM**
67
+ ```bash
68
+ pdm install
69
+ ```
70
+
71
+ ### Usage
72
+ ```bash
73
+ # Set download directory (required first)
74
+ python fm-dlp.py config ~/Music
75
+
76
+ # Search for tracks
77
+ python fm-dlp.py search "artist name" --limit 5 --platform yt-music
78
+
79
+ # Search for albums
80
+ python fm-dlp.py search "album name" --platform yt-music --type album
81
+
82
+ # Download audio
83
+ python fm-dlp.py download "https://youtu.be/..." --codec mp3 --kbps 320
84
+
85
+ # Download video
86
+ python fm-dlp.py download "https://youtu.be/..." --codec mp4
87
+ ```
88
+
89
+ ## 📋 Commands
90
+
91
+ ### `search` — Find music
92
+ ```bash
93
+ python fm-dlp.py search <query> [--limit 10] [--platform {yt-video|yt-music}] [--type {track|album}] [--proxy URL]
94
+ ```
95
+ | Option | Values | Default | Description |
96
+ |--------|--------|---------|-------------|
97
+ | `--platform` | `yt-video`, `yt-music` | `yt-music` | Search platform |
98
+ | `--type` | `track`, `album` | `track` | Content type to search |
99
+ | `--limit` | 1–∞ | 10 | Number of results |
100
+ | `--proxy` | URL | — | Proxy for requests |
101
+
102
+ ### `download` — Download audio or video
103
+ ```bash
104
+ python fm-dlp.py download <urls> [--codec CODEC] [--kbps 256] [--quiet False] [--max-concurrent 5] [--cookies browser] [--proxy URL]
105
+ ```
106
+ | Option | Values | Default |
107
+ |--------|--------|---------|
108
+ | `--codec` | **Audio:** `mp3`, `aac`, `flac`, `m4a`, `opus`, `vorbis`, `wav`<br>**Video:** `mp4`, `mkv`, `webm`, `mov`, `avi`, `flv` | `m4a` (macOS) / `opus` |
109
+ | `--kbps` | 64–320 (audio only) | 256 |
110
+ | `--quiet` | True/False (flag) | False |
111
+ | `--max-concurrent` | 1–∞ | 5 |
112
+ | `--cookies` | chrome, firefox, edge, etc. | — |
113
+ | `--proxy` | http://, socks5:// | — |
114
+
115
+ ### Supported Proxies
116
+
117
+ fm-dlp supports the following proxy protocols:
118
+
119
+ | Protocol | Download | Search (yt-video) | Search (yt-music) |
120
+ |----------|:--------:|:-----------------:|:-----------------:|
121
+ | `http://` | ✅ | ✅ | ✅ |
122
+ | `https://` | ✅ | ✅ | ✅ |
123
+ | `socks4://` | ✅ | ✅ | ❌ |
124
+ | `socks5://` | ✅ | ✅ | ❌ |
125
+ | `socks5h://` | ✅ | ✅ | ❌ |
126
+
127
+ > **Note:** `socks5h://` performs DNS resolution through the proxy (remote DNS), while `socks5://` resolves DNS locally. Use `socks5h://` for better privacy with Tor.
128
+
129
+ **Examples:**
130
+ ```bash
131
+ # HTTP proxy
132
+ python fm-dlp.py download "URL" --proxy http://user:pass@proxy.example.com:8080
133
+
134
+ # SOCKS5 (Tor)
135
+ python fm-dlp.py download "URL" --proxy socks5://127.0.0.1:9050
136
+
137
+ # SOCKS5h with remote DNS (recommended for Tor)
138
+ python fm-dlp.py download "URL" --proxy socks5h://127.0.0.1:9050
139
+
140
+ # SOCKS5 for video search
141
+ python fm-dlp.py search "query" --platform yt-video --proxy socks5://127.0.0.1:9050
142
+ ```
143
+
144
+ **Video container audio codec mapping:**
145
+
146
+ | Video Container | Audio Codec | Typical Use |
147
+ |-----------------|-------------|-------------|
148
+ | `mp4` | `m4a` (AAC) | Universal compatibility |
149
+ | `mkv` | `opus` | High quality, modern |
150
+ | `webm` | `opus` | Web, streaming |
151
+ | `mov` | `m4a` (AAC) | Apple ecosystem |
152
+ | `avi` | `mp3` | Legacy hardware |
153
+ | `flv` | `aac` | Legacy web |
154
+
155
+ ### `config` — Set or view download path
156
+ ```bash
157
+ python fm-dlp.py config <path> # Set directory
158
+ python fm-dlp.py config # View current setting
159
+ ```
160
+
161
+ ### `update` — Update the tool
162
+ ```bash
163
+ python fm-dlp.py update # Pull latest version via Git
164
+ ```
165
+ Requires Git to be installed and the project to be a clone of the repository.
166
+
167
+ ## 📁 Project Structure
168
+ ```
169
+ fm-dlp/
170
+ ├── fm-dlp.py # CLI entry point (cyclopts App)
171
+ ├── config.json # Persistent download path storage
172
+ ├── pyproject.toml # Project metadata & dependencies
173
+ ├── README.md # Project documentation
174
+ └── modules/
175
+ ├── __init__.py # Package initializer
176
+ ├── commands/
177
+ │ ├── __init__.py
178
+ │ ├── search.py # YouTube & YT Music search (tracks & albums)
179
+ │ └── download.py # Async audio/video download engine (yt-dlp)
180
+ └── utils/
181
+ ├── __init__.py
182
+ ├── configer.py # JSON config manager (read/write)
183
+ ├── validator.py # Input validation (URLs, codecs, proxies, bitrate)
184
+ │ # + system dependency checks (ffmpeg, git, yt-dlp)
185
+ ├── update.py # Self-update via Git (fetch + hard reset)
186
+ └── colors.py # Terminal ANSI color constants
187
+ ```
188
+
189
+ ## 🔧 Requirements
190
+
191
+ | Dependency | Purpose |
192
+ |------------|---------|
193
+ | `yt-dlp` | YouTube extraction & download |
194
+ | `mutagen` | Audio metadata tagging |
195
+ | `ytmusicapi` | YouTube Music API |
196
+ | `cyclopts` | CLI framework |
197
+ | **FFmpeg** | Audio/video conversion (system) |
198
+ | **Git** | Self-update mechanism (system) |
199
+
200
+ ## 📖 Examples
201
+
202
+ ### Search Examples
203
+ ```bash
204
+ # Search for tracks on YouTube Music
205
+ python fm-dlp.py search "Sewerslvt" --limit 10 --platform yt-music
206
+
207
+ # Search for albums on YouTube Music
208
+ python fm-dlp.py search "usedcvnt" --platform yt-music --type album
209
+
210
+ # Search for videos on YouTube
211
+ python fm-dlp.py search "breakcore mix" --platform yt-video --limit 5
212
+
213
+ # Search with proxy
214
+ python fm-dlp.py search "tokyona" --proxy socks5://127.0.0.1:9050
215
+ ```
216
+
217
+ ### Download Examples
218
+
219
+ **Audio:**
220
+ ```bash
221
+ # Basic audio download
222
+ python fm-dlp.py download "https://youtu.be/..." --codec flac
223
+
224
+ # Multiple URLs with custom quality
225
+ python fm-dlp.py download "URL1 URL2 URL3" --codec mp3 --kbps 320
226
+
227
+ # Lossless download
228
+ python fm-dlp.py download "URL" --codec wav
229
+ ```
230
+
231
+ **Video:**
232
+ ```bash
233
+ # Download as MP4
234
+ python fm-dlp.py download "https://youtu.be/..." --codec mp4
235
+
236
+ # Download as MKV with Opus audio
237
+ python fm-dlp.py download "https://youtu.be/..." --codec mkv
238
+
239
+ # Download as MOV for Apple devices
240
+ python fm-dlp.py download "https://youtu.be/..." --codec mov
241
+ ```
242
+
243
+ **Advanced:**
244
+ ```bash
245
+ # Age-restricted content with cookies
246
+ python fm-dlp.py download "URL" --cookies firefox
247
+
248
+ # Anonymous download via Tor
249
+ python fm-dlp.py download "URL" --proxy socks5://127.0.0.1:9050
250
+
251
+ # Quiet mode with increased parallelism
252
+ python fm-dlp.py download "URL1 URL2 URL3 URL4 URL5" --quiet --max-concurrent 10
253
+ ```
254
+
255
+ ### Maintenance
256
+ ```bash
257
+ # Update to latest version
258
+ python fm-dlp.py update
259
+ ```
260
+
261
+ ### Complete Workflow
262
+ ```bash
263
+ # 1. Set download location
264
+ python fm-dlp.py config ~/Music
265
+
266
+ # 2. Search for an album
267
+ python fm-dlp.py search "we had good times together, don't forget that" --limit 1 --type album
268
+
269
+ # 3. Download audio from album
270
+ python fm-dlp.py download "https://music.youtube.com/playlist?list=OLAK5uy_muvgxae_oLSvDyo0q_zp0JrkBS73nkLMM" --codec flac
271
+
272
+ # 4. Search and download a video
273
+ python fm-dlp.py search "goreshit" --platform yt-video
274
+ python fm-dlp.py download "https://youtu.be/gnubBJ6dP4g" --codec mkv
275
+ ```
276
+
277
+ ## ❓ FAQ
278
+
279
+ ### Why does fm-dlp exist when yt-dlp already downloads audio and video?
280
+
281
+ Think of fm-dlp as a **purpose-built stereo system**, while yt-dlp is a universal
282
+ multimedia Swiss Army knife. Yes, yt-dlp can extract audio, embed metadata,
283
+ and download video, but it takes a long string of flags to get there:
284
+
285
+ ```bash
286
+ # Audio with yt-dlp
287
+ yt-dlp -f bestaudio --extract-audio --audio-format mp3 --audio-quality 320k \
288
+ --embed-metadata --embed-thumbnail -o "~/Music/%(title)s.%(ext)s" "URL"
289
+
290
+ # Video with yt-dlp
291
+ yt-dlp -f "bestvideo[ext=mp4]+bestaudio[ext=m4a]/best" --merge-output-format mp4 \
292
+ -o "~/Videos/%(title)s.%(ext)s" "URL"
293
+ ```
294
+
295
+ fm-dlp wraps all that into a clean, music-focused workflow:
296
+ - **Search** with human-readable, formatted output — no scraping IDs from text dumps
297
+ - **Download audio or video** with a single option — no memorising flag combinations
298
+ - **Cleaner tags** — when used with `search` results, artist and title come from
299
+ structured music metadata rather than raw video descriptions with channel suffixes
300
+ - **Automatic format selection** — video containers automatically pick the best compatible audio codec
301
+
302
+ ### Why does macOS default to M4A while other platforms default to Opus?
303
+
304
+ The defaults are chosen to match the **native music player experience** on each
305
+ operating system:
306
+
307
+ | Platform | Default | Reasoning |
308
+ |----------|---------|-----------|
309
+ | **macOS / iOS** | `m4a` (AAC) | Apple's entire ecosystem — Finder, Music.app, QuickTime, GarageBand — treats M4A/AAC as the first-class audio format. Album artwork, tagging, and playback are seamless. |
310
+ | **Linux / Windows** | `opus` | Opus offers superior perceptual quality at equivalent bitrates. It's the codec modern Android devices, desktop players (VLC, foobar2000, audacious), and browsers use natively. |
311
+
312
+ You can always override the default with `--codec mp3` (universal, legacy
313
+ hardware), `--codec flac` (lossless archival), or any other supported format.
314
+
315
+ ### What video formats are supported and how do they work?
316
+
317
+ fm-dlp supports six video containers: `mp4`, `mkv`, `webm`, `mov`, `avi`, and `flv`.
318
+ When you choose a video format, fm-dlp automatically:
319
+ 1. Downloads the best available video stream
320
+ 2. Selects the optimal audio codec for that container (see mapping table above)
321
+ 3. Merges them together using FFmpeg
322
+
323
+ For example, `--codec mkv` downloads VP9 video + Opus audio and packs them into an MKV container,
324
+ while `--codec mp4` prefers H.264 video + AAC audio for maximum device compatibility.
325
+
326
+ ### Why is metadata embedding only available for audio?
327
+
328
+ Metadata embedding (title, artist, album, thumbnail) works only with audio codecs
329
+ (`mp3`, `aac`, `flac`, `m4a`, `opus`, `vorbis`, `wav`) using the `mutagen` library.
330
+ Video containers don't get automatic metadata tagging — this keeps the download
331
+ fast and avoids potential issues with video metadata standards.
332
+
333
+ ### How does the update command work?
334
+
335
+ `fm-dlp update` runs `git pull` inside the project directory. This means:
336
+ - You must have **Git installed** and accessible from the terminal
337
+ - The project must be a **Git clone** (not a downloaded ZIP)
338
+ - It pulls the latest commits from the remote repository
339
+ - No version checking or rollback — it's intentionally simple and transparent
340
+
341
+ ### Why write this in Python instead of something faster?
342
+
343
+ The initial version was a personal script that solved a daily annoyance: finding
344
+ and tagging high-quality music without fighting CLI flags. Python allowed rapid
345
+ iteration and immediate real-world use.
346
+
347
+ Most of the actual "work" is performed by highly optimised native code:
348
+ `yt-dlp` for networking, `ffmpeg` (C/ASM) for transcoding. The Python layer
349
+ orchestrates these tools and handles metadata logic in **milliseconds** — the
350
+ network download and ffmpeg encoding dominate execution time regardless of the
351
+ language.
352
+
353
+ ### Does this break YouTube's Terms of Service?
354
+
355
+ fm-dlp is an educational tool that demonstrates how public APIs and
356
+ open-source software can be combined. You are responsible for ensuring your
357
+ usage complies with the platform's Terms of Service and your local copyright
358
+ laws. Please support artists you enjoy.
359
+
360
+ ## 🐛 Troubleshooting
361
+
362
+ ### Configuration
363
+ | Issue | Solution |
364
+ |-------|----------|
365
+ | **Config file not found** | Run `fm-dlp config /your/download/path` first |
366
+ | **"Invalid path" error** | Ensure the directory exists and is writable |
367
+ | **Config reset after update** | `config.json` is preserved across updates — no action needed |
368
+
369
+ ### Dependencies
370
+ | Issue | Solution |
371
+ |-------|----------|
372
+ | **"FFmpeg is not installed"** | Install FFmpeg and verify: `ffmpeg -version`<br>• macOS: `brew install ffmpeg`<br>• Linux: `sudo apt install ffmpeg`<br>• Windows: `winget install ffmpeg` |
373
+ | **"Git is not installed"** | Required only for `update` command: `git --version` |
374
+
375
+ ### Search Issues
376
+ | Issue | Solution |
377
+ |-------|----------|
378
+ | **Album search returns no results** | Try different `--platform` (`yt-video` vs `yt-music`) or `--type` (`album` vs `track`) |
379
+ | **Too few results** | Increase limit: `--limit 20` |
380
+ | **Wrong content type** | Music search defaults to `track`. Use `--type album` for albums |
381
+
382
+ ### Download Issues
383
+ | Issue | Solution |
384
+ |-------|----------|
385
+ | **Age-restricted video** | Use browser cookies: `--cookies chrome` (or `firefox`, `edge`, `brave`) |
386
+ | **Network blocked / 403 error** | Use a proxy: `--proxy socks5://127.0.0.1:9050` |
387
+ | **Slow downloads** | Increase concurrent downloads: `--max-concurrent 10` |
388
+ | **Audio codec error in video** | Video containers auto-select compatible audio. Use `mp4` or `mkv` for best compatibility |
389
+ | **Video format not supported** | Supported containers: `mp4`, `mkv`, `webm`, `mov`, `avi`, `flv` |
390
+ | **WAV has no metadata** | WAV doesn't support embedded tags. Use `flac` or `m4a` instead |
391
+ | **Codec not available** | yt-dlp selects best available. Try `opus` (best quality) or `mp3` (compatibility) |
392
+
393
+ ### Update Issues
394
+ | Issue | Solution |
395
+ |-------|----------|
396
+ | **"Not a git repository"** | `update` only works if installed via `git clone`. ZIP downloads must be updated manually |
397
+ | **Update fails** | Check internet connection. Force update: `git -C /path/to/fm-dlp fetch origin && git -C /path/to/fm-dlp reset --hard origin/main` |
398
+
399
+ ### Proxy
400
+ | Issue | Solution |
401
+ |-------|----------|
402
+ | **"Invalid proxy URL"** | Format: `protocol://host:port`<br>• HTTP: `http://127.0.0.1:8080`<br>• SOCKS5: `socks5://127.0.0.1:9050` |
403
+ | **Proxy not working with yt-music** | yt-music only supports `http://` and `https://` proxies |
404
+
405
+ ---
406
+
407
+ ### Still stuck?
408
+ Run with verbose output to see detailed errors:
409
+ ```bash
410
+ fm-dlp download "URL" --no-quiet
411
+ ```
412
+
413
+ Check yt-dlp version compatibility:
414
+ ```bash
415
+ yt-dlp --version
416
+ ```
417
+
418
+ ## 📄 License
419
+
420
+ MIT License — see [LICENSE](LICENSE) file.
421
+
422
+ ## 🙏 Acknowledgments
423
+
424
+ - [yt-dlp](https://github.com/yt-dlp/yt-dlp) — YouTube extraction & download engine
425
+ - [ytmusicapi](https://github.com/sigma67/ytmusicapi) — YouTube Music API wrapper
426
+ - [mutagen](https://github.com/quodlibet/mutagen) — Audio metadata tagging
427
+ - [cyclopts](https://github.com/BrianPugh/cyclopts) — Modern CLI framework
428
+
429
+ ## ⚠️ Disclaimer
430
+
431
+ For educational purposes only. Users are responsible for complying with platform Terms of Service and applicable copyright laws.
432
+
433
+ ---
434
+
435
+ **Author:** [Fkernel653](https://github.com/Fkernel653)
436
+ **Repository:** [github.com/Fkernel653/fm-dlp](https://github.com/Fkernel653/fm-dlp)