From 442a37a53564c02c7e1232af47b5e8e4d6860c9d Mon Sep 17 00:00:00 2001 From: Aldrik Ramaekers Date: Fri, 19 Dec 2025 21:23:17 +0100 Subject: error handling --- dl-artist.py | 189 +++++++++++++++++++++++++++++++---------------------------- 1 file changed, 98 insertions(+), 91 deletions(-) diff --git a/dl-artist.py b/dl-artist.py index 873c486..16f5730 100644 --- a/dl-artist.py +++ b/dl-artist.py @@ -10,6 +10,7 @@ import argparse import os import subprocess from subprocess import Popen, PIPE, STDOUT +import shutil try: from subprocess import DEVNULL # py3k @@ -47,12 +48,12 @@ if args.update: file.write(line + '\n') -def artist_is_external(name, complete_albums): +def remove_external_albums(name, complete_albums): directory_path = output_dir+'/'+name if not os.path.exists(directory_path): return False - album_titles = [album['title'] for album in complete_albums] + album_titles = [album['title'].replace("/", "-") for album in complete_albums] # / in title will break path. album_titles = album_titles.copy() album_titles.append('Singles') @@ -61,10 +62,15 @@ def artist_is_external(name, complete_albums): # Find albums that are on disk, but are not is discography list. unknown_albums = [elem for elem in filenames if elem not in album_titles] - if len(unknown_albums) > 0: - return True + for external_album in unknown_albums: + directory_path = output_dir+'/'+name+'/'+external_album + if os.path.exists(directory_path): + if not args.test: + shutil.rmtree(directory_path) + print(f'Deleted album "{name}/{external_album}"') - return False + + return True try: @@ -96,7 +102,7 @@ try: artist_result = ytmusic.get_artist(artist_id_to_download) - artist_name = artist_to_download #artist_result['name'] + artist_name = artist_to_download.replace("/", "-") # / in title will break path. #artist_result['name'] ## Collect albums and singles to download. albums = [] @@ -111,103 +117,104 @@ try: if artist_result['singles']['browseId'] != None: singles = ytmusic.get_artist_albums(artist_result["singles"]["browseId"], artist_result["singles"]["params"], 9999) - if artist_is_external(artist_name, albums): - print(f'Artist {artist_name} was downloaded externally and has been skipped.') - continue + remove_external_albums(artist_name, albums) # Check if artist albums and singles are downloaded already by counting. #directory_path = output_dir+'/'+artist_name+'/Singles' #existing_single_count = sum(1 for entry in os.listdir(directory_path) if os.path.isfile(os.path.join(directory_path, entry))) - directory_path = output_dir+'/'+artist_name.replace('/', r'\/') - existing_album_count = sum(1 for entry in os.listdir(directory_path) if os.path.isdir(os.path.join(directory_path, entry))) - if existing_album_count == len(albums)+1: # Ideally we check single count here too but we have no way to find out how many singles the artist actually has. - print(f'Artist {artist_name} is complete.') - continue + directory_path = output_dir+'/'+artist_name + if os.path.exists(directory_path): + existing_album_count = sum(1 for entry in os.listdir(directory_path) if os.path.isdir(os.path.join(directory_path, entry))) + if existing_album_count == len(albums)+1: # Ideally we check single count here too but we have no way to find out how many singles the artist actually has. + print(f'Artist {artist_name} is complete.') + continue # 1. Download albums print('Artist "' + artist_name + '" has ' + str(len(albums)) + ' albums...') for index, album in enumerate(albums): - albumdata = ytmusic.get_album(album['browseId']) - album_name = albumdata['title'] - - # Skip existing albums. - directory_path = output_dir+'/'+artist_name+'/'+album_name - if os.path.exists(directory_path) and os.path.isdir(directory_path): - print(f'Skipping existing album "{album_name}"') - continue - - print(f'Downloading "{album_name}"', end='\r') - - # Construct the command as a list - command = [ - './yt-dlp_linux', - f"https://music.youtube.com/playlist?list={albumdata['audioPlaylistId']}", - '-o', - output_dir+'/'+artist_name+'/'+album_name+'/%(title)s.%(ext)s', # Adjust the path as needed - '-x', - '--audio-format', - 'mp3', - '--embed-thumbnail', - '--add-metadata', - '--no-overwrites' - ] - - if not do_download: - print(f'Skipped download of album {album_name}') - continue - - p = subprocess.Popen(command, stdin=PIPE, stdout=DEVNULL, stderr=STDOUT) - (output, err) = p.communicate() - p_status = p.wait() - - directory_path = output_dir+'/'+artist_name+'/'+album_name - if os.path.exists(directory_path) and os.path.isdir(directory_path): - print(f'Downloaded "{album_name} ({index+1}/{len(albums)})"') - else: - print('Download failed') - exit() + while True: + albumdata = ytmusic.get_album(album['browseId']) + album_name = albumdata['title'].replace("/", "-") # / in title will break path. + + # Skip existing albums. + directory_path = output_dir+'/'+artist_name+'/'+album_name + if os.path.exists(directory_path) and os.path.isdir(directory_path): + print(f'Skipping existing album "{album_name}"') + break + + print(f'Downloading "{album_name}"', end='\r') + + # Construct the command as a list + command = [ + './yt-dlp_linux', + f"https://music.youtube.com/playlist?list={albumdata['audioPlaylistId']}", + '-o', + output_dir+'/'+artist_name+'/'+album_name+'/%(title)s.%(ext)s', # Adjust the path as needed + '-x', + '--audio-format', + 'mp3', + '--embed-thumbnail', + '--add-metadata', + '--no-overwrites' + ] + + if not do_download: + print(f'Skipped download of album {album_name}') + break + + p = subprocess.Popen(command, stdin=PIPE, stdout=DEVNULL, stderr=STDOUT) + (output, err) = p.communicate() + p_status = p.wait() + + directory_path = output_dir+'/'+artist_name+'/'+album_name + if os.path.exists(directory_path) and os.path.isdir(directory_path): + print(f'({index+1}/{len(albums)}) Downloaded "{album_name}"') + break + else: + print('Download failed') # 2. Download singles print('Artist "' + artist_name + '" has ' + str(len(singles)) + ' singles...') for index, single in enumerate(singles): - singledata = ytmusic.get_album(single['browseId']) - single_name = singledata['title'] - - # Skip existing albums. - directory_path = output_dir+'/'+artist_name+'/Singles/'+single_name+'.mp3' - if os.path.exists(directory_path): - print(f'Skipping existing single "{single_name}"') - continue - - print(f'Downloading "{single_name}"', end='\r') - - # Construct the command as a list - command = [ - './yt-dlp_linux', - f"https://music.youtube.com/playlist?list={singledata['audioPlaylistId']}", - '-o', - output_dir+'/'+artist_name+'/Singles/%(title)s.%(ext)s', # Adjust the path as needed - '-x', - '--audio-format', - 'mp3', - '--embed-thumbnail', - '--add-metadata', - '--no-overwrites' - ] - - if not do_download: - print(f'Skipped download of single {single_name}') - continue - - p = subprocess.Popen(command, stdin=PIPE, stdout=DEVNULL, stderr=STDOUT) - (output, err) = p.communicate() - p_status = p.wait() - - if os.path.exists(directory_path): - print(f'Downloaded "{single_name} ({index+1}/{len(singles)})"') - else: - print('Download failed') - exit() + while True: + singledata = ytmusic.get_album(single['browseId']) + single_name = singledata['title'].replace("/", "-") # / in title will break path. + + # Skip existing albums. + directory_path = output_dir+'/'+artist_name+'/Singles/'+single_name+'.mp3' + if os.path.exists(directory_path): + print(f'Skipping existing single "{single_name}"') + break + + print(f'Downloading "{single_name}"', end='\r') + + # Construct the command as a list + command = [ + './yt-dlp_linux', + f"https://music.youtube.com/playlist?list={singledata['audioPlaylistId']}", + '-o', + output_dir+'/'+artist_name+'/Singles/%(title)s.%(ext)s', # Adjust the path as needed + '-x', + '--audio-format', + 'mp3', + '--embed-thumbnail', + '--add-metadata', + '--no-overwrites' + ] + + if not do_download: + print(f'Skipped download of single {single_name}') + break + + p = subprocess.Popen(command, stdin=PIPE, stdout=DEVNULL, stderr=STDOUT) + (output, err) = p.communicate() + p_status = p.wait() + + #if os.path.exists(directory_path): + print(f'({index+1}/{len(singles)}) Downloaded "{single_name}"') + break + #else: + # print('Download failed') except KeyboardInterrupt: print('Download cancelled') -- cgit v1.2.3-70-g09d2