gamdl 2.9.2__tar.gz → 3.0__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.
Files changed (69) hide show
  1. {gamdl-2.9.2 → gamdl-3.0}/PKG-INFO +114 -76
  2. {gamdl-2.9.2 → gamdl-3.0}/README.md +111 -75
  3. gamdl-3.0/gamdl/__init__.py +1 -0
  4. gamdl-3.0/gamdl/api/__init__.py +3 -0
  5. gamdl-3.0/gamdl/api/apple_music.py +603 -0
  6. gamdl-3.0/gamdl/api/constants.py +34 -0
  7. gamdl-3.0/gamdl/api/exceptions.py +25 -0
  8. gamdl-3.0/gamdl/api/itunes.py +147 -0
  9. {gamdl-2.9.2 → gamdl-3.0}/gamdl/cli/cli.py +143 -141
  10. {gamdl-2.9.2 → gamdl-3.0}/gamdl/cli/cli_config.py +172 -148
  11. gamdl-3.0/gamdl/cli/database.py +48 -0
  12. gamdl-3.0/gamdl/cli/interactive_prompts.py +232 -0
  13. {gamdl-2.9.2 → gamdl-3.0}/gamdl/cli/utils.py +29 -25
  14. gamdl-3.0/gamdl/downloader/__init__.py +9 -0
  15. {gamdl-2.9.2 → gamdl-3.0}/gamdl/downloader/amdecrypt.py +152 -20
  16. gamdl-2.9.2/gamdl/downloader/downloader_base.py → gamdl-3.0/gamdl/downloader/base.py +72 -131
  17. gamdl-3.0/gamdl/downloader/constants.py +3 -0
  18. gamdl-3.0/gamdl/downloader/downloader.py +269 -0
  19. gamdl-3.0/gamdl/downloader/enums.py +16 -0
  20. gamdl-3.0/gamdl/downloader/exceptions.py +25 -0
  21. gamdl-3.0/gamdl/downloader/music_video.py +213 -0
  22. gamdl-3.0/gamdl/downloader/song.py +181 -0
  23. gamdl-3.0/gamdl/downloader/types.py +15 -0
  24. gamdl-3.0/gamdl/downloader/uploaded_video.py +65 -0
  25. gamdl-3.0/gamdl/interface/__init__.py +8 -0
  26. gamdl-3.0/gamdl/interface/base.py +309 -0
  27. {gamdl-2.9.2 → gamdl-3.0}/gamdl/interface/constants.py +36 -0
  28. {gamdl-2.9.2 → gamdl-3.0}/gamdl/interface/enums.py +19 -0
  29. gamdl-3.0/gamdl/interface/exceptions.py +42 -0
  30. gamdl-3.0/gamdl/interface/interface.py +608 -0
  31. gamdl-3.0/gamdl/interface/music_video.py +426 -0
  32. gamdl-2.9.2/gamdl/interface/interface_song.py → gamdl-3.0/gamdl/interface/song.py +137 -116
  33. {gamdl-2.9.2 → gamdl-3.0}/gamdl/interface/types.py +39 -3
  34. gamdl-3.0/gamdl/interface/uploaded_video.py +126 -0
  35. gamdl-3.0/gamdl/interface/wvd.py +3 -0
  36. {gamdl-2.9.2 → gamdl-3.0}/gamdl/utils.py +0 -43
  37. {gamdl-2.9.2 → gamdl-3.0}/gamdl.egg-info/PKG-INFO +114 -76
  38. {gamdl-2.9.2 → gamdl-3.0}/gamdl.egg-info/SOURCES.txt +15 -11
  39. {gamdl-2.9.2 → gamdl-3.0}/gamdl.egg-info/requires.txt +2 -0
  40. {gamdl-2.9.2 → gamdl-3.0}/pyproject.toml +9 -1
  41. gamdl-2.9.2/gamdl/__init__.py +0 -1
  42. gamdl-2.9.2/gamdl/api/__init__.py +0 -2
  43. gamdl-2.9.2/gamdl/api/apple_music_api.py +0 -467
  44. gamdl-2.9.2/gamdl/api/constants.py +0 -170
  45. gamdl-2.9.2/gamdl/api/exceptions.py +0 -7
  46. gamdl-2.9.2/gamdl/api/itunes_api.py +0 -86
  47. gamdl-2.9.2/gamdl/downloader/__init__.py +0 -8
  48. gamdl-2.9.2/gamdl/downloader/constants.py +0 -46
  49. gamdl-2.9.2/gamdl/downloader/downloader.py +0 -617
  50. gamdl-2.9.2/gamdl/downloader/downloader_music_video.py +0 -285
  51. gamdl-2.9.2/gamdl/downloader/downloader_song.py +0 -248
  52. gamdl-2.9.2/gamdl/downloader/downloader_uploaded_video.py +0 -107
  53. gamdl-2.9.2/gamdl/downloader/enums.py +0 -38
  54. gamdl-2.9.2/gamdl/downloader/exceptions.py +0 -31
  55. gamdl-2.9.2/gamdl/downloader/hardcoded_wvd.py +0 -3
  56. gamdl-2.9.2/gamdl/downloader/types.py +0 -44
  57. gamdl-2.9.2/gamdl/interface/__init__.py +0 -6
  58. gamdl-2.9.2/gamdl/interface/interface.py +0 -161
  59. gamdl-2.9.2/gamdl/interface/interface_music_video.py +0 -380
  60. gamdl-2.9.2/gamdl/interface/interface_uploaded_video.py +0 -86
  61. {gamdl-2.9.2 → gamdl-3.0}/LICENSE +0 -0
  62. {gamdl-2.9.2 → gamdl-3.0}/gamdl/__main__.py +0 -0
  63. {gamdl-2.9.2 → gamdl-3.0}/gamdl/cli/__init__.py +0 -0
  64. {gamdl-2.9.2 → gamdl-3.0}/gamdl/cli/config_file.py +0 -0
  65. {gamdl-2.9.2 → gamdl-3.0}/gamdl/cli/constants.py +0 -0
  66. {gamdl-2.9.2 → gamdl-3.0}/gamdl.egg-info/dependency_links.txt +0 -0
  67. {gamdl-2.9.2 → gamdl-3.0}/gamdl.egg-info/entry_points.txt +0 -0
  68. {gamdl-2.9.2 → gamdl-3.0}/gamdl.egg-info/top_level.txt +0 -0
  69. {gamdl-2.9.2 → gamdl-3.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gamdl
3
- Version: 2.9.2
3
+ Version: 3.0
4
4
  Summary: A command-line app for downloading Apple Music songs, music videos and post videos.
5
5
  License-Expression: MIT
6
6
  Project-URL: Repository, https://github.com/glomatico/gamdl
@@ -12,11 +12,13 @@ Requires-Dist: click>=8.3.0
12
12
  Requires-Dist: colorama>=0.4.6
13
13
  Requires-Dist: dataclass-click>=1.0.4
14
14
  Requires-Dist: httpx>=0.28.1
15
+ Requires-Dist: httpx-retries>=0.4.6
15
16
  Requires-Dist: inquirerpy>=0.3.4
16
17
  Requires-Dist: m3u8>=6.0.0
17
18
  Requires-Dist: mutagen>=1.47.0
18
19
  Requires-Dist: pillow>=12.0.0
19
20
  Requires-Dist: pywidevine>=1.8.0
21
+ Requires-Dist: structlog>=25.5.0
20
22
  Requires-Dist: yt-dlp>=2025.10.22
21
23
  Dynamic: license-file
22
24
 
@@ -49,28 +51,43 @@ A command-line app for downloading Apple Music songs, music videos and post vide
49
51
  - **Firefox**: [Export Cookies](https://addons.mozilla.org/addon/export-cookies-txt)
50
52
  - **Chromium**: [Get cookies.txt LOCALLY](https://chromewebstore.google.com/detail/get-cookiestxt-locally/cclelndahbckbenkjhflpdbgdldlbecc)
51
53
 
52
- ### Optional
54
+ ### Dependencies
53
55
 
54
- Add these tools to your system PATH for additional features:
56
+ Add these tools to your system PATH or specify their paths via command-line arguments or the config file. The tools needed depend on which audio quality, video format, and download mode you want. Use the table below to find the required tools for your use case:
55
57
 
56
- - **[FFmpeg](https://ffmpeg.org/download.html)** - Required for `ffmpeg` music video remux mode
57
- - **[mp4decrypt](https://www.bento4.com/downloads/)** - Required for `mp4box` music video remux mode
58
- - **[MP4Box](https://gpac.io/downloads/gpac-nightly-builds/)** - Required for `mp4box` music video remux mode
59
- - **[N_m3u8DL-RE](https://github.com/nilaoda/N_m3u8DL-RE/releases/latest)** - Required for `nm3u8dlre` download mode, which is faster than the default downloader
60
- - **[Wrapper](#️-wrapper)** - For downloading songs in ALAC and other experimental codecs without API limitations
58
+ | Use Case | Configuration | Required Tools |
59
+ |---|---|---|
60
+ | **Songs in Legacy Codecs** | `song_codec_priority: aac-legacy\|aac-he-legacy` | None |
61
+ | **Songs in Non Legacy Codecs** | `song_codec_priority: aac\|aac-he\|aac-binaural\|aac-downmix\|aac-he-binaural\|aac-he-downmix\|atmos\|ac3`<br/>`use_wrapper: true` | Wrapper |
62
+ | **Music Videos** | `music_video_remux_mode: ffmpeg` | FFmpeg<br/>mp4decrypt |
63
+ | | `music_video_remux_mode: mp4box` | MP4Box<br/>mp4decrypt |
64
+ | **Faster Downloads** | `download_mode: nm3u8dlre` | N_m3u8DL-RE |
65
+
66
+ #### Tool Reference
67
+
68
+ | Tool | Download | Purpose |
69
+ |---|---|---|
70
+ | **FFmpeg** | [Windows](https://github.com/AnimMouse/ffmpeg-stable-autobuild/releases) / [Linux](https://johnvansickle.com/ffmpeg/) | Required for music video remuxing with FFmpeg mode |
71
+ | **MP4Box** | [Download](https://gpac.io/downloads/gpac-nightly-builds/) | Alternative for music video remuxing |
72
+ | **mp4decrypt** | [Download](https://www.bento4.com/downloads/) | Decrypts MP4 files when used with MP4Box |
73
+ | **N_m3u8DL-RE** | [Download](https://github.com/nilaoda/N_m3u8DL-RE/releases/latest) | Faster download alternative |
74
+ | **Wrapper** | [Download](https://github.com/WorldObservationLog/wrapper) | For downloading songs in ALAC and other experimental codecs |
61
75
 
62
76
  ## 📦 Installation
63
77
 
64
- **Install Gamdl via pip:**
78
+ 1. **Install Gamdl via pip:**
65
79
 
66
- ```bash
67
- pip install gamdl
68
- ```
80
+ ```bash
81
+ pip install gamdl
82
+ ```
69
83
 
70
- **Setup cookies:**
84
+ 2. **Set up the cookies file:**
85
+ - Place the cookies file in the working directory as `cookies.txt`, or
86
+ - Specify the path using `--cookies-path` or in the config file
71
87
 
72
- 1. Place your cookies file in the working directory as `cookies.txt`, or
73
- 2. Specify the path using `--cookies-path` or in the config file
88
+ 3. **Optional: Set up tools** (only if you need the functionality)
89
+
90
+ See the [Dependencies](#dependencies) section to determine which tools you need based on your use case, then follow the [Tool Reference](#tool-reference) for download and installation instructions.
74
91
 
75
92
  ## 🚀 Usage
76
93
 
@@ -138,54 +155,56 @@ The file is created automatically on first run. Command-line arguments override
138
155
  | `--log-level` | Logging level | `INFO` |
139
156
  | `--log-file` | Log file path | - |
140
157
  | `--no-exceptions` | Don't print exceptions | `false` |
158
+ | `--artist-auto-select` | Automatically select artist content to download (artist URLs) | - |
159
+ | `--database-path` | Path to the SQLite database file for registering downloaded media | - |
141
160
  | `--no-config-file`, `-n` | Don't use a config file | `false` |
142
161
  | **Apple Music Options** | | |
143
162
  | `--cookies-path`, `-c` | Cookies file path | `./cookies.txt` |
144
163
  | `--wrapper-account-url` | Wrapper account URL | `http://127.0.0.1:30020` |
145
164
  | `--language`, `-l` | Metadata language | `en-US` |
146
165
  | **Output Options** | | |
166
+ | `--cover-format` | Cover format | `jpg` |
167
+ | `--cover-size` | Cover size in pixels | `1200` |
168
+ | `--wvd-path` | .wvd file path | - |
169
+ | **Song Options** | | |
170
+ | `--synced-lyrics-format` | Synced lyrics format | `lrc` |
171
+ | `--song-codec-priority` | Comma-separated codec priority | `aac-legacy` |
172
+ | `--use-album-date` | Use album release date for songs | `false` |
173
+ | `--no-synced-lyrics` | Don't download synced lyrics | `false` |
174
+ | `--synced-lyrics-only` | Download only synced lyrics | `false` |
175
+ | **Music Video Options** | | |
176
+ | `--music-video-resolution` | Max music video resolution | `1080p` |
177
+ | `--music-video-codec-priority` | Comma-separated codec priority | `h264,h265` |
178
+ | `--music-video-remux-mode` | Remux mode | `ffmpeg` |
179
+ | `--music-video-remux-format` | Music video remux format | `m4v` |
180
+ | **Post Video Options** | | |
181
+ | `--uploaded-video-quality` | Post video quality | `best` |
182
+ | **Download & Path Options** | | |
147
183
  | `--output-path`, `-o` | Output directory path | `./Apple Music` |
148
184
  | `--temp-path` | Temporary directory path | `.` |
149
- | `--wvd-path` | .wvd file path | - |
150
- | `--overwrite` | Overwrite existing files | `false` |
151
- | `--save-cover`, `-s` | Save cover as separate file | `false` |
152
- | `--save-playlist` | Save M3U8 playlist file | `false` |
153
- | **Download Options** | | |
154
- | `--artist-auto-select` | Automatically select artist content to download (artist URLs) | - |
155
185
  | `--nm3u8dlre-path` | N_m3u8DL-RE executable path | `N_m3u8DL-RE` |
156
186
  | `--mp4decrypt-path` | mp4decrypt executable path | `mp4decrypt` |
157
187
  | `--ffmpeg-path` | FFmpeg executable path | `ffmpeg` |
158
188
  | `--mp4box-path` | MP4Box executable path | `MP4Box` |
159
- | `--use-wrapper` | Use wrapper | `false` |
189
+ | `--use-wrapper` | Use wrapper for decrypting songs | `false` |
160
190
  | `--wrapper-decrypt-ip` | Wrapper decryption server IP | `127.0.0.1:10020` |
161
191
  | `--download-mode` | Download mode | `ytdlp` |
162
- | `--cover-format` | Cover format | `jpg` |
163
192
  | **Template Options** | | |
164
193
  | `--album-folder-template` | Album folder template | `{album_artist}/{album}` |
165
194
  | `--compilation-folder-template` | Compilation folder template | `Compilations/{album}` |
166
195
  | `--no-album-folder-template` | No album folder template | `{artist}/Unknown Album` |
196
+ | `--playlist-folder-template` | Playlist folder template | `Playlists/{playlist_artist}/{playlist_title}` |
167
197
  | `--single-disc-file-template` | Single disc file template | `{track:02d} {title}` |
168
198
  | `--multi-disc-file-template` | Multi disc file template | `{disc}-{track:02d} {title}` |
169
199
  | `--no-album-file-template` | No album file template | `{title}` |
170
200
  | `--playlist-file-template` | Playlist file template | `Playlists/{playlist_artist}/{playlist_title}` |
171
201
  | `--date-tag-template` | Date tag template | `%Y-%m-%dT%H:%M:%SZ` |
172
202
  | `--exclude-tags` | Comma-separated tags to exclude | - |
173
- | `--cover-size` | Cover size in pixels | `1200` |
174
203
  | `--truncate` | Max filename length | - |
175
- | **Song Options** | | |
176
- | `--song-codec-priority` | Comma-separated codec priority | `aac-legacy` |
177
- | `--synced-lyrics-format` | Synced lyrics format | `lrc` |
178
- | `--no-synced-lyrics` | Don't download synced lyrics | `false` |
179
- | `--synced-lyrics-only` | Download only synced lyrics | `false` |
180
- | `--use-album-date` | Use album release date for songs | `false` |
181
- | `--fetch-extra-tags` | Fetch extra tags from preview (normalization and smooth playback) | `false` |
182
- | **Music Video Options** | | |
183
- | `--music-video-codec-priority` | Comma-separated codec priority | `h264,h265` |
184
- | `--music-video-remux-mode` | Remux mode | `ffmpeg` |
185
- | `--music-video-remux-format` | Music video remux format | `m4v` |
186
- | `--music-video-resolution` | Max music video resolution | `1080p` |
187
- | **Post Video Options** | | |
188
- | `--uploaded-video-quality` | Post video quality | `best` |
204
+ | **File Output Options** | | |
205
+ | `--overwrite` | Overwrite existing files | `false` |
206
+ | `--save-cover`, `-s` | Save cover as separate file | `false` |
207
+ | `--save-playlist` | Save M3U8 playlist file | `false` |
189
208
 
190
209
 
191
210
  ### Template Variables
@@ -216,6 +235,9 @@ The file is created automatically on first run. Command-line arguments override
216
235
 
217
236
  - `ytdlp`, `nm3u8dlre`
218
237
 
238
+ > [!NOTE]
239
+ > - **yt-dlp is only used as a file download library**. Media is still fetched directly from Apple Music's servers, and yt-dlp is only responsible for handling the file download process.
240
+
219
241
  ### Remux Mode
220
242
 
221
243
  - `ffmpeg`
@@ -304,7 +326,7 @@ Use Gamdl as a library in your Python projects:
304
326
  ```python
305
327
  import asyncio
306
328
 
307
- from gamdl.api import AppleMusicApi, ItunesApi
329
+ from gamdl.api import AppleMusicApi
308
330
  from gamdl.downloader import (
309
331
  AppleMusicBaseDownloader,
310
332
  AppleMusicDownloader,
@@ -313,63 +335,79 @@ from gamdl.downloader import (
313
335
  AppleMusicUploadedVideoDownloader,
314
336
  )
315
337
  from gamdl.interface import (
338
+ AppleMusicBaseInterface,
316
339
  AppleMusicInterface,
317
340
  AppleMusicMusicVideoInterface,
318
341
  AppleMusicSongInterface,
319
342
  AppleMusicUploadedVideoInterface,
320
343
  )
321
344
 
345
+
322
346
  async def main():
323
- # Create AppleMusicApi instance (from cookies or wrapper)
347
+ # Create AppleMusicApi instance from cookies
324
348
  apple_music_api = await AppleMusicApi.create_from_netscape_cookies(
325
349
  cookies_path="cookies.txt",
326
350
  )
327
- itunes_api = ItunesApi(
328
- apple_music_api.storefront,
329
- apple_music_api.language,
330
- )
331
351
 
332
352
  # Check subscription
333
- assert apple_music_api.active_subscription
334
-
335
- # Set up interfaces
336
- interface = AppleMusicInterface(apple_music_api, itunes_api)
337
- song_interface = AppleMusicSongInterface(interface)
338
- music_video_interface = AppleMusicMusicVideoInterface(interface)
339
- uploaded_video_interface = AppleMusicUploadedVideoInterface(interface)
340
-
341
- # Set up base downloader and specialized downloaders
342
- base_downloader = AppleMusicBaseDownloader()
343
- song_downloader = AppleMusicSongDownloader(
344
- base_downloader=base_downloader,
345
- interface=song_interface,
353
+ if not apple_music_api.active_subscription:
354
+ print("No active Apple Music subscription")
355
+ return
356
+
357
+ # Create base interface
358
+ base_interface = await AppleMusicBaseInterface.create(
359
+ apple_music_api=apple_music_api,
346
360
  )
347
- music_video_downloader = AppleMusicMusicVideoDownloader(
348
- base_downloader=base_downloader,
349
- interface=music_video_interface,
361
+
362
+ # Create specialized interfaces
363
+ song_interface = AppleMusicSongInterface(
364
+ base=base_interface,
365
+ )
366
+ music_video_interface = AppleMusicMusicVideoInterface(
367
+ base=base_interface,
350
368
  )
351
- uploaded_video_downloader = AppleMusicUploadedVideoDownloader(
352
- base_downloader=base_downloader,
353
- interface=uploaded_video_interface,
369
+ uploaded_video_interface = AppleMusicUploadedVideoInterface(
370
+ base=base_interface,
354
371
  )
355
372
 
356
- # Main downloader
357
- downloader = AppleMusicDownloader(
373
+ # Create main interface
374
+ interface = AppleMusicInterface(
375
+ song=song_interface,
376
+ music_video=music_video_interface,
377
+ uploaded_video=uploaded_video_interface,
378
+ )
379
+
380
+ # Create base downloader
381
+ base_downloader = AppleMusicBaseDownloader(
358
382
  interface=interface,
359
- base_downloader=base_downloader,
360
- song_downloader=song_downloader,
361
- music_video_downloader=music_video_downloader,
362
- uploaded_video_downloader=uploaded_video_downloader,
363
383
  )
364
384
 
365
- # Download a song
385
+ # Create specialized downloaders
386
+ song_downloader = AppleMusicSongDownloader(base=base_downloader)
387
+ music_video_downloader = AppleMusicMusicVideoDownloader(
388
+ base=base_downloader,
389
+ )
390
+ uploaded_video_downloader = AppleMusicUploadedVideoDownloader(base=base_downloader)
391
+
392
+ # Create main downloader
393
+ downloader = AppleMusicDownloader(
394
+ song=song_downloader,
395
+ music_video=music_video_downloader,
396
+ uploaded_video=uploaded_video_downloader,
397
+ )
398
+
399
+ # Download from URL
366
400
  url = "https://music.apple.com/us/album/never-gonna-give-you-up-2022-remaster/1624945511?i=1624945512"
367
- url_info = downloader.get_url_info(url)
368
- if url_info:
369
- download_queue = await downloader.get_download_queue(url_info)
370
- if download_queue:
371
- for download_item in download_queue:
372
- await downloader.download(download_item)
401
+
402
+ download_queue = []
403
+ async for media in downloader.get_download_item_from_url(url):
404
+ download_queue.append(media)
405
+
406
+ for download_item in download_queue:
407
+ try:
408
+ await downloader.download(download_item)
409
+ except Exception as e:
410
+ print(f"Error downloading: {e}")
373
411
 
374
412
 
375
413
  if __name__ == "__main__":
@@ -27,28 +27,43 @@ A command-line app for downloading Apple Music songs, music videos and post vide
27
27
  - **Firefox**: [Export Cookies](https://addons.mozilla.org/addon/export-cookies-txt)
28
28
  - **Chromium**: [Get cookies.txt LOCALLY](https://chromewebstore.google.com/detail/get-cookiestxt-locally/cclelndahbckbenkjhflpdbgdldlbecc)
29
29
 
30
- ### Optional
30
+ ### Dependencies
31
31
 
32
- Add these tools to your system PATH for additional features:
32
+ Add these tools to your system PATH or specify their paths via command-line arguments or the config file. The tools needed depend on which audio quality, video format, and download mode you want. Use the table below to find the required tools for your use case:
33
33
 
34
- - **[FFmpeg](https://ffmpeg.org/download.html)** - Required for `ffmpeg` music video remux mode
35
- - **[mp4decrypt](https://www.bento4.com/downloads/)** - Required for `mp4box` music video remux mode
36
- - **[MP4Box](https://gpac.io/downloads/gpac-nightly-builds/)** - Required for `mp4box` music video remux mode
37
- - **[N_m3u8DL-RE](https://github.com/nilaoda/N_m3u8DL-RE/releases/latest)** - Required for `nm3u8dlre` download mode, which is faster than the default downloader
38
- - **[Wrapper](#️-wrapper)** - For downloading songs in ALAC and other experimental codecs without API limitations
34
+ | Use Case | Configuration | Required Tools |
35
+ |---|---|---|
36
+ | **Songs in Legacy Codecs** | `song_codec_priority: aac-legacy\|aac-he-legacy` | None |
37
+ | **Songs in Non Legacy Codecs** | `song_codec_priority: aac\|aac-he\|aac-binaural\|aac-downmix\|aac-he-binaural\|aac-he-downmix\|atmos\|ac3`<br/>`use_wrapper: true` | Wrapper |
38
+ | **Music Videos** | `music_video_remux_mode: ffmpeg` | FFmpeg<br/>mp4decrypt |
39
+ | | `music_video_remux_mode: mp4box` | MP4Box<br/>mp4decrypt |
40
+ | **Faster Downloads** | `download_mode: nm3u8dlre` | N_m3u8DL-RE |
41
+
42
+ #### Tool Reference
43
+
44
+ | Tool | Download | Purpose |
45
+ |---|---|---|
46
+ | **FFmpeg** | [Windows](https://github.com/AnimMouse/ffmpeg-stable-autobuild/releases) / [Linux](https://johnvansickle.com/ffmpeg/) | Required for music video remuxing with FFmpeg mode |
47
+ | **MP4Box** | [Download](https://gpac.io/downloads/gpac-nightly-builds/) | Alternative for music video remuxing |
48
+ | **mp4decrypt** | [Download](https://www.bento4.com/downloads/) | Decrypts MP4 files when used with MP4Box |
49
+ | **N_m3u8DL-RE** | [Download](https://github.com/nilaoda/N_m3u8DL-RE/releases/latest) | Faster download alternative |
50
+ | **Wrapper** | [Download](https://github.com/WorldObservationLog/wrapper) | For downloading songs in ALAC and other experimental codecs |
39
51
 
40
52
  ## 📦 Installation
41
53
 
42
- **Install Gamdl via pip:**
54
+ 1. **Install Gamdl via pip:**
43
55
 
44
- ```bash
45
- pip install gamdl
46
- ```
56
+ ```bash
57
+ pip install gamdl
58
+ ```
47
59
 
48
- **Setup cookies:**
60
+ 2. **Set up the cookies file:**
61
+ - Place the cookies file in the working directory as `cookies.txt`, or
62
+ - Specify the path using `--cookies-path` or in the config file
49
63
 
50
- 1. Place your cookies file in the working directory as `cookies.txt`, or
51
- 2. Specify the path using `--cookies-path` or in the config file
64
+ 3. **Optional: Set up tools** (only if you need the functionality)
65
+
66
+ See the [Dependencies](#dependencies) section to determine which tools you need based on your use case, then follow the [Tool Reference](#tool-reference) for download and installation instructions.
52
67
 
53
68
  ## 🚀 Usage
54
69
 
@@ -116,54 +131,56 @@ The file is created automatically on first run. Command-line arguments override
116
131
  | `--log-level` | Logging level | `INFO` |
117
132
  | `--log-file` | Log file path | - |
118
133
  | `--no-exceptions` | Don't print exceptions | `false` |
134
+ | `--artist-auto-select` | Automatically select artist content to download (artist URLs) | - |
135
+ | `--database-path` | Path to the SQLite database file for registering downloaded media | - |
119
136
  | `--no-config-file`, `-n` | Don't use a config file | `false` |
120
137
  | **Apple Music Options** | | |
121
138
  | `--cookies-path`, `-c` | Cookies file path | `./cookies.txt` |
122
139
  | `--wrapper-account-url` | Wrapper account URL | `http://127.0.0.1:30020` |
123
140
  | `--language`, `-l` | Metadata language | `en-US` |
124
141
  | **Output Options** | | |
142
+ | `--cover-format` | Cover format | `jpg` |
143
+ | `--cover-size` | Cover size in pixels | `1200` |
144
+ | `--wvd-path` | .wvd file path | - |
145
+ | **Song Options** | | |
146
+ | `--synced-lyrics-format` | Synced lyrics format | `lrc` |
147
+ | `--song-codec-priority` | Comma-separated codec priority | `aac-legacy` |
148
+ | `--use-album-date` | Use album release date for songs | `false` |
149
+ | `--no-synced-lyrics` | Don't download synced lyrics | `false` |
150
+ | `--synced-lyrics-only` | Download only synced lyrics | `false` |
151
+ | **Music Video Options** | | |
152
+ | `--music-video-resolution` | Max music video resolution | `1080p` |
153
+ | `--music-video-codec-priority` | Comma-separated codec priority | `h264,h265` |
154
+ | `--music-video-remux-mode` | Remux mode | `ffmpeg` |
155
+ | `--music-video-remux-format` | Music video remux format | `m4v` |
156
+ | **Post Video Options** | | |
157
+ | `--uploaded-video-quality` | Post video quality | `best` |
158
+ | **Download & Path Options** | | |
125
159
  | `--output-path`, `-o` | Output directory path | `./Apple Music` |
126
160
  | `--temp-path` | Temporary directory path | `.` |
127
- | `--wvd-path` | .wvd file path | - |
128
- | `--overwrite` | Overwrite existing files | `false` |
129
- | `--save-cover`, `-s` | Save cover as separate file | `false` |
130
- | `--save-playlist` | Save M3U8 playlist file | `false` |
131
- | **Download Options** | | |
132
- | `--artist-auto-select` | Automatically select artist content to download (artist URLs) | - |
133
161
  | `--nm3u8dlre-path` | N_m3u8DL-RE executable path | `N_m3u8DL-RE` |
134
162
  | `--mp4decrypt-path` | mp4decrypt executable path | `mp4decrypt` |
135
163
  | `--ffmpeg-path` | FFmpeg executable path | `ffmpeg` |
136
164
  | `--mp4box-path` | MP4Box executable path | `MP4Box` |
137
- | `--use-wrapper` | Use wrapper | `false` |
165
+ | `--use-wrapper` | Use wrapper for decrypting songs | `false` |
138
166
  | `--wrapper-decrypt-ip` | Wrapper decryption server IP | `127.0.0.1:10020` |
139
167
  | `--download-mode` | Download mode | `ytdlp` |
140
- | `--cover-format` | Cover format | `jpg` |
141
168
  | **Template Options** | | |
142
169
  | `--album-folder-template` | Album folder template | `{album_artist}/{album}` |
143
170
  | `--compilation-folder-template` | Compilation folder template | `Compilations/{album}` |
144
171
  | `--no-album-folder-template` | No album folder template | `{artist}/Unknown Album` |
172
+ | `--playlist-folder-template` | Playlist folder template | `Playlists/{playlist_artist}/{playlist_title}` |
145
173
  | `--single-disc-file-template` | Single disc file template | `{track:02d} {title}` |
146
174
  | `--multi-disc-file-template` | Multi disc file template | `{disc}-{track:02d} {title}` |
147
175
  | `--no-album-file-template` | No album file template | `{title}` |
148
176
  | `--playlist-file-template` | Playlist file template | `Playlists/{playlist_artist}/{playlist_title}` |
149
177
  | `--date-tag-template` | Date tag template | `%Y-%m-%dT%H:%M:%SZ` |
150
178
  | `--exclude-tags` | Comma-separated tags to exclude | - |
151
- | `--cover-size` | Cover size in pixels | `1200` |
152
179
  | `--truncate` | Max filename length | - |
153
- | **Song Options** | | |
154
- | `--song-codec-priority` | Comma-separated codec priority | `aac-legacy` |
155
- | `--synced-lyrics-format` | Synced lyrics format | `lrc` |
156
- | `--no-synced-lyrics` | Don't download synced lyrics | `false` |
157
- | `--synced-lyrics-only` | Download only synced lyrics | `false` |
158
- | `--use-album-date` | Use album release date for songs | `false` |
159
- | `--fetch-extra-tags` | Fetch extra tags from preview (normalization and smooth playback) | `false` |
160
- | **Music Video Options** | | |
161
- | `--music-video-codec-priority` | Comma-separated codec priority | `h264,h265` |
162
- | `--music-video-remux-mode` | Remux mode | `ffmpeg` |
163
- | `--music-video-remux-format` | Music video remux format | `m4v` |
164
- | `--music-video-resolution` | Max music video resolution | `1080p` |
165
- | **Post Video Options** | | |
166
- | `--uploaded-video-quality` | Post video quality | `best` |
180
+ | **File Output Options** | | |
181
+ | `--overwrite` | Overwrite existing files | `false` |
182
+ | `--save-cover`, `-s` | Save cover as separate file | `false` |
183
+ | `--save-playlist` | Save M3U8 playlist file | `false` |
167
184
 
168
185
 
169
186
  ### Template Variables
@@ -194,6 +211,9 @@ The file is created automatically on first run. Command-line arguments override
194
211
 
195
212
  - `ytdlp`, `nm3u8dlre`
196
213
 
214
+ > [!NOTE]
215
+ > - **yt-dlp is only used as a file download library**. Media is still fetched directly from Apple Music's servers, and yt-dlp is only responsible for handling the file download process.
216
+
197
217
  ### Remux Mode
198
218
 
199
219
  - `ffmpeg`
@@ -282,7 +302,7 @@ Use Gamdl as a library in your Python projects:
282
302
  ```python
283
303
  import asyncio
284
304
 
285
- from gamdl.api import AppleMusicApi, ItunesApi
305
+ from gamdl.api import AppleMusicApi
286
306
  from gamdl.downloader import (
287
307
  AppleMusicBaseDownloader,
288
308
  AppleMusicDownloader,
@@ -291,63 +311,79 @@ from gamdl.downloader import (
291
311
  AppleMusicUploadedVideoDownloader,
292
312
  )
293
313
  from gamdl.interface import (
314
+ AppleMusicBaseInterface,
294
315
  AppleMusicInterface,
295
316
  AppleMusicMusicVideoInterface,
296
317
  AppleMusicSongInterface,
297
318
  AppleMusicUploadedVideoInterface,
298
319
  )
299
320
 
321
+
300
322
  async def main():
301
- # Create AppleMusicApi instance (from cookies or wrapper)
323
+ # Create AppleMusicApi instance from cookies
302
324
  apple_music_api = await AppleMusicApi.create_from_netscape_cookies(
303
325
  cookies_path="cookies.txt",
304
326
  )
305
- itunes_api = ItunesApi(
306
- apple_music_api.storefront,
307
- apple_music_api.language,
308
- )
309
327
 
310
328
  # Check subscription
311
- assert apple_music_api.active_subscription
312
-
313
- # Set up interfaces
314
- interface = AppleMusicInterface(apple_music_api, itunes_api)
315
- song_interface = AppleMusicSongInterface(interface)
316
- music_video_interface = AppleMusicMusicVideoInterface(interface)
317
- uploaded_video_interface = AppleMusicUploadedVideoInterface(interface)
318
-
319
- # Set up base downloader and specialized downloaders
320
- base_downloader = AppleMusicBaseDownloader()
321
- song_downloader = AppleMusicSongDownloader(
322
- base_downloader=base_downloader,
323
- interface=song_interface,
329
+ if not apple_music_api.active_subscription:
330
+ print("No active Apple Music subscription")
331
+ return
332
+
333
+ # Create base interface
334
+ base_interface = await AppleMusicBaseInterface.create(
335
+ apple_music_api=apple_music_api,
324
336
  )
325
- music_video_downloader = AppleMusicMusicVideoDownloader(
326
- base_downloader=base_downloader,
327
- interface=music_video_interface,
337
+
338
+ # Create specialized interfaces
339
+ song_interface = AppleMusicSongInterface(
340
+ base=base_interface,
341
+ )
342
+ music_video_interface = AppleMusicMusicVideoInterface(
343
+ base=base_interface,
328
344
  )
329
- uploaded_video_downloader = AppleMusicUploadedVideoDownloader(
330
- base_downloader=base_downloader,
331
- interface=uploaded_video_interface,
345
+ uploaded_video_interface = AppleMusicUploadedVideoInterface(
346
+ base=base_interface,
332
347
  )
333
348
 
334
- # Main downloader
335
- downloader = AppleMusicDownloader(
349
+ # Create main interface
350
+ interface = AppleMusicInterface(
351
+ song=song_interface,
352
+ music_video=music_video_interface,
353
+ uploaded_video=uploaded_video_interface,
354
+ )
355
+
356
+ # Create base downloader
357
+ base_downloader = AppleMusicBaseDownloader(
336
358
  interface=interface,
337
- base_downloader=base_downloader,
338
- song_downloader=song_downloader,
339
- music_video_downloader=music_video_downloader,
340
- uploaded_video_downloader=uploaded_video_downloader,
341
359
  )
342
360
 
343
- # Download a song
361
+ # Create specialized downloaders
362
+ song_downloader = AppleMusicSongDownloader(base=base_downloader)
363
+ music_video_downloader = AppleMusicMusicVideoDownloader(
364
+ base=base_downloader,
365
+ )
366
+ uploaded_video_downloader = AppleMusicUploadedVideoDownloader(base=base_downloader)
367
+
368
+ # Create main downloader
369
+ downloader = AppleMusicDownloader(
370
+ song=song_downloader,
371
+ music_video=music_video_downloader,
372
+ uploaded_video=uploaded_video_downloader,
373
+ )
374
+
375
+ # Download from URL
344
376
  url = "https://music.apple.com/us/album/never-gonna-give-you-up-2022-remaster/1624945511?i=1624945512"
345
- url_info = downloader.get_url_info(url)
346
- if url_info:
347
- download_queue = await downloader.get_download_queue(url_info)
348
- if download_queue:
349
- for download_item in download_queue:
350
- await downloader.download(download_item)
377
+
378
+ download_queue = []
379
+ async for media in downloader.get_download_item_from_url(url):
380
+ download_queue.append(media)
381
+
382
+ for download_item in download_queue:
383
+ try:
384
+ await downloader.download(download_item)
385
+ except Exception as e:
386
+ print(f"Error downloading: {e}")
351
387
 
352
388
 
353
389
  if __name__ == "__main__":
@@ -0,0 +1 @@
1
+ __version__ = "3.0"
@@ -0,0 +1,3 @@
1
+ from .apple_music import AppleMusicApi
2
+ from .exceptions import *
3
+ from .itunes import ItunesApi