def createYTPlaylist(playlistname, description, listSongs): #Parameters: YTMusic playlist name, description, and the list of songs to be uploaded to the playlist #Returns: A YTMusic playlist with the designated name/description, with the list of songs in the playlist ytmusic = YTMusic('headers_auth.json') failed = [] playlistID = ytmusic.create_playlist(playlistname, description) printProgressBar(0, len(listSongs), prefix='uploading songs...:', suffix='Complete', length=50) i = 0 for song in listSongs: try: printProgressBar(i + 1, len(listSongs), prefix='uploading songs...:', suffix='Complete', length=50) search_results = ytmusic.search(song, "songs") ytmusic.add_playlist_items(playlistID, [search_results[0]['videoId']]) i += 1 except Exception as e: failed.append("failed on song: " + song + " from err. " + str(e)) print("completed")
def export_song_data(name, data, dry_run): if not os.path.exists(AUTH_FILE): YTMusic.setup(filepath=AUTH_FILE) ytmusic = YTMusic(AUTH_FILE) song_ids = data_to_song_ids(ytmusic, data) print("Found %d/%d tracks on YouTube Music." % (len(song_ids), len(data))) if song_ids and not dry_run: playlist_id = ytmusic.create_playlist(name, "Auto-generated playlist") ytmusic.add_playlist_items(playlist_id, song_ids) print("Created playlist \"%s\"." % name)
def main(): print('Initializing...') playlist_name = datetime.now().strftime("%A, %d. %B %Y %I:%M%p") ytmusic = YTMusic('headers_auth.json') print('Retrieving songs...') songs = ytmusic.get_library_songs(limit=10000) song_ids = list(map(lambda x: x['videoId'], songs)) print('Creating playlist...') playlist = ytmusic.create_playlist(playlist_name, 'Automatically created playlist') print('Adding songs to playlist...') ytmusic.add_playlist_items(playlist, song_ids) print('Done.')
def AddToPlaylist(ytmusic: YTMusic, playlistId: str, videoId: str, duplicates: bool = False) -> bool: status = ytmusic.add_playlist_items(playlistId, videoIds=[videoId], duplicates=duplicates) if status['status'] == "STATUS_SUCCEEDED": return True else: print(f"AddtoPlaylist Error: Could not add {videoId}") return False
def UpdatePlaylist(ytmusic: YTMusic, playlistId: str, videoResults, description=str, excludeDisliked=bool, clearPlaylist=bool): try: currentSongCount = ytmusic.get_playlist(playlistId, limit=1)["trackCount"] except Exception as e: return e if currentSongCount > 0 and clearPlaylist: currentPlaylist = ytmusic.get_playlist(playlistId, limit=currentSongCount) ytmusic.remove_playlist_items(playlistId, currentPlaylist['tracks']) addedVideos = False for videoId in videoResults['videoIds']: status = ytmusic.add_playlist_items(playlistId, videoIds=[videoId]) if status['status'] == "STATUS_SUCCEEDED": addedVideos = True else: print(status) if addedVideos: if description is None: nowFormatted = datetime.now().strftime("%Y-%m-%d at %H:%M") description = ( f"Last updated {nowFormatted}.\nStation played " f"{videoResults['searchCount']} songs.\n" f"{videoResults['uniqueCount']} songs were unique.\n" f"YTMusic match {videoResults['matchedCount']} songs.") if excludeDisliked: description = ( f"{description}\n\nNote: Songs I've marked as " f"\"dislike\" were not included in the playlist.") ytmusic.edit_playlist(playlistId, description=description) return True else: print("There was an error adding songs to the playlist.") return False
class YTMusicTransfer: def __init__(self): self.api = YTMusic(settings['youtube']['headers'], settings['youtube']['user_id']) def create_playlist(self, name, info, privacy="PRIVATE", tracks=None): return self.api.create_playlist(name, info, privacy, video_ids=tracks) def get_best_fit_song_id(self, results, song): match_score = {} title_score = {} for res in results: if res['resultType'] not in ['song', 'video']: continue durationMatch = None if 'duration' in res and res['duration']: durationItems = res['duration'].split(':') duration = int(durationItems[0]) * 60 + int(durationItems[1]) durationMatch = 1 - abs( duration - song['duration']) * 2 / song['duration'] title = res['title'] # for videos, if res['resultType'] == 'video': titleSplit = title.split('-') if len(titleSplit) == 2: title = titleSplit[1] artists = ' '.join([a['name'] for a in res['artists']]) title_score[res['videoId']] = difflib.SequenceMatcher( a=title.lower(), b=song['name'].lower()).ratio() scores = [ title_score[res['videoId']], difflib.SequenceMatcher(a=artists.lower(), b=song['artist'].lower()).ratio() ] if durationMatch: scores.append(durationMatch * 5) #add album for songs only if res['resultType'] == 'song' and res['album'] is not None: scores.append( difflib.SequenceMatcher(a=res['album']['name'].lower(), b=song['album'].lower()).ratio()) match_score[res['videoId']] = sum(scores) / len(scores) * max( 1, int(res['resultType'] == 'song') * 1.5) if len(match_score) == 0: return None #don't return songs with titles <45% match max_score = max(match_score, key=match_score.get) return max_score def search_songs(self, tracks): videoIds = [] songs = list(tracks) notFound = list() for i, song in enumerate(songs): name = re.sub(r' \(feat.*\..+\)', '', song['name']) query = song['artist'] + ' ' + name query = query.replace(" &", "") result = self.api.search(query, ignore_spelling=True) if len(result) == 0: notFound.append(query) else: targetSong = self.get_best_fit_song_id(result, song) if targetSong is None: notFound.append(query) else: videoIds.append(targetSong) if i > 0 and i % 10 == 0: print(f"YouTube tracks: {i}/{len(songs)}") with open(path + 'noresults_youtube.txt', 'w', encoding="utf-8") as f: f.write("\n".join(notFound)) f.write("\n") f.close() return videoIds def add_playlist_items(self, playlistId, videoIds): videoIds = OrderedDict.fromkeys(videoIds) self.api.add_playlist_items(playlistId, videoIds) def get_playlist_id(self, name): pl = self.api.get_library_playlists(10000) try: playlist = next(x for x in pl if x['title'].find(name) != -1)['playlistId'] return playlist except: raise Exception("Playlist title not found in playlists") def remove_songs(self, playlistId): items = self.api.get_playlist(playlistId, 10000)['tracks'] if len(items) > 0: self.api.remove_playlist_items(playlistId, items) def remove_playlists(self, pattern): playlists = self.api.get_library_playlists(10000) p = re.compile("{0}".format(pattern)) matches = [pl for pl in playlists if p.match(pl['title'])] print("The following playlists will be removed:") print("\n".join([pl['title'] for pl in matches])) print("Please confirm (y/n):") choice = input().lower() if choice[:1] == 'y': [self.api.delete_playlist(pl['playlistId']) for pl in matches] print(str(len(matches)) + " playlists deleted.") else: print("Aborted. No playlists were deleted.")
remove_songs, add_songs = [], [] for p in playlist_songs: if p not in songs: remove_songs.append(p) for s in songs: if s not in playlist_songs: add_songs.append(s) if remove_songs and songs_library: print("------------------------------") print("[Remove Songs]") remove_title = [playlist_songs[s]["title"] for s in remove_songs] remove_songs = [{ "videoId": playlist_songs[s]["videoId"], "setVideoId": playlist_songs[s]["setVideoId"], } for s in remove_songs] print("\n".join(remove_title)) ytmusic.remove_playlist_items(playlistId=playlist_id, videos=remove_songs) if add_songs: print("------------------------------") print("[Add Songs]") add_title = [songs[s] for s in add_songs] print("\n".join(add_title)) ytmusic.add_playlist_items(playlistId=playlist_id, videoIds=add_songs) print("------------------------------") print("Done!")
class YTMusicTransfer: def __init__(self): self.api = YTMusic() def create_playlist(self, name, info, privacy="PRIVATE", tracks=None): return self.api.create_playlist(name, info, privacy, video_ids=tracks) def get_best_fit_song(self, results, song): match_score = {} title_score = {} for res in results: if res['resultType'] not in ['song', 'video']: continue durationMatch = None if res['duration']: durationItems = res['duration'].split(':') duration = int(durationItems[0]) * 60 + int(durationItems[1]) durationMatch = 1 - abs(duration - song['duration']) * 2 / song['duration'] title = res['title'] # for videos, if res['resultType'] == 'video': titleSplit = title.split('-') if len(titleSplit) == 2: title = titleSplit[1] artists = ' '.join([a['name'] for a in res['artists']]) title_score[res['videoId']] = difflib.SequenceMatcher(a=title.lower(), b=song['name'].lower()).ratio() scores = [title_score[res['videoId']], difflib.SequenceMatcher(a=artists.lower(), b=song['artist'].lower()).ratio()] if durationMatch: scores.append(durationMatch * 5) #add album for songs only if res['resultType'] == 'song' and res['album'] is not None: scores.append(difflib.SequenceMatcher(a=res['album']['name'].lower(), b=song['album'].lower()).ratio()) match_score[res['videoId']] = sum(scores) / (len(scores) + 1) * max(1, int(res['resultType'] == 'song') * 1.5) if len(match_score) == 0: return None #don't return songs with titles <45% match max_score = max(match_score, key=match_score.get) return [el for el in results if el['resultType'] in ['song', 'video'] and el['videoId'] == max_score][0] def search_songs(self, tracks): videos = [] songs = list(tracks) notFound = list() for i, song in enumerate(songs): query = song['artist'] + ' ' + song['name'] query = query.replace(" &", "") try: result = self.api.search(query) except: print(f'Fail for {song["artist"]} - {song["name"]}') if len(result) == 0: notFound.append(query) else: targetSong = self.get_best_fit_song(result, song) if targetSong is None: notFound.append(query) else: video = self.format_song(targetSong) videos.append(video) if i > 0 and i % 10 == 0: print(str(i) + ' searched') print(notFound) return videos def format_song(self, video): video['_id'] = video['videoId'] video['durationDisplay'] = video['duration'] if len(video['durationDisplay'].split(':')) == 3: video['duration'] = int(video['duration'].split(':')[0]) * 3600 + int(video['duration'].split(':')[1]) * 60 + int(video['duration'].split(':')[2]) if len(video['durationDisplay'].split(':')) == 2: video['duration'] = int(video['duration'].split(':')[0]) * 60 + int(video['duration'].split(':')[1]) video['thumbnail'] = video['thumbnails'][-1]['url'] video['artist'] = video['artists'][0]['name'] video['album'] = video['album']['name'] if 'album' in video and 'name' in video['album'] else None return video def add_playlist_items(self, playlistId, videoIds): videoIds = OrderedDict.fromkeys(videoIds) self.api.add_playlist_items(playlistId, videoIds) def get_playlist_id(self, name): pl = self.api.get_library_playlists(10000) try: playlist = next(x for x in pl if x['title'].find(name) != -1)['playlistId'] return playlist except: raise Exception("Playlist title not found in playlists") def remove_songs(self, playlistId): items = self.api.get_playlist(playlistId, 10000)['tracks'] if len(items) > 0: self.api.remove_playlist_items(playlistId, items) def remove_playlists(self, pattern): playlists = self.api.get_library_playlists(10000) p = re.compile("{0}".format(pattern)) matches = [pl for pl in playlists if p.match(pl['title'])] print("The following playlists will be removed:") print("\n".join([pl['title'] for pl in matches])) print("Please confirm (y/n):") choice = input().lower() if choice[:1] == 'y': [self.api.delete_playlist(pl['playlistId']) for pl in matches] print(str(len(matches)) + " playlists deleted.") else: print("Aborted. No playlists were deleted.")
"875 Dollars De Lux", "Nikes Frank Ocean", "You Got Me The Roots", "Make a Smile for Me Bill Withers", "Pains Silk Rhodes", "I Believe (When I Fall in Love It Will Be Forever) Stevie Wonder", "Don't Let Me Be Misunderstood Nina Simone", "Not Today Ronnie D'addario", "Pains Silk Rhodes", "Unsatisfied Woman Barbara Stant", "Feel So Good Denise Darlington", "I Get Lonely Janet Jackson", "Everybody Dies (feat. Sean Nicholas Savage) World Brain", "Come Home Rollee McGill", "Another Night The Men", "Baby Where You Are Ted Lucas", "Ram Dancehall Double Tiger", "Can You Get to That Funkadelic" ] toAddVideoIds = [] for song in toAdd: songSearch = ytmusic.search(song, "songs") firstSong = songSearch[0] toAddVideoIds.append(firstSong['videoId']) print("Search Term:", song, "\nReturn:", firstSong['title'], "-", firstSong['artists'][0]['name'], "\n") print(toAddVideoIds) status = ytmusic.add_playlist_items(playlistId, toAddVideoIds, None, True) print(status)
f = open(playlist, "r") for remote_playlist in remote_playlists: if remote_playlist["title"] in playlist: playlist_content[remote_playlist["playlistId"]] = f.readlines() for playlist in playlist_content: upload = [] pl_tracks = ytmusic.get_playlist(playlist, 9999)["tracks"] pl_trackid = [] for track in pl_tracks: pl_trackid.append(track["videoId"]) duplicates = [ song for song in pl_tracks if pl_trackid.count(song["videoId"]) > 1 ] for song in remote_songs: #print(str(song["title"]) + str(playlist_content[playlist])) if song["artist"] and song["album"] and song["title"]: upload += [song["videoId"] for pl_entry in playlist_content[playlist] if song["title"] in pl_entry \ and song["artist"] in pl_entry and song["album"] in pl_entry and \ song["videoId"] not in pl_trackid] print("removing %s duplicates from %s" % (len(duplicates), playlist)) if len(duplicates) > 0: print(ytmusic.remove_playlist_items(playlist, duplicates)) #remove duplicates from teh final playlist upload = list(dict.fromkeys(upload)) print("adding %s songs to %s" % (len(upload), playlist)) print(ytmusic.add_playlist_items(playlist, upload)) # if song["title"] in playlist_content[playlist]: # print(song["title"] + playlist_content[playlist]) # #print(ytmusic.add_playlist_items(playlist, [song["videoid"]]))
file = open("failed_songs.txt", "w") count = 0 for i in rows: count += 1 print(count) # time.sleep(0.5) # print("sleeping") song_result = ytmusic.search(i, 'songs') # print(len(song_result)) if len(song_result) > 0: if i != song_result[0]['title']: video_result = ytmusic.search(i, 'videos') if len(video_result) > 0: # print(video_result[0]['videoId']) ytmusic.add_playlist_items(new_playlist, [video_result[0]['videoId']]) else: print("Failed Plus ONEEEEE") file.write(i + ' \n') else: # print(song_result[0]['videoId']) ytmusic.add_playlist_items(new_playlist, [song_result[0]['videoId']]) else: print("Failed Plus ONEEEEE") file.write(i + ' \n') file.close()
class SpotTube(): def __init__(self, clientId=None, clientSecret=None, redirectURI=None): self._clientId = clientId self._clientSecret = clientSecret self._redirectURI = redirectURI self._sp = None self.username = None scope = "playlist-modify-public playlist-modify-public playlist-read-private playlist-read-collaborative" try: access_token = util.prompt_for_user_token( client_id=self._clientId, client_secret=self._clientSecret, scope=scope, redirect_uri=self._redirectURI, cache_path=".cache") except Exception: print( "Não foi possível autenticar em Spotify, verifique se suas credenciais estão corretas.\n" ) sys.exit() else: self._sp = spotipy.Spotify(access_token) self.username = self._sp.me()["display_name"] print(f"Conectado em Spotify como {self.username}") print("\nAutenticando em Youtube Music...\n") sleep(3) try: self._yt = YTMusic("headers_auth.json") except Exception: print( "Não foi possível autenticar em Youtube Music, verifique se o arquivo headers.json está configurado corretamente\n" ) sys.exit() else: print("Conectado em Youtube Music\n") def main(self): userPlaylists = self.get_all_user_spotify_playlists() selected = self.select_playlist(userPlaylists) musics = self.get_musics_from_spotify_playlist(selected[0]) videoIds = self.search_on_youtube(musics) self.add_musics_on_youtube(videoIds, selected[1]) self.saveCredentials(client_id=self._clientId, client_secret=self._clientSecret, redirect_uri=self._redirectURI) def get_all_user_spotify_playlists(self): userPlaylists = {} playlists = self._sp.user_playlists(self._sp.me()["id"])["items"] print() for i in range(len(playlists)): if playlists[i]["owner"]["display_name"] == self.username: userPlaylists[playlists[i]["id"]] = playlists[i]["name"] return userPlaylists def select_playlist(self, playlists): choice = None options = [] name = [] print("Essas são as suas playlists que encontrei: \n") while True: for i, j in enumerate(playlists.items()): print(f"{i+1}ª playlist: {j[1]}") options.append(i + 1) name.append({"name": j[1], "id": j[0]}) try: choice = int(input("\nSelecione uma playlist: ")) if choice not in options: os.system("cls") print("Selecione uma playlist válida.\n") continue except ValueError: os.system("cls") print("Selecione uma playlist válida.\n") else: os.system("cls") playlistName = name[choice - 1]["name"] print("Voce selecionou " + playlistName) choice = name[choice - 1]["id"] del name del options break return (choice, playlistName) def get_musics_from_spotify_playlist(self, playlistId): tracks = [] songs = self._sp.playlist_tracks(playlistId)["items"] for i in range(len(songs)): tracks.append(songs[i]["track"]["name"]) if len(songs) >= 100: songs = self._sp.playlist_tracks(playlistId, offset=100 + 1)["items"] for i in range(len(songs)): tracks.append(songs[i]["track"]["name"]) return tracks return tracks def search_on_youtube(self, tracks): print("Buscando as músicas...\n") videoIds = {} for music in tracks: youtube = self._yt.search(query=music, filter="songs", ignore_spelling=True, limit=5)[0] videoIds[youtube["title"]] = youtube["videoId"] return videoIds def add_musics_on_youtube(self, ids, playlistName): names = [i for i in ids.keys()] all_ids = [i for i in ids.values()] [print(track) for track in names] print("\n") print( "Adicionando músicas em sua playlist do Yt Music.\nAguarde alguns instantes..." ) sleep(5) playlist = self._yt.create_playlist(title=playlistName, description="", privacy_status="PRIVATE") self._yt.add_playlist_items(playlistId=playlist, videoIds=all_ids) print("\nAs músicas foram adicionadas!") browser = input( "Pressione 1 para abrir no navegador ou pressione qualquer tecla para terminar: " ) if browser == '1': webbrowser.open( f"https://music.youtube.com/playlist?list={playlist}") def saveCredentials(self, client_id, client_secret, redirect_uri): with open(".env", "w") as file: file.write(f"clientID={client_id}\n") file.write(f"clientSecret={client_secret}\n") file.write(f"URI={redirect_uri}\n")
from ytmusicapi import YTMusic import json ytmusic = YTMusic('headers_auth.json') #read auth file songs = ytmusic.get_liked_songs(limit=5000) targetId = input("Plese enter playlist ID to add liked songs: ") print(targetId + " Will be used as target playlist") targetPl = ytmusic.get_playlist(targetId, limit=5000) def ContainsTrackId (TrackId, TrackDict): for i in TrackDict: if i['videoId'] == TrackId: return True return False songList = [] for n in songs['tracks']: if not ContainsTrackId(n['videoId'], targetPl['tracks']): print("not in playlist: " + n['videoId']) songList.append(n['videoId']) else: print("in playlist already: " + n['videoId']) print(songList) print(json.dumps(ytmusic.add_playlist_items(targetId,videoIds = songList, duplicates=True)))
class youtube_music_tasker: def __init__(self, auth_json: str): self.api = YTMusic(auth_json) # Return: # [ # { # "id": "playlistid1", # "title": "playlist_title1", # "thumbnail": "url_to_playlist1_1st_thumbnail" # }, # { # "id": "playlistid2", # "title": "playlist_title2", # "thumbnail": "url_to_playlist2_1st_thumbnail" # } # ] # def show_playlist(self): list_of_playlist = [] try: library_playlists = self.api.get_library_playlists( limit=50) # Hopefully, no one has 50+ playlists. for pl in library_playlists: # Only showing non-empty well-formed playlists if 'count' in pl and int( pl['count'] ) > 0 and 'playlistId' in pl and 'title' in pl and 'thumbnails' in pl: playlist = {} playlist['id'] = pl['playlistId'] playlist['title'] = pl['title'] if len(pl['thumbnails']) > 0: playlist['thumbnail'] = pl['thumbnails'][0]['url'] else: playlist['thumbnail'] = DEFAULT_IMG_URL list_of_playlist.append(playlist) except Exception as e: print("Unexpected Error in show_playlist:", e) return json.dumps(list_of_playlist) # Return: # [ # { # "title": "name", # "artist": "someone", # "album": "the album" # }, # { # "title": "name", # "artist": "any", # "album": "any" # } # ] # def show_song_in_playlist(self, playlist_id: str): list_of_song = [] try: pl_detail = self.api.get_playlist(playlistId=playlist_id) if 'tracks' in pl_detail: for track in pl_detail['tracks']: if 'title' in track: new_track = { 'title': track['title'], 'artist': 'any', 'album': 'any' } if 'artists' in track and len(track['artists']) > 0: new_track['artist'] = track['artists'][0]['name'] if 'album' in track and track[ 'album'] != None and 'name' in track['album']: new_track['album'] = track['album']['name'] list_of_song.append(new_track) except Exception as e: print("Unexpected Error in show_song_in_playlist:", e) return json.dumps(list_of_song) # access: 'PRIVATE', 'PUBLIC', 'UNLISTED' # Return: A tuple of (create_status, playlist_id, add_status) def new_playlist(self, playlist_name: str, desc: str = "A playlist created by PlaySync on " + str(datetime.today().strftime('%Y-%m-%d')), access: str = 'PRIVATE', tracks=[]): try: playlist_id = self.api.create_playlist(title=playlist_name, description=desc, privacy_status=access) if type(playlist_id) == str: # It is an id if len(tracks) > 0: status = self.api.add_playlist_items(playlist_id, tracks) return (0, playlist_id, status ) # Creation successful, add status attached else: return (0, playlist_id, "NULL" ) # Creation successful, didn't add else: # Status message, means error in creation return (-1, 0, playlist_id) except Exception as e: print("Unexpected Error in new_playlist:", e) return (-2, 0, e) # Didn't crash gracefully def search_song(self, song_title: str, song_artist: str = "", song_misc: str = ""): song_list = [] try: search_results = self.api.search(query=song_title + song_artist + song_misc, limit=10) for song_found in search_results: if (song_found['resultType'] in ['song', 'video']): new_song = { 'id': song_found['videoId'], 'title': song_found['title'], 'artist': 'None', 'album': 'None', 'duration': 'Unknown' } if len(song_found['artists']) > 0: new_song['artist'] = song_found['artists'][0]['name'] if 'album' in song_found: new_song['artist'] = song_found['album']['name'] if 'duration' in song_found: new_song['duration'] = song_found['duration'] song_list.append(new_song) except Exception as e: print("Unexpected Error in search_song:", e) return json.dumps(song_list) def add_songs(self, playlist_id: str, tracks=[]): try: status = self.api.add_playlist_items(playlist_id, tracks) return (0, playlist_id, status ) # Creation successful, add status attached except Exception as e: print("Unexpected Error in add_songs:", e) return (-2, 0, 0) # Didn't crash gracefully def del_songs(self, playlist_id: str, tracks=[]): try: if len(tracks) > 0: status = self.api.remove_playlist_items(playlist_id, videos=tracks) return status except Exception as e: return "UNCAUGHT ERROR" + str(e) return "NULL" def del_playlist(self, playlist_id: str): try: status = self.api.delete_playlist(playlist_id) return status except Exception as e: return "UNCAUGHT ERROR" + str(e)
from ytmusicapi import YTMusic ytmusic = YTMusic('headers_auth.json') playlistId = ytmusic.create_playlist("Yandex Music", "Imported from Yandex Music") fp = open('yandexTracks.txt', 'r') fSkipped = open('youtubeSkippedDuringImport.txt', 'a') for track in fp: print(track) search_results = ytmusic.search(track.strip()) if ('videoId' not in search_results[0]): fSkipped.writelines([track.strip(), '\n']) continue ytmusic.add_playlist_items(playlistId, [search_results[0]['videoId']]) ytmusic.rate_song(search_results[0]['videoId'], 'LIKE') fp.close() fSkipped.close()