diff options
author | Jackson Taylor <jackson@jacksontaylor.xyz> | 2023-04-16 22:14:44 -0400 |
---|---|---|
committer | Jackson Taylor <jackson@jacksontaylor.xyz> | 2023-04-16 22:14:44 -0400 |
commit | 7bda15b7d5d034ce2be4293693b2a84ce4b40c3d (patch) | |
tree | 3a0984160cb336fc4a6abc1f1e1ced8ee40d1b5e | |
parent | d4a30fead6bf904e3a0db28034f2549521e1497b (diff) |
-rwxr-xr-x | jamos | 251 |
1 files changed, 157 insertions, 94 deletions
@@ -1,7 +1,6 @@ #!/usr/bin/env python3 import argparse import collections -import datetime import glob import json import music_tag @@ -37,6 +36,17 @@ How the albums will be formatted: """ ALBUMS = collections.defaultdict(lambda: None) +# Array to save any failed songs and their reasons +FAILED_SONGS = [] + + +class UnableToCreateAlbumDirectoryError(Exception): + pass + + +class UnableToFindThumbnailFileError(Exception): + pass + def get_command_line_options(): parser = argparse.ArgumentParser( @@ -211,9 +221,9 @@ def save_album(app, args, album_id): with open(filename, 'wb') as f: shutil.copyfileobj(r.raw, f) - print('Image sucessfully Downloaded: ', filename) + print('Thumbnail sucessfully Downloaded: {}'.format(filename)) else: - print('Image Couldn\'t be retreived') + print('Thumbnail could not be retrieved: {}'.format(filename)) parsed_album['thumbnail_filepath'] = filename except Exception as ex: @@ -282,58 +292,58 @@ def get_library_songs(app, args, order='a_to_z'): return all_parsed_songs -def stuff(): - # TODO: Can you use the cookies from YTMusic here - # cookies = os.path.join(os.path.expanduser("~"), "cookies.txt") - cookies = './cookies.txt' - ytdl = create_downloader(music_directory, cookies) - - failed_songs = [] - for song in []: - try: - ytdl.extract_info(song['url'], download=True) - except Exception as ex: - print(ex) - print("Could not download: {}".format((song))) - failed_songs.append(song) - - failed_songs = [] - - for song in all_songs: - try: - print("Downloading: {} - {} - {} from {}...".format( - song['title'], song['artist'], song['album'], song['url']), - end='') - ytdl.extract_info(song['url'], download=True) - sys.exit() - print("Done.") - except Exception as ex: - print(ex) - print("Could not download: {}".format((song['url']))) - failed_songs.append(song) - - files = get_all_files(music_directory) - - counter = 1 - for f in files: - try: - print("Adding metadata to {} ...".format(f), end="") - with open(f.replace('.mp3', '.info.json')) as json_file: - json_data = json.load(json_file) - metadata = get_song_metadata_from_json(json_data, counter) - write_metadata_to_song_file(f, metadata) - print("Done") - print("Moving file...", end="") - move_file(f, metadata, music_directory) - print("Done") - counter += 1 - except Exception as e: - # just gonna print this and move on to the next file. - print(e) - - print("Cleaning up JSON files...", end='') - cleanup_metadata_files(music_directory) - print("Done.") +# def stuff(): +# # TODO: Can you use the cookies from YTMusic here +# # cookies = os.path.join(os.path.expanduser("~"), "cookies.txt") +# cookies = './cookies.txt' +# ytdl = create_downloader(music_directory, cookies) + +# failed_songs = [] +# for song in []: +# try: +# ytdl.extract_info(song['url'], download=True) +# except Exception as ex: +# print(ex) +# print("Could not download: {}".format((song))) +# failed_songs.append(song) + +# failed_songs = [] + +# for song in songs: +# try: +# print("Downloading: {} - {} - {} from {}...".format( +# song['title'], song['artist'], song['album'], song['url']), +# end='') +# ytdl.extract_info(song['url'], download=True) +# sys.exit() +# print("Done.") +# except Exception as ex: +# print(ex) +# print("Could not download: {}".format((song['url']))) +# failed_songs.append(song) + +# files = get_all_files(music_directory) + +# counter = 1 +# for f in files: +# try: +# print("Adding metadata to {} ...".format(f), end="") +# with open(f.replace('.mp3', '.info.json')) as json_file: +# json_data = json.load(json_file) +# metadata = get_song_metadata_from_json(json_data, counter) +# write_metadata_to_song_file(f, metadata) +# print("Done") +# print("Moving file...", end="") +# move_file(f, metadata, music_directory) +# print("Done") +# counter += 1 +# except Exception as e: +# # just gonna print this and move on to the next file. +# print(e) + +# print("Cleaning up JSON files...", end='') +# cleanup_metadata_files(music_directory) +# print("Done.") # TODO: Implement @@ -374,69 +384,122 @@ def handle_downloading_playlist(): # [s for s in new_filename if s.isalnum() or s == '_'])).lower() # return new_filename - -if __name__ == "__main__": +def tag_song(filename, song_data): try: - args = get_command_line_options() - except Exception as ex: - print(ex) - sys.exit() - - music_directory = args.output - - app = create_youtube_music_api_object(args.headers) - - all_songs = get_library_songs(app, args) - - ytdl = create_downloader(music_directory) - - for song in all_songs: - # download song - ytdl.extract_info(song['url'], download=True) - - # get filename song was downloaded to - filenames = glob.glob(os.path.join(music_directory, song['id'] + '.*')) - filename = filenames[0] - # tag basic data file = music_tag.load_file(filename) - file['name'] = song['title'] - file['artist'] = song['artists'][0] - file['albumartist'] = song['artists'][0] - file['album'] = song['album'] - file['tracknumber'] = song['track'] - file['year'] = song['year'] + file['name'] = song_data['title'] + file['artist'] = song_data['artists'][0] + file['albumartist'] = song_data['artists'][0] + file['album'] = song_data['album'] + file['tracknumber'] = song_data['track'] + file['year'] = song_data['year'] # include album cover try: # NOTE: this will be at least None - if song['thumbnail_filepath']: - with open(song['thumbnail_filepath'], 'rb') as img_in: + if song_data['thumbnail_filepath']: + with open(song_data['thumbnail_filepath'], 'rb') as img_in: file['artwork'] = img_in.read() - except Exception as ex: - print(ex) + + except Exception: + raise UnableToFindThumbnailFileError() # save music tag data file.save() + except Exception: + print("could not tag song!") + +def move_song_to_permanent_location(music_directory, song_data, filename): + try: # move song to music_directory/artist/album/artist_album_title.ext # excluding non filesafe characters - artist_for_filename = remove_special_characters_for_filename( - song['artists'][0]) + song_data['artists'][0]) album_for_filename = remove_special_characters_for_filename( - song['album']) + song_data['album']) title_for_filename = remove_special_characters_for_filename( - song['title']) + song_data['title']) + song_output_dir = os.path.join(music_directory, artist_for_filename, album_for_filename) - Path(song_output_dir).mkdir(parents=True, exist_ok=True) + try: + Path(song_output_dir).mkdir(parents=True, exist_ok=True) + except OSError as ex: + raise UnableToCreateAlbumDirectoryError(ex) new_filename = '{}_{}_{}.mp3'.format(artist_for_filename, album_for_filename, title_for_filename) shutil.move(filename, os.path.join(song_output_dir, new_filename)) - print("done") + except Exception: + print("could not move file to correct directory!") + + +def download_songs(ytdl, music_directory, songs): + for song in songs: + try: + # download song + ytdl.extract_info(song['url'], download=True) + + # get filename song was downloaded to + filenames = glob.glob( + os.path.join(music_directory, song['id'] + '.*')) + filename = filenames[0] + + if not filename: + raise FileNotFoundError() + + tag_song(filename, song) + + move_song_to_permanent_location(music_directory, song, filename) + except UnableToCreateAlbumDirectoryError as ex: + add_to_failed_songs(song, ex) + print('Could not download {} - {}, moving on'.format( + song['title'], + song['artists'][0])) + except FileNotFoundError: + error_reason = 'Thought song downloaded, but filename was None' + add_to_failed_songs(song, error_reason) + print('Could not download {} - {}, moving on'.format( + song['title'], + song['artists'][0])) + + except Exception: + add_to_failed_songs( + song, + 'Unknown exception while downloading song.') + print('Could not download {} - {}, moving on'.format( + song['title'], + song['artists'][0])) + + +def add_to_failed_songs(song, reason): + song['error_reason'] = reason + global FAILED_SONGS + FAILED_SONGS.append(song) + + +if __name__ == "__main__": + try: + args = get_command_line_options() + + music_directory = args.output + + app = create_youtube_music_api_object(args.headers) + + songs = get_library_songs(app, args) + + ytdl = create_downloader(music_directory) + + download_songs(ytdl, music_directory, songs) + + except Exception as ex: + print(ex) + sys.exit() + + print("Complete.") |