Added --output argument for output templating

This commit is contained in:
Mike Schwörer 2021-11-19 00:20:17 +01:00
parent ad43153d4c
commit 543567079b
No known key found for this signature in database
GPG Key ID: D3C7172E0A70F8CF
6 changed files with 57 additions and 32 deletions

View File

@ -47,12 +47,9 @@ def get_artist_albums(artist_id):
def download_album(album):
""" Downloads songs from an album """
artist, album_name = get_album_name(album)
artist_fixed = fix_filename(artist)
album_name_fixed = fix_filename(album_name)
tracks = get_album_tracks(album)
for n, track in tqdm(enumerate(tracks, start=1), unit_scale=True, unit='Song', total=len(tracks)):
download_track(track[ID], f'{artist_fixed}/{album_name_fixed}',
prefix=True, prefix_value=str(n), disable_progressbar=True)
download_track('album', track[ID], extra_keys={'album_num': str(n).zfill(2), 'artist': artist, 'album': album}, disable_progressbar=True)
def download_artist_albums(artist):

View File

@ -54,7 +54,7 @@ def client(args) -> None:
print(
'### SKIPPING: SONG DOES NOT EXIST ON SPOTIFY ANYMORE ###')
else:
download_track(song[TRACK][ID], 'Liked Songs/')
download_track('liked', song[TRACK][ID])
print('\n')
if args.search_spotify:
@ -75,7 +75,7 @@ def download_from_urls(urls: list[str]) -> bool:
if track_id is not None:
download = True
download_track(track_id)
download_track('single', track_id)
elif artist_id is not None:
download = True
download_artist_albums(artist_id)
@ -87,8 +87,7 @@ def download_from_urls(urls: list[str]) -> bool:
playlist_songs = get_playlist_songs(playlist_id)
name, _ = get_playlist_info(playlist_id)
for song in playlist_songs:
download_track(song[TRACK][ID],
fix_filename(name) + '/')
download_track('playlist', song[TRACK][ID], extra_keys={'playlist': name})
print('\n')
elif episode_id is not None:
download = True
@ -273,7 +272,7 @@ def search(search_term):
print_pos = dics.index(dic) + 1
if print_pos == position:
if dic['type'] == TRACK:
download_track(dic[ID])
download_track('single', dic[ID])
elif dic['type'] == ALBUM:
download_album(dic[ID])
elif dic['type'] == ARTIST:

View File

@ -20,6 +20,7 @@ LANGUAGE = 'LANGUAGE'
BITRATE = 'BITRATE'
SONG_ARCHIVE = 'SONG_ARCHIVE'
CREDENTIALS_LOCATION = 'CREDENTIALS_LOCATION'
OUTPUT = 'OUTPUT'
CONFIG_VALUES = {
ROOT_PATH: { 'default': '../ZSpotify Music/', 'type': str, 'arg': '--root-path' },
@ -37,8 +38,14 @@ CONFIG_VALUES = {
BITRATE: { 'default': '', 'type': str, 'arg': '--bitrate' },
SONG_ARCHIVE: { 'default': '.song_archive', 'type': str, 'arg': '--song-archive' },
CREDENTIALS_LOCATION: { 'default': 'credentials.json', 'type': str, 'arg': '--credentials-location' },
OUTPUT: { 'default': '', 'type': str, 'arg': '--output' },
}
OUTPUT_DEFAULT_PLAYLIST = '{playlist}/{artist} - {song_name}.{ext}'
OUTPUT_DEFAULT_PLAYLIST_EXT = '{playlist}/{playlist_num} - {artist} - {song_name}.{ext}'
OUTPUT_DEFAULT_LIKED_SONGS = 'Liked Songs/{artist} - {song_name}.{ext}'
OUTPUT_DEFAULT_SINGLE = '{artist} - {song_name}.{ext}'
OUTPUT_DEFAULT_ALBUM = '{artist}/{album}/{album_num} - {artist} - {song_name}.{ext}'
class Config:
Values = {}
@ -165,3 +172,20 @@ class Config:
@classmethod
def get_credentials_location(cls) -> str:
return cls.get(CREDENTIALS_LOCATION)
@classmethod
def get_output(cls, mode: str) -> str:
v = cls.get(OUTPUT)
if v:
return v
if mode == 'playlist':
return OUTPUT_DEFAULT_PLAYLIST
if mode == 'extplaylist':
return OUTPUT_DEFAULT_PLAYLIST_EXT
if mode == 'liked':
return OUTPUT_DEFAULT_LIKED_SONGS
if mode == 'single':
return OUTPUT_DEFAULT_SINGLE
if mode == 'album':
return OUTPUT_DEFAULT_ALBUM
raise ValueError()

View File

@ -54,8 +54,7 @@ def download_playlist(playlist):
p_bar = tqdm(playlist_songs, unit='song', total=len(playlist_songs), unit_scale=True)
enum = 1
for song in p_bar:
download_track(song[TRACK][ID], fix_filename(playlist[NAME].strip()) + '/',
prefix=True, prefix_value=str(enum) ,disable_progressbar=True)
download_track('extplaylist', song[TRACK][ID], extra_keys={'playlist': playlist, 'playlist_num': str(enum).zfill(2)}, disable_progressbar=True)
p_bar.set_description(song[TRACK][NAME])
enum += 1

View File

@ -69,39 +69,45 @@ def get_song_duration(song_id: str) -> float:
return duration
# noinspection PyBroadException
def download_track(track_id: str, extra_paths='', prefix=False, prefix_value='', disable_progressbar=False) -> None:
def download_track(mode: str, track_id: str, extra_keys={}, disable_progressbar=False) -> None:
""" Downloads raw song audio from Spotify """
try:
output_template = ZSpotify.CONFIG.get_output(mode)
(artists, album_name, name, image_url, release_year, disc_number,
track_number, scraped_song_id, is_playable, duration_ms) = get_song_info(track_id)
if ZSpotify.CONFIG.get_split_album_discs():
download_directory = os.path.join(os.path.dirname(
__file__), ZSpotify.CONFIG.get_root_path(), extra_paths, f'Disc {disc_number}')
else:
download_directory = os.path.join(os.path.dirname(
__file__), ZSpotify.CONFIG.get_root_path(), extra_paths)
song_name = fix_filename(artists[0]) + ' - ' + fix_filename(name)
if prefix:
song_name = f'{prefix_value.zfill(2)} - {song_name}' if prefix_value.isdigit(
) else f'{prefix_value} - {song_name}'
filename = os.path.join(
download_directory, f'{song_name}.{EXT_MAP.get(ZSpotify.CONFIG.get_download_format().lower())}')
for k in extra_keys:
output_template = output_template.replace("{"+k+"}", fix_filename(extra_keys[k]))
output_template = output_template.replace("{artist}", fix_filename(artists[0]))
output_template = output_template.replace("{album}", fix_filename(album_name))
output_template = output_template.replace("{song_name}", fix_filename(name))
output_template = output_template.replace("{release_year}", fix_filename(release_year))
output_template = output_template.replace("{disc_number}", fix_filename(disc_number))
output_template = output_template.replace("{track_number}", fix_filename(track_number))
output_template = output_template.replace("{id}", fix_filename(scraped_song_id))
output_template = output_template.replace("{track_id}", fix_filename(track_id))
output_template = output_template.replace("{ext}", EXT_MAP.get(ZSpotify.CONFIG.get_download_format().lower()))
filename = os.path.join(os.path.dirname(__file__), ZSpotify.CONFIG.get_root_path(), output_template)
filedir = os.path.dirname(filename)
check_name = os.path.isfile(filename) and os.path.getsize(filename)
check_id = scraped_song_id in get_directory_song_ids(download_directory)
check_id = scraped_song_id in get_directory_song_ids(filedir)
check_all_time = scraped_song_id in get_previously_downloaded()
# a song with the same name is installed
if not check_id and check_name:
c = len([file for file in os.listdir(download_directory)
if re.search(f'^{song_name}_', file)]) + 1
c = len([file for file in os.listdir(filedir) if re.search(f'^{filename}_', str(file))]) + 1
filename = os.path.join(
download_directory, f'{song_name}_{c}.{EXT_MAP.get(ZSpotify.CONFIG.get_download_format())}')
fname = os.path.splitext(os.path.basename(filename))[0]
ext = os.path.splitext(os.path.basename(filename))[1]
filename = os.path.join(filedir, f'{fname}_{c}{ext}')
except Exception as e:
@ -127,7 +133,7 @@ def download_track(track_id: str, extra_paths='', prefix=False, prefix_value='',
track_id = TrackId.from_base62(track_id)
stream = ZSpotify.get_content_stream(
track_id, ZSpotify.DOWNLOAD_QUALITY)
create_download_directory(download_directory)
create_download_directory(filedir)
total_size = stream.input_stream.size
with open(filename, 'wb') as file, tqdm(
@ -155,7 +161,7 @@ def download_track(track_id: str, extra_paths='', prefix=False, prefix_value='',
add_to_archive(scraped_song_id, artists[0], name)
# add song id to download directory's .song_ids file
if not check_id:
add_to_directory_song_ids(download_directory, scraped_song_id)
add_to_directory_song_ids(filedir, scraped_song_id)
if not ZSpotify.CONFIG.get_anti_ban_wait_time():
time.sleep(ZSpotify.CONFIG.get_anti_ban_wait_time())

View File

@ -256,4 +256,4 @@ def fix_filename(name):
>>> all('_' == fix_filename(chr(i)) for i in list(range(32)))
True
"""
return re.sub(r'[/\\:|<>"?*\0-\x1f]|^(AUX|COM[1-9]|CON|LPT[1-9]|NUL|PRN)(?![^.])|^\s|[\s.]$', "_", name, flags=re.IGNORECASE)
return re.sub(r'[/\\:|<>"?*\0-\x1f]|^(AUX|COM[1-9]|CON|LPT[1-9]|NUL|PRN)(?![^.])|^\s|[\s.]$', "_", str(name), flags=re.IGNORECASE)