#!/usr/bin/env python3 import datetime import glob import json import music_tag import os from pathlib import Path import sys import youtube_dl # MUSIC_DIRECTORY = "~/Music/" MUSIC_DIRECTORY = "./music/" AUDIO_OPTIONS = { 'format': 'mp3/bestaudio/best', 'cookiefile': 'cookies.txt', 'outtmpl': MUSIC_DIRECTORY + '%(title)s.%(ext)s', 'postprocessors': [ { 'key': 'FFmpegExtractAudio', 'preferredcodec': 'mp3', 'preferredquality': '192', }, {'key': 'FFmpegMetadata'}, ], 'writeinfojson': True } ytdl = youtube_dl.YoutubeDL(AUDIO_OPTIONS) def download_song(song_url): """ Download a song using youtube url and song title """ return ytdl.extract_info(song_url, download=True) def format_youtube_date(date): default = "Unknown Year" try: fmt = "%Y%m%d" d = datetime.datetime.strptime(date, fmt) return d.year except Exception as ex: print(ex) return default def get_all_files(directory): things = glob.glob(os.path.join(directory, '*.mp3')) files = [] for thing in things: if os.path.isfile(thing): files.append(thing) return files # TODO: Make this better with argparse def get_playlist_url(): return sys.argv[1] def get_video_urls_in_playlist(playlist_url): videos = ytdl.extract_info(playlist_url, download=False) urls = [] for vid in videos['entries']: if 'webpage_url' in vid.keys() and vid['webpage_url'] is not None: urls.append(vid['webpage_url']) return urls def move_file(file, metadata): # TODO: Move this to its own function to have our own jamos metadata? artist = 'unknownartist' album = 'unknownalbum' title = 'unknownsong' if ('artist' in metadata.keys()) and (metadata['artist'] is not None): if len(metadata['artist'].split(',')) > 1: # If there are multiple artists, pick the first one # NOTE: This may break if the artist has a comma in their name artist = metadata['artist'].split(',')[0].replace(' ', '_').lower() else: artist = metadata['artist'].replace(' ', '_').lower() if ('album' in metadata.keys()) and (metadata['album'] is not None): album = metadata['album'].replace(' ', '_').lower() if ('title' in metadata.keys()) and (metadata['title'] is not None): title = metadata['title'].replace(' ', '_').replace('/', '').lower() final_directory = os.path.join( MUSIC_DIRECTORY, artist, album) Path(final_directory).mkdir(parents=True, exist_ok=True) # TODO: Include album title in filename # TODO: Research converting to mp3 instead of just naming it such. # TODO: Research better file formats over mp3? os.rename( file, os.path.join(final_directory, artist + '_' + title + '.mp3')) def write_metadata_to_song_file(file, metadata): f = music_tag.load_file(file) artist = 'unknownartist' album = 'unknownalbum' title = 'unknownsong' year = 9999 if ('artist' in metadata.keys()) and (metadata['artist'] is not None): if len(metadata['artist'].split(',')) > 1: # If there are multiple artists, pick the first one # NOTE: This may break if the artist has a comma in their name artist = metadata['artist'].split(',')[0].replace(' ', '_').lower() else: artist = metadata['artist'].replace(' ', '_').lower() artist = artist.replace('&', 'and') if ('album' in metadata.keys()) and (metadata['album'] is not None): album = metadata['album'].replace(' ', '_').lower() if ('title' in metadata.keys()) and (metadata['title'] is not None): title = metadata['title'].replace(' ', '_').lower() if ('release_date' in metadata.keys()): year = format_youtube_date(metadata['release_date']) f['name'] = title f['artist'] = artist f['album'] = album f['year'] = year f.save() if __name__ == "__main__": # Get the playlist url from the command line playlist_url = get_playlist_url() urls = get_video_urls_in_playlist(playlist_url) for url in urls: try: # TODO: make this continue downloading if a song fails download_song(url) except Exception as ex: # TODO: Handle this a different way print(ex) files = get_all_files(MUSIC_DIRECTORY) for f in files: json_data = None with open(f.replace('.mp3', '.info.json')) as json_file: json_data = json.load(json_file) write_metadata_to_song_file(f, json_data) move_file(f, json_data)