mirror of
https://github.com/glomatico/gamdl.git
synced 2026-06-13 12:15:18 +03:00
heaac
This commit is contained in:
@@ -42,9 +42,9 @@ Some new features that I added:
|
||||
|
||||
## Usage
|
||||
```
|
||||
usage: gamdl [-h] [-u [URLS_TXT]] [-w WVD_LOCATION] [-f FINAL_PATH] [-t TEMP_PATH] [-c COOKIES_LOCATION] [-m] [-p]
|
||||
[-o] [-n] [-s] [-e] [-i] [-v]
|
||||
[url ...]
|
||||
usage: gamdl [-h] [-u [URLS_TXT]] [-w WVD_LOCATION] [-f FINAL_PATH] [-t TEMP_PATH] [-c COOKIES_LOCATION] [-m]
|
||||
[-p] [-a] [-o] [-n] [-s] [-e] [-i] [-v]
|
||||
[url ...]
|
||||
|
||||
Download Apple Music songs/music videos/albums/playlists
|
||||
|
||||
@@ -66,6 +66,7 @@ options:
|
||||
-m, --disable-music-video-skip
|
||||
Disable music video skip on playlists/albums (default: False)
|
||||
-p, --prefer-hevc Prefer HEVC over AVC (default: False)
|
||||
-a, --heaac Download songs/music videos with HE-AAC instead of AAC (default: False)
|
||||
-o, --overwrite Overwrite existing files (default: False)
|
||||
-n, --no-lrc Don't create .lrc file (default: False)
|
||||
-s, --skip-cleanup Skip cleanup (default: False)
|
||||
@@ -78,15 +79,15 @@ options:
|
||||
|
||||
## Songs/Music Videos quality
|
||||
* Songs:
|
||||
* 256kbps AAC
|
||||
* 256kbps AAC / HE-AAC 64kbps
|
||||
* Music Videos (varies depending on the video):
|
||||
* 4K HEVC 20mbps / AAC 256kbps
|
||||
* 4K HEVC 12mbps / AAC 256kbps
|
||||
* 1080p AVC 10mbps / AAC 256kbps
|
||||
* 1080p AVC 6.5bps / AAC 256kbps
|
||||
* 720p AVC 4mbps / AAC 256kbps
|
||||
* 480p AVC 2mbps / AAC 256kbps
|
||||
* 480p AVC 1.5mbps / AAC 256kbps
|
||||
* 360p AVC 1mbps / AAC 256kbps
|
||||
* 4K HEVC 20mbps, AAC 256kbps / HE-AAC 64kbps
|
||||
* 4K HEVC 12mbps, AAC 256kbps / HE-AAC 64kbps
|
||||
* 1080p AVC 10mbps, AAC 256kbps / HE-AAC 64kbps
|
||||
* 1080p AVC 6.5bps, AAC 256kbps / HE-AAC 64kbps
|
||||
* 720p AVC 4mbps, AAC 256kbps / HE-AAC 64kbps
|
||||
* 576p AVC 2mbps, AAC 256kbps / HE-AAC 64kbps
|
||||
* 480p AVC 1.5mbps, AAC 256kbps / HE-AAC 64kbps
|
||||
* 360p AVC 1mbps, AAC 256kbps / HE-AAC 64kbps
|
||||
|
||||
Some videos may include EIA-608 closed captions.
|
||||
|
||||
+23
-16
@@ -3,7 +3,7 @@ import argparse
|
||||
import traceback
|
||||
from .gamdl import Gamdl
|
||||
|
||||
__version__ = '1.6'
|
||||
__version__ = '1.8'
|
||||
|
||||
|
||||
def main():
|
||||
@@ -13,18 +13,18 @@ def main():
|
||||
raise Exception('MP4Box is not on PATH')
|
||||
parser = argparse.ArgumentParser(
|
||||
description = 'Download Apple Music songs/music videos/albums/playlists',
|
||||
formatter_class = argparse.ArgumentDefaultsHelpFormatter
|
||||
formatter_class = argparse.ArgumentDefaultsHelpFormatter,
|
||||
)
|
||||
parser.add_argument(
|
||||
'url',
|
||||
help = 'Apple Music song/music video/album/playlist URL(s)',
|
||||
nargs = '*'
|
||||
nargs = '*',
|
||||
)
|
||||
parser.add_argument(
|
||||
'-u',
|
||||
'--urls-txt',
|
||||
help = 'Read URLs from a text file',
|
||||
nargs = '?'
|
||||
nargs = '?',
|
||||
)
|
||||
parser.add_argument(
|
||||
'-w',
|
||||
@@ -36,67 +36,73 @@ def main():
|
||||
'-f',
|
||||
'--final-path',
|
||||
default = 'Apple Music',
|
||||
help = 'Final Path'
|
||||
help = 'Final Path',
|
||||
)
|
||||
parser.add_argument(
|
||||
'-t',
|
||||
'--temp-path',
|
||||
default = 'temp',
|
||||
help = 'Temp Path'
|
||||
help = 'Temp Path',
|
||||
)
|
||||
parser.add_argument(
|
||||
'-c',
|
||||
'--cookies-location',
|
||||
default = 'cookies.txt',
|
||||
help = 'Cookies location'
|
||||
help = 'Cookies location',
|
||||
)
|
||||
parser.add_argument(
|
||||
'-m',
|
||||
'--disable-music-video-skip',
|
||||
action = 'store_true',
|
||||
help = 'Disable music video skip on playlists/albums'
|
||||
help = 'Disable music video skip on playlists/albums',
|
||||
)
|
||||
parser.add_argument(
|
||||
'-p',
|
||||
'--prefer-hevc',
|
||||
action = 'store_true',
|
||||
help = 'Prefer HEVC over AVC'
|
||||
help = 'Prefer HEVC over AVC',
|
||||
)
|
||||
parser.add_argument(
|
||||
'-a',
|
||||
'--heaac',
|
||||
action = 'store_true',
|
||||
help = 'Download songs/music videos with HE-AAC instead of AAC',
|
||||
)
|
||||
parser.add_argument(
|
||||
'-o',
|
||||
'--overwrite',
|
||||
action = 'store_true',
|
||||
help = 'Overwrite existing files'
|
||||
help = 'Overwrite existing files',
|
||||
)
|
||||
parser.add_argument(
|
||||
'-n',
|
||||
'--no-lrc',
|
||||
action = 'store_true',
|
||||
help = "Don't create .lrc file"
|
||||
help = "Don't create .lrc file",
|
||||
)
|
||||
parser.add_argument(
|
||||
'-s',
|
||||
'--skip-cleanup',
|
||||
action = 'store_true',
|
||||
help = 'Skip cleanup'
|
||||
help = 'Skip cleanup',
|
||||
)
|
||||
parser.add_argument(
|
||||
'-e',
|
||||
'--print-exceptions',
|
||||
action = 'store_true',
|
||||
help = 'Print execeptions'
|
||||
help = 'Print execeptions',
|
||||
)
|
||||
parser.add_argument(
|
||||
'-i',
|
||||
'--print-video-m3u8-url',
|
||||
action = 'store_true',
|
||||
help = 'Print Video M3U8 URL'
|
||||
help = 'Print Video M3U8 URL',
|
||||
)
|
||||
parser.add_argument(
|
||||
'-v',
|
||||
'--version',
|
||||
action = 'version',
|
||||
version = f'%(prog)s {__version__}'
|
||||
version = f'%(prog)s {__version__}',
|
||||
)
|
||||
args = parser.parse_args()
|
||||
if not args.url and not args.urls_txt:
|
||||
@@ -109,11 +115,12 @@ def main():
|
||||
args.cookies_location,
|
||||
args.disable_music_video_skip,
|
||||
args.prefer_hevc,
|
||||
args.heaac,
|
||||
args.temp_path,
|
||||
args.final_path,
|
||||
args.no_lrc,
|
||||
args.overwrite,
|
||||
args.skip_cleanup
|
||||
args.skip_cleanup,
|
||||
)
|
||||
error_count = 0
|
||||
download_queue = []
|
||||
|
||||
+24
-18
@@ -17,9 +17,15 @@ from mutagen.mp4 import MP4, MP4Cover
|
||||
|
||||
|
||||
class Gamdl:
|
||||
def __init__(self, wvd_location, cookies_location, disable_music_video_skip, prefer_hevc, temp_path, final_path, no_lrc, overwrite, skip_cleanup):
|
||||
def __init__(self, wvd_location, cookies_location, disable_music_video_skip, prefer_hevc, heaac, temp_path, final_path, no_lrc, overwrite, skip_cleanup):
|
||||
self.disable_music_video_skip = disable_music_video_skip
|
||||
self.prefer_hevc = prefer_hevc
|
||||
if heaac:
|
||||
self.song_audio_quality = '32:ctrp64'
|
||||
self.music_video_audio_quality = 'audio-HE-stereo-64'
|
||||
else:
|
||||
self.song_audio_quality = '28:ctrp256'
|
||||
self.music_video_audio_quality = 'audio-stereo-256'
|
||||
self.temp_path = Path(temp_path)
|
||||
self.final_path = Path(final_path)
|
||||
self.no_lrc = no_lrc
|
||||
@@ -31,7 +37,7 @@ class Gamdl:
|
||||
self.cdm = Cdm.from_device(Device.load(Path(wvd_location[0])))
|
||||
self.cdm_session = self.cdm.open()
|
||||
cookies = MozillaCookieJar(Path(cookies_location))
|
||||
cookies.load(ignore_discard = True, ignore_expires = True)
|
||||
cookies.load(ignore_discard=True, ignore_expires=True)
|
||||
self.session = requests.Session()
|
||||
self.session.cookies.update(cookies)
|
||||
self.session.headers.update({
|
||||
@@ -47,7 +53,7 @@ class Gamdl:
|
||||
'Sec-Fetch-Dest': 'empty',
|
||||
'Sec-Fetch-Mode': 'cors',
|
||||
'Sec-Fetch-Site': 'same-site',
|
||||
'origin': 'https://beta.music.apple.com'
|
||||
'origin': 'https://beta.music.apple.com',
|
||||
})
|
||||
web_page = self.session.get('https://beta.music.apple.com').text
|
||||
index_js_uri = re.search('(?<=index\.)(.*?)(?=\.js")', web_page).group(1)
|
||||
@@ -81,14 +87,14 @@ class Gamdl:
|
||||
'https://play.itunes.apple.com/WebObjects/MZPlay.woa/wa/webPlayback',
|
||||
json = {
|
||||
'salableAdamId': track_id,
|
||||
'language': 'en-US'
|
||||
'language': 'en-US',
|
||||
}
|
||||
).json()["songList"][0]
|
||||
return response
|
||||
|
||||
|
||||
def get_stream_url_song(self, webplayback):
|
||||
return next(i for i in webplayback["assets"] if i["flavor"] == "28:ctrp256")['URL']
|
||||
return next(i for i in webplayback["assets"] if i["flavor"] == self.song_audio_quality)['URL']
|
||||
|
||||
|
||||
def get_stream_url_music_video(self, webplayback):
|
||||
@@ -102,7 +108,7 @@ class Gamdl:
|
||||
stream_url_video = playlist['formats'][-1]['url']
|
||||
else:
|
||||
stream_url_video = [i['url'] for i in playlist['formats'] if i['vcodec'] is not None and 'avc1' in i['vcodec']][-1]
|
||||
stream_url_audio = next(i['url'] for i in playlist['formats'] if 'audio-stereo-256' in i['format_id'])
|
||||
stream_url_audio = next(i['url'] for i in playlist['formats'] if self.music_video_audio_quality in i['format_id'])
|
||||
return stream_url_video, stream_url_audio
|
||||
|
||||
|
||||
@@ -138,7 +144,7 @@ class Gamdl:
|
||||
'allow_unplayable_formats': True,
|
||||
'fixup': 'never',
|
||||
'overwrites': self.overwrite,
|
||||
'external_downloader': 'aria2c'
|
||||
'external_downloader': 'aria2c',
|
||||
}) as ydl:
|
||||
ydl.download(stream_url)
|
||||
|
||||
@@ -152,7 +158,7 @@ class Gamdl:
|
||||
'uri': track_uri,
|
||||
'adamId': track_id,
|
||||
'isLibrary': False,
|
||||
'user-initiated': True
|
||||
'user-initiated': True,
|
||||
}
|
||||
).json()['license']
|
||||
|
||||
@@ -186,9 +192,9 @@ class Gamdl:
|
||||
encrypted_location,
|
||||
'--key',
|
||||
decryption_keys,
|
||||
decrypted_location
|
||||
decrypted_location,
|
||||
],
|
||||
check = True
|
||||
check=True
|
||||
)
|
||||
|
||||
|
||||
@@ -232,8 +238,8 @@ class Gamdl:
|
||||
|
||||
|
||||
def get_tags_song(self, webplayback, unsynced_lyrics):
|
||||
metadata = next(i for i in webplayback["assets"] if i["flavor"] == "28:ctrp256")['metadata']
|
||||
cover_url = next(i for i in webplayback["assets"] if i["flavor"] == "28:ctrp256")['artworkURL']
|
||||
metadata = next(i for i in webplayback["assets"] if i["flavor"] == self.song_audio_quality)['metadata']
|
||||
cover_url = next(i for i in webplayback["assets"] if i["flavor"] == self.song_audio_quality)['artworkURL']
|
||||
tags = {
|
||||
'\xa9nam': [metadata['itemName']],
|
||||
'\xa9gen': [metadata['genre']],
|
||||
@@ -254,7 +260,7 @@ class Gamdl:
|
||||
'disk': [(metadata['discNumber'], metadata['discCount'])],
|
||||
'trkn': [(metadata['trackNumber'], metadata['trackCount'])],
|
||||
'covr': [MP4Cover(self.get_cover(cover_url), MP4Cover.FORMAT_JPEG)],
|
||||
'stik': [1]
|
||||
'stik': [1],
|
||||
}
|
||||
if 'copyright' in metadata:
|
||||
tags['cprt'] = [metadata['copyright']]
|
||||
@@ -286,7 +292,7 @@ class Gamdl:
|
||||
'cnID': [metadata[0]["trackId"]],
|
||||
'geID': [int(extra_metadata['genres'][0]['genreId'])],
|
||||
'sfID': [int(self.storefront.split('-')[0])],
|
||||
'covr': [MP4Cover(self.get_cover(metadata[0]["artworkUrl30"].replace('30x30bb.jpg', '600x600bb.jpg')), MP4Cover.FORMAT_JPEG)]
|
||||
'covr': [MP4Cover(self.get_cover(metadata[0]["artworkUrl30"].replace('30x30bb.jpg', '600x600bb.jpg')), MP4Cover.FORMAT_JPEG)],
|
||||
}
|
||||
if 'copyright' in extra_metadata:
|
||||
tags['cprt'] = [extra_metadata['copyright']]
|
||||
@@ -361,9 +367,9 @@ class Gamdl:
|
||||
'-itags',
|
||||
'artist=placeholder',
|
||||
'-new',
|
||||
fixed_location
|
||||
fixed_location,
|
||||
],
|
||||
check = True
|
||||
check=True
|
||||
)
|
||||
|
||||
|
||||
@@ -377,9 +383,9 @@ class Gamdl:
|
||||
'-itags',
|
||||
'artist=placeholder',
|
||||
'-new',
|
||||
fixed_location
|
||||
fixed_location,
|
||||
],
|
||||
check = True
|
||||
check=True
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user