from ytmusicapi import YTMusic import sys import os import subprocess from subprocess import Popen, PIPE, STDOUT try: from subprocess import DEVNULL # py3k except ImportError: import os DEVNULL = open(os.devnull, 'wb') output_dir = 'download' do_download = True ytmusic = YTMusic() while True: ## Pop item from top of list and write back file. with open('queue.txt', 'r') as file: lines = file.readlines() lines = [line.strip() for line in lines if line.strip()] artist_to_download = lines.pop(0) with open('queue.txt', 'w') as file: for line in lines: file.write(line + '\n') ## Artist exists already or other instance is downloading it. directory_path = output_dir+'/'+artist_to_download if os.path.exists(directory_path) and os.path.isdir(directory_path): print(f'Artist exists: {artist_to_download}, skipping.') continue artist_id_to_download = 0 ## Find artist id by name. search_results = ytmusic.search(artist_to_download, filter='artists') if search_results: for artist in search_results: artist_id_to_download = artist['browseId'] print(f"Found artist: {artist['artist']}, ID: {artist['browseId']}") break else: print(f"No artists found for {artist_to_download}") continue artist_result = ytmusic.get_artist(artist_id_to_download) artist_name = artist_result['name'] ## Collect albums and singles to download. albums = [] singles = [] if 'albums' in artist_result: albums = artist_result['albums']['results'] if artist_result['albums']['browseId'] != None: albums = ytmusic.get_artist_albums(artist_result["albums"]["browseId"], artist_result["albums"]["params"]) if 'singles' in artist_result: singles = artist_result['singles']['results'] if artist_result['singles']['browseId'] != None: singles = ytmusic.get_artist_albums(artist_result["singles"]["browseId"], artist_result["singles"]["params"]) ##################### #### 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'] 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: 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() ##################### #### 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'] 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: 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+'/Singles' if os.path.exists(directory_path) and os.path.isdir(directory_path): print(f'Downloaded "{single_name} ({index+1}/{len(singles)})"') else: print('Download failed') exit()