mirror of
https://github.com/glomatico/gamdl.git
synced 2026-06-13 12:15:18 +03:00
Small changes
This commit is contained in:
@@ -3,7 +3,6 @@ import re
|
||||
import requests
|
||||
import urllib3
|
||||
import storefront_ids
|
||||
import json
|
||||
import m3u8
|
||||
from yt_dlp import YoutubeDL
|
||||
from pywidevine.L3.decrypt.wvdecrypt import WvDecrypt
|
||||
@@ -22,12 +21,15 @@ import traceback
|
||||
import subprocess
|
||||
|
||||
class Gamdl:
|
||||
def __init__(self, disable_music_video_skip, cookies_location, temp_path, prefer_hevc, final_path):
|
||||
def __init__(self, disable_music_video_skip, cookies_location, temp_path, prefer_hevc, final_path, skip_cleanup, print_video_playlist, no_lrc):
|
||||
self.disable_music_video_skip = disable_music_video_skip
|
||||
self.cookies_location = Path(cookies_location)
|
||||
self.temp_path = Path(temp_path)
|
||||
self.prefer_hevc = prefer_hevc
|
||||
self.final_path = Path(final_path)
|
||||
self.skip_cleanup = skip_cleanup
|
||||
self.print_video_playlist = print_video_playlist
|
||||
self.no_lrc = no_lrc
|
||||
self.login()
|
||||
|
||||
|
||||
@@ -103,15 +105,18 @@ class Gamdl:
|
||||
def get_webplayback(self, track_id):
|
||||
response = self.session.post(
|
||||
'https://play.itunes.apple.com/WebObjects/MZPlay.woa/wa/webPlayback',
|
||||
json.dumps({
|
||||
json = {
|
||||
'salableAdamId': track_id
|
||||
})
|
||||
}
|
||||
).json()["songList"][0]
|
||||
return response
|
||||
|
||||
|
||||
def get_playlist_music_video(self, webplayback):
|
||||
return m3u8.load(webplayback['hls-playlist-url'])
|
||||
playlist = m3u8.load(webplayback['hls-playlist-url'])
|
||||
if self.print_video_playlist:
|
||||
print(playlist.dumps())
|
||||
return playlist
|
||||
|
||||
|
||||
def get_stream_url_song(self, webplayback):
|
||||
@@ -157,14 +162,14 @@ class Gamdl:
|
||||
def get_license_b64(self, challenge, track_uri, track_id):
|
||||
return self.session.post(
|
||||
'https://play.itunes.apple.com/WebObjects/MZPlay.woa/wa/acquireWebPlaybackLicense',
|
||||
json.dumps({
|
||||
json = {
|
||||
'challenge': challenge,
|
||||
'key-system': 'com.widevine.alpha',
|
||||
'uri': track_uri,
|
||||
'adamId': track_id,
|
||||
'isLibrary': False,
|
||||
'user-initiated': True
|
||||
})
|
||||
}
|
||||
).json()['license']
|
||||
|
||||
|
||||
@@ -253,7 +258,6 @@ class Gamdl:
|
||||
'soar': [metadata['sort-artist']],
|
||||
'soal': [metadata['sort-album']],
|
||||
'sonm': [metadata['sort-name']],
|
||||
'\xa9alb': [metadata['playlistName']],
|
||||
'\xa9ART': [metadata['artistName']],
|
||||
'geID': [metadata['genreId']],
|
||||
'atID': [int(metadata['artistId'])],
|
||||
@@ -363,19 +367,40 @@ class Gamdl:
|
||||
|
||||
def fixup_music_video(self, decrypted_location_audio, decrypted_location_video, fixed_location, final_location):
|
||||
os.makedirs(final_location.parents[0], exist_ok = True)
|
||||
subprocess.check_output(['MP4Box', '-quiet', '-add', decrypted_location_audio, '-add', decrypted_location_video, '-itags', 'artist=placeholder', '-new', fixed_location])
|
||||
subprocess.check_output([
|
||||
'MP4Box',
|
||||
'-quiet',
|
||||
'-add',
|
||||
decrypted_location_audio,
|
||||
'-add',
|
||||
decrypted_location_video,
|
||||
'-itags',
|
||||
'artist=placeholder',
|
||||
'-new',
|
||||
fixed_location
|
||||
])
|
||||
shutil.copy(fixed_location, final_location)
|
||||
|
||||
|
||||
def fixup_song(self, decrypted_location, fixed_location, final_location):
|
||||
os.makedirs(final_location.parents[0], exist_ok = True)
|
||||
subprocess.check_output(['MP4Box', '-quiet', '-add', decrypted_location, '-itags', 'album=placeholder', '-new', fixed_location])
|
||||
subprocess.check_output([
|
||||
'MP4Box',
|
||||
'-quiet',
|
||||
'-add',
|
||||
decrypted_location,
|
||||
'-itags',
|
||||
'album=placeholder',
|
||||
'-new',
|
||||
fixed_location
|
||||
])
|
||||
shutil.copy(fixed_location, final_location)
|
||||
|
||||
|
||||
def make_lrc(self, final_location, lyrics):
|
||||
with open(final_location.with_suffix('.lrc'), 'w', encoding = 'utf8') as f:
|
||||
f.write(lyrics[1])
|
||||
if lyrics and lyrics[1] and not self.no_lrc:
|
||||
with open(final_location.with_suffix('.lrc'), 'w', encoding = 'utf8') as f:
|
||||
f.write(lyrics[1])
|
||||
|
||||
|
||||
def apply_tags(self, final_location, tags):
|
||||
@@ -385,6 +410,11 @@ class Gamdl:
|
||||
file.save(final_location)
|
||||
|
||||
|
||||
def cleanup(self):
|
||||
if self.temp_path.exists() and not self.skip_cleanup:
|
||||
shutil.rmtree(self.temp_path)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if not shutil.which('mp4decrypt'):
|
||||
raise Exception('mp4decrypt is not on PATH.')
|
||||
@@ -397,6 +427,13 @@ if __name__ == '__main__':
|
||||
nargs='*',
|
||||
metavar = '<url>'
|
||||
)
|
||||
parser.add_argument(
|
||||
'-u',
|
||||
'--urls-txt',
|
||||
help = 'Read URLs from a text file.',
|
||||
nargs = '?',
|
||||
metavar = '<txt_file>'
|
||||
)
|
||||
parser.add_argument(
|
||||
'-f',
|
||||
'--final-path',
|
||||
@@ -454,25 +491,27 @@ if __name__ == '__main__':
|
||||
action = 'store_true',
|
||||
help = 'Print Video M3U8 Playlist.'
|
||||
)
|
||||
parser.add_argument(
|
||||
'-u',
|
||||
'--urls-txt',
|
||||
help = 'Read URLs from a text file.',
|
||||
nargs = '?',
|
||||
metavar = '<txt_file>'
|
||||
)
|
||||
args = parser.parse_args()
|
||||
if not args.url and not args.urls_txt:
|
||||
parser.error('you must specify an url or a text file using -u/--urls-txt.')
|
||||
if args.urls_txt:
|
||||
with open(args.urls_txt, 'r', encoding = 'utf8') as f:
|
||||
args.url = f.read().splitlines()
|
||||
gamdl = Gamdl(args.disable_music_video_skip, args.cookies_location, args.temp_path, args.prefer_hevc, args.final_path)
|
||||
dl = Gamdl(
|
||||
args.disable_music_video_skip,
|
||||
args.cookies_location,
|
||||
args.temp_path,
|
||||
args.prefer_hevc,
|
||||
args.final_path,
|
||||
args.skip_cleanup,
|
||||
args.print_video_playlist,
|
||||
args.no_lrc
|
||||
)
|
||||
error_count = 0
|
||||
download_queue = []
|
||||
for i in range(len(args.url)):
|
||||
try:
|
||||
download_queue.append(gamdl.get_download_queue(args.url[i].strip()))
|
||||
download_queue.append(dl.get_download_queue(args.url[i].strip()))
|
||||
except KeyboardInterrupt:
|
||||
exit(1)
|
||||
except:
|
||||
@@ -480,48 +519,42 @@ if __name__ == '__main__':
|
||||
print(f'* Failed to check URL {i + 1}.')
|
||||
if args.print_exceptions:
|
||||
traceback.print_exc()
|
||||
if not download_queue:
|
||||
print('* Failed to check all URLs.')
|
||||
exit(1)
|
||||
for i in range(len(download_queue)):
|
||||
for j in range(len(download_queue[i])):
|
||||
print(f'Downloading "{download_queue[i][j]["title"]}" (track {j + 1} from URL {i + 1})...')
|
||||
track_id = download_queue[i][j]['track_id']
|
||||
try:
|
||||
webplayback = gamdl.get_webplayback(track_id)
|
||||
webplayback = dl.get_webplayback(track_id)
|
||||
if 'alt_track_id' in download_queue[i][j]:
|
||||
playlist = gamdl.get_playlist_music_video(webplayback)
|
||||
if args.print_video_playlist:
|
||||
print(playlist.dumps())
|
||||
stream_url_audio = gamdl.get_stream_url_music_video_audio(playlist)
|
||||
encrypted_location_audio = gamdl.get_encrypted_location('.m4a', track_id)
|
||||
gamdl.download(encrypted_location_audio, stream_url_audio)
|
||||
decrypted_location_audio = gamdl.get_decrypted_location('.m4a', track_id)
|
||||
gamdl.decrypt_music_video(decrypted_location_audio, encrypted_location_audio, stream_url_audio, track_id)
|
||||
stream_url_video = gamdl.get_stream_url_music_video_video(playlist)
|
||||
encrypted_location_video = gamdl.get_encrypted_location('.m4v', track_id)
|
||||
gamdl.download(encrypted_location_video, stream_url_video)
|
||||
decrypted_location_video = gamdl.get_decrypted_location('.m4v', track_id)
|
||||
gamdl.decrypt_music_video(decrypted_location_video, encrypted_location_video, stream_url_video, track_id)
|
||||
tags = gamdl.get_tags_music_video(download_queue[i][j]['alt_track_id'])
|
||||
fixed_location = gamdl.get_fixed_location('.m4v', track_id)
|
||||
final_location = gamdl.get_final_location('.m4v', tags)
|
||||
gamdl.fixup_music_video(decrypted_location_audio, decrypted_location_video, fixed_location, final_location)
|
||||
gamdl.apply_tags(final_location, tags)
|
||||
playlist = dl.get_playlist_music_video(webplayback)
|
||||
stream_url_audio = dl.get_stream_url_music_video_audio(playlist)
|
||||
encrypted_location_audio = dl.get_encrypted_location('.m4a', track_id)
|
||||
dl.download(encrypted_location_audio, stream_url_audio)
|
||||
decrypted_location_audio = dl.get_decrypted_location('.m4a', track_id)
|
||||
dl.decrypt_music_video(decrypted_location_audio, encrypted_location_audio, stream_url_audio, track_id)
|
||||
stream_url_video = dl.get_stream_url_music_video_video(playlist)
|
||||
encrypted_location_video = dl.get_encrypted_location('.m4v', track_id)
|
||||
dl.download(encrypted_location_video, stream_url_video)
|
||||
decrypted_location_video = dl.get_decrypted_location('.m4v', track_id)
|
||||
dl.decrypt_music_video(decrypted_location_video, encrypted_location_video, stream_url_video, track_id)
|
||||
tags = dl.get_tags_music_video(download_queue[i][j]['alt_track_id'])
|
||||
fixed_location = dl.get_fixed_location('.m4v', track_id)
|
||||
final_location = dl.get_final_location('.m4v', tags)
|
||||
dl.fixup_music_video(decrypted_location_audio, decrypted_location_video, fixed_location, final_location)
|
||||
dl.apply_tags(final_location, tags)
|
||||
else:
|
||||
stream_url = gamdl.get_stream_url_song(webplayback)
|
||||
encrypted_location = gamdl.get_encrypted_location('.m4a', track_id)
|
||||
gamdl.download(encrypted_location, stream_url)
|
||||
decrypted_location = gamdl.get_decrypted_location('.m4a', track_id)
|
||||
gamdl.decrypt_song(decrypted_location, encrypted_location, stream_url, track_id)
|
||||
lyrics = gamdl.get_lyrics(track_id)
|
||||
tags = gamdl.get_tags_song(webplayback, lyrics)
|
||||
fixed_location = gamdl.get_fixed_location('.m4a', track_id)
|
||||
final_location = gamdl.get_final_location('.m4a', tags)
|
||||
gamdl.fixup_song(decrypted_location, fixed_location, final_location)
|
||||
if not args.no_lrc and lyrics and lyrics[1]:
|
||||
gamdl.make_lrc(final_location, lyrics)
|
||||
gamdl.apply_tags(final_location, tags)
|
||||
stream_url = dl.get_stream_url_song(webplayback)
|
||||
encrypted_location = dl.get_encrypted_location('.m4a', track_id)
|
||||
dl.download(encrypted_location, stream_url)
|
||||
decrypted_location = dl.get_decrypted_location('.m4a', track_id)
|
||||
dl.decrypt_song(decrypted_location, encrypted_location, stream_url, track_id)
|
||||
lyrics = dl.get_lyrics(track_id)
|
||||
tags = dl.get_tags_song(webplayback, lyrics)
|
||||
fixed_location = dl.get_fixed_location('.m4a', track_id)
|
||||
final_location = dl.get_final_location('.m4a', tags)
|
||||
dl.fixup_song(decrypted_location, fixed_location, final_location)
|
||||
dl.make_lrc(final_location, lyrics)
|
||||
dl.apply_tags(final_location, tags)
|
||||
except KeyboardInterrupt:
|
||||
exit(1)
|
||||
except:
|
||||
@@ -529,6 +562,5 @@ if __name__ == '__main__':
|
||||
print(f'* Failed to download "{download_queue[i][j]["title"]}" (track {j + 1} from URL {i + 1}).')
|
||||
if args.print_exceptions:
|
||||
traceback.print_exc()
|
||||
if not args.skip_cleanup and gamdl.temp_path.exists():
|
||||
shutil.rmtree(gamdl.temp_path)
|
||||
print(f'Finished ({error_count} error(s)).')
|
||||
dl.cleanup()
|
||||
print(f'Done ({error_count} error(s)).')
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
class WvDecryptConfig(object):
|
||||
def __init__(self, decrypted_download_location, encrypted_download_location, init_data_b64):
|
||||
self.decrypted_download_location = str(decrypted_download_location)
|
||||
self.encrypted_download_location = str(encrypted_download_location)
|
||||
def __init__(self, decrypted_location, encrypted_location, init_data_b64):
|
||||
self.decrypted_location = str(decrypted_location)
|
||||
self.encrypted_location = str(encrypted_location)
|
||||
self.init_data_b64 = init_data_b64
|
||||
|
||||
def build_commandline_list(self, keys):
|
||||
@@ -12,6 +12,6 @@ class WvDecryptConfig(object):
|
||||
commandline.append('--key')
|
||||
default_KID = 1
|
||||
commandline.append('{}:{}'.format(str(default_KID), key.key.hex()))
|
||||
commandline.append(self.encrypted_download_location)
|
||||
commandline.append(self.decrypted_download_location)
|
||||
commandline.append(self.encrypted_location)
|
||||
commandline.append(self.decrypted_location)
|
||||
return commandline
|
||||
|
||||
Reference in New Issue
Block a user