class Playlist(): ''' Parent class for specific types of playlists, like: Live Setlist Playlist setlist based on the set of songs played at a live concert Upcoming Concert Playlist setlist generated from a list of bands that have upcoming concerts in an area ''' def __init__(self, make=False): self.setup_logging() self.api = Mobileclient() self.logged_in = self.api.login( EMAIL, TOKEN, # Mobileclient.FROM_MAC_ADDRESS) DEVICE_ID) if self.logged_in: self.info("Logged into GPMAA successfully") def setup_logging(self): logger_name = '.'.join([__name__, __class__.__name__]) self.logger = logging.getLogger(logger_name) logging.getLogger('gmusicapi.protocol.shared').setLevel(logging.INFO) logging.getLogger('urllib3.connectionpool').setLevel(logging.WARNING) def error(self, msg): self.logger.error(msg) def info(self, msg): self.logger.info(msg) def debug(self, msg): self.logger.debug(msg) def search(self, query): ''' This function got pulled to the parent class because we'll always be searching for things and wanting the song results. They're always going to have to be processed this way because of how the search result is formatted. The result is a list of song dictionaries with keys such as storeId, artist, etc. ''' res = self.api.search(query)['song_hits'] res = [song['track'] for song in res] return res def create_playlist(self, song_ids, name, description='', public=False): self.info("Creating {}".format(name)) self.id = self.api.create_playlist(name, description, public) self.api.add_songs_to_playlist(self.id, song_ids) def delete_playlist(self): if hasattr(self, 'id') and self.id is not None: self.info("Deleting playlist id: %s".format(self.id)) self.api.delete_playlist(self.id) else: self.info("Can't delete a playlist without its id")
""" cursor.execute(sql) trackRows = cursor.fetchall() playlistName = "BG Rand " + datetime.now().strftime("%Y-%m %B") # Check if the playlist exists # If it does, abort unless --replace is specified, in which case delete the old list playlists = gpm.get_all_playlists() for playlist in playlists: if playlist["deleted"]: continue if playlist["name"] == playlistName: if args.replace: logger.info("Deleting existing playlist") gpm.delete_playlist(playlist["id"]) else: logger.error("Playlist already exists: " + playlistName) exit(1) logger.info("Creating playlist: " + playlistName) playlistId = gpm.create_playlist(playlistName, description="Autogenerated by RPG", public=False) logger.info("Adding " + str(len(trackRows)) + " tracks to playlist") trackIds = [] for row in trackRows: trackIds.append(row[0]) if len(trackIds) >= 50: gpm.add_songs_to_playlist(playlist_id=playlistId, song_ids=trackIds)
songs_ids = [] for line in options.file.readlines(): line = line.strip().decode('utf-8') if not line: continue log.info('Searching for %s', line) result = cached_search(cache, api, line) songs = result['song_hits'] songs = filter_songs(songs, line) if len(songs): songs_ids.append(songs[0]['track']['storeId']) continue log.debug(songs) for pl in api.get_all_playlists(): if pl['name'] == options.playlist: api.delete_playlist(pl['id']) playlist_id = api.create_playlist(options.playlist) try: api.add_songs_to_playlist(playlist_id, songs_ids) except Exception, _: api.delete_playlist(playlist_id)
class GoogleMusic: __metaclass__ = Singleton SKIP_ARTIST = ['vox freaks'] def __init__(self): self.gmusicapi = Mobileclient(debug_logging=False) logged_in = self.gmusicapi.login( email=Config.GOOGLE_MUSIC_USER_NAME, password=Config.GOOGLE_MUSIC_APP_PASSWORD, locale='en_US', android_id=Mobileclient.FROM_MAC_ADDRESS) if not logged_in: raise Exception('Unable to log in to GoogleMusic') def get_lib_from_gmusic(self): lib = self.gmusicapi.get_all_songs() lib_list = [] song = None for song in lib: song = Song(artist=song['artist'], title=song['title']) lib_list.append(song) return lib_list def delete_playlist_if_exists(self, name): all_playlists = self.gmusicapi.get_all_playlists() for playlist in all_playlists: if playlist['name'] == name: self.gmusicapi.delete_playlist(playlist['id']) def create_playlist(self, name, description, public=True): return self.gmusicapi.create_playlist(name=name, description=description, public=public) def add_songs_to_playlist(self, playlist_id, song_ids=None, song_df=None): if (song_ids is None and song_df is None): raise ValueError('Need song_ids or song_dfs to add to playlist') if song_df is not None and (not song_df.empty): song_ids = song_df.google_music_store_id.dropna().tolist() return self.gmusicapi.add_songs_to_playlist(playlist_id, song_ids) def gmusic_constrained_search(self, song, query, strict): song_hits = query['song_hits'] for result in song_hits: track = result['track'] if track['albumArtist'].lower() in SKIP_ARTIST: continue if song.remix: if "remix" not in track['title'].lower(): continue else: if "remix" in track['title'].lower(): continue if strict: full_title = "{} - {}".format(track['albumArtist'], track['title']) score = difflib.SequenceMatcher(None, song.full_title.lower(), full_title.lower()).ratio() if score < 0.6: continue return track return None def search_song(self, song, strict=False): try: first_query = self.gmusicapi.search(song.full_title) first_result = self.gmusic_constrained_search( song, first_query, strict) if first_result is None: second_query = self.gmusicapi.search(song.full_title_stripped) first_result = self.gmusic_constrained_search( song, second_query, strict) if first_result is None: logger.warning( 'No satisfactory result found in Google Music for {}'. format(song.full_title)) return first_result except Exception as e: logger.debug('Exception: {}'.format(e)) logger.info(u'Skipped {}'.format(song.title)) return None def get_store_id(self, result): store_id = None if result: if result.has_key('storeId'): store_id = result['storeId'] return store_id def get_google_rating(self, result): rating = None if result: if result.has_key('rating'): return result['rating'] return rating def update_playlist(self, playlist, public=True, exclude_0_rating=True): #Delete Playlist if present. logger.info(u'Updating the playlist {} in GoogleMusic'.format( playlist.name)) self.delete_playlist_if_exists(playlist.name) #Create Playlist playlist_id = self.create_playlist(name=playlist.name, description=playlist.description, public=public) if exclude_0_rating: playlist.song_df = playlist.song_df[ playlist.song_df['google_music_rating'] != '1'] self.add_songs_to_playlist(playlist_id=playlist_id, song_df=playlist.song_df)
from gmusicapi import Mobileclient from gmusicapi import Webclient import json import requests requests.packages.urllib3.disable_warnings() api = Mobileclient() logged_in = api.login('*****@*****.**', 'musicatyourspeed') playlists = api.get_all_playlists() for i,v in enumerate(playlists): api.delete_playlist(v['id']) print "All playlists deleted"
def reverseplaylist(playlist_name='', repeat=False, quick=False): mc = Mobileclient() mc.__init__() # Find location of this script dir_path = os.path.dirname(os.path.realpath(__file__)) # Check whether this is the first time the program has been run by searching the directory for the log file file_list = os.listdir(dir_path) # No log file means not run if '.gmusiclog.txt' not in file_list: print( '\n' + 'This is the first time this program has been run in this folder.' + '\n' + 'performing initial authentication.' + '\n') # Autorepeat cannot be true without logfile, override if true repeat = False # Start with a bogus device ID to determine real id from error message devID = 'ffffffff' mc.perform_oauth() try: mc.oauth_login(devID) except Exception as e: error = str(e) IDpos = error.find('*') nextIDpos = error.find('\n', IDpos + 1, len(error)) devID = error[IDpos + 2:nextIDpos] # Perform login mc.oauth_login(devID) # Write authentication stuff to logfile with open(dir_path + '/.gmusiclog.txt', 'w') as log: log.write(devID + '\n') x = datetime.datetime.now() timeString = (str(x.day) + '/' + str(x.month) + '/' + str(x.year) + ' ' + str(x.hour) + ':' + str(x.minute) + ':' + str(x.second) + '.' + str(x.microsecond)) log.write('Initial authentication performed at ' + timeString + '\n') # Log file exists, we will check whether the user has requested autorepeat else: print( '\n' + 'This is not the first time this program has been run in this folder' + '\n' + 'performing login.' + '\n') # Open the logfile to read device id and previous playlists with open(dir_path + '/.gmusiclog.txt', 'r') as log: # Get device ID devID = log.readline().strip() # Look for the playlist name from the bottom of the list contents = log.read() # Perform login mc.oauth_login(devID) playlistLocation = contents.rfind('PLAYLIST') if playlistLocation != -1: # Define end of playlist to make defining desired playlist a little cleaner endOfPlaylist = contents.find('\n', playlistLocation, len(contents)) desired_playlist = contents[playlistLocation + 10:endOfPlaylist] with open(dir_path + '/.gmusiclog.txt', 'a+') as log: # Write authentication stuff to logfile x = datetime.datetime.now() timeString = (str(x.day) + '/' + str(x.month) + '/' + str(x.year) + ' ' + str(x.hour) + ':' + str(x.minute) + ':' + str(x.second) + '.' + str(x.microsecond)) log.write('Login performed at ' + timeString + '\n') # Get user input for desired playlist if autorepeat is not enabled if repeat == False and playlist_name == '': desired_playlist = input( 'Name of the playlist being reversed (case sensetive): ') elif playlist_name != '': # If a name is given this overrides all else desired_playlist = playlist_name else: print('Autorepeat enabled, reversing playlist: ' + desired_playlist + '\n') # Establish the name of the reversed playlist reversed_playlist = desired_playlist + 'REVERSED' # Check to see whether the desired and reversed playlists exist yet allPlaylists = mc.get_all_playlists() desired_playlist_index = -1 reversed_playlist_index = -1 for n in allPlaylists: if n['name'] == reversed_playlist: reversed_playlist_index = n reversedID = n['id'] elif n['name'] == desired_playlist: desired_playlist_index = n desiredID = n['id'] # Desired playlist exists, so we check to see if it has also been reversed if desired_playlist_index != -1: # We cache the playlist name so that it can be automatically re-reversed next time with open(dir_path + '/.gmusiclog.txt', 'a+') as log: log.write('PLAYLIST: ' + desired_playlist + '\n') # Desired playlist has been reversed, we can either delete the old one before proceeding # or perform a quick update if reversed_playlist_index != -1: print('The ' + desired_playlist + ' playlist has been reversed.') # Determine whether to do a quick update or not if quick == True: print('performing quick update') quick_update(mc, desiredID, reversedID) return else: print('Performing full update\n' + 'Deleting the old playlist...\n') mc.delete_playlist(reversedID) # Desired playlist has not been reversed, create the reverse else: print('The ' + desired_playlist + ' playlist has not been reversed, creating the reverse now.') # If we have got this far, the reversed playlist doesn't exist print('Generating reversed song list...') reversedID, id_list = create_new(mc, desired_playlist) print('Adding songs to the playlist...') mc.add_songs_to_playlist(reversedID, id_list) print('Done!') # No such playlist exists else: print( 'No playlist by the name of ' + desired_playlist + ' found. Did you spell it correctly? A reminder here that the playlist name is case sensetive.' )
hKey = OpenKey(HKEY_LOCAL_MACHINE, "Software\\Lattuce") username = QueryValueEx(hKey, "GoogleUsername")[0] password = QueryValueEx(hKey, "GooglePassword")[0] # Log into Google api = Mobileclient() api.login(username, password, Mobileclient.FROM_MAC_ADDRESS) # => True # Reactivate # Delete Playlist playlists = api.get_all_playlists() for playlist in playlists: if playlist['name'] == 'Reactivate': id_to_delete = playlist['id'] print('Deleting Playlist ID: ', id_to_delete) api.delete_playlist(id_to_delete) # Add new Playlist playlist_id = api.create_playlist('Reactivate') songs = api.get_all_songs() playlistsongs = [] for song in songs: if 'Reactivate' in song['album']: print('Adding song ID: ', song['id'], 'to playlist Reactivate') playlistsongs.append(song['id']) api.add_songs_to_playlist(playlist_id, playlistsongs) # Dance etc. # Delete Playlist playlists = api.get_all_playlists() for playlist in playlists: if playlist['name'] == 'Dance':
class Gopma(): def __init__(self, action=None): print "Initialising GOPMA." config = ConfigParser.ConfigParser() config.read('config.ini') email = config.get('login', 'email') password = config.get('login', 'password') try: auth_token = config.get('login', 'auth_token') except: auth_token = False print "No auth token could be found" print "Logging into Google Play Music as", email logged_in = False bad_auth = False while not logged_in: if not auth_token or bad_auth: self.api = Mobileclient() login = self.api.login(email, password, Mobileclient.FROM_MAC_ADDRESS) if not login: print "Login failed, check your credentials." sys.exit() # Save the auth token for later with open('config.ini', 'w+') as f: config.set('login', 'auth_token', self.api.session._authtoken) config.write(f) f.close() print "Saved auth token for later." logged_in = True else: print "Found an auth token, trying it." self.api = Mobileclient() self.api.session._authtoken = auth_token self.api.session.is_authenticated = True try: # Test the auth token self.api.get_registered_devices() logged_in = True except: # Failed print "Bad auth token, manually signing in." bad_auth = True print "Successfully logged in as", email if action != 'reset_genres': print "Loading data." self.playlists = self.api.get_all_playlists() self.content = self.api.get_all_user_playlist_contents() self.root_genres, self.child_genres = self.load_genres() print "Data successfully loaded." def create_or_retrieve_playlists(self, playlists): """ Helper function to create or retrieve playlist IDs for a given agg_lists Input: List of playlist names Output: Dict of playlist names and IDs """ if type(playlists) is not list: print "Stop passing non-lists to this function." sys.exit() agg_lists = [ p for p in self.content if p.get('type') == 'USER_GENERATED' and p.get('name') in playlists ] # Get all playlist IDs agg_playlists = {} existing_playlists = [playlist['name'] for playlist in agg_lists] for name in playlists: if name not in existing_playlists: print "Playlist not found, creating", name agg_playlists[name] = self.api.create_playlist(name) self.api.edit_playlist(agg_playlists[name], public=True) else: print "Playlist found", name + ", retrieving ID." playlist_id = [ p['id'] for p in agg_lists if p.get('name') == name ][0] agg_playlists[name] = playlist_id # self.api.edit_playlist(agg_playlists[name], public=True) return agg_playlists def load_genres(self, reset=False): """ Load all genres """ # Get the root genres if os.path.isfile(ROOT_GENRE_FILE): print "Found a root genres file." if reset: root_genres = self.api.get_genres() with open(ROOT_GENRE_FILE, 'w') as fp: pickle.dump(root_genres, fp) print "Root genres have been reset." else: with open(ROOT_GENRE_FILE) as fp: root_genres = pickle.load(fp) else: print "Couldn't find a root genres file, retrieving data." root_genres = self.api.get_genres() with open(ROOT_GENRE_FILE, 'w') as fp: pickle.dump(root_genres, fp) print "Root genres file created." # Get the child genres if os.path.isfile(CHILD_GENRE_FILE): print "Found a child genres file." if reset: child_genres = {} for genre in root_genres: children = self.api.get_genres(genre['id']) child_names = [] for child in children: child_names.append(child['name']) child_genres[genre['id']] = child_names with open(CHILD_GENRE_FILE, 'w') as fp: pickle.dump(child_genres, fp) print "Child genres have been reset." else: with open(CHILD_GENRE_FILE) as fp: child_genres = pickle.load(fp) else: print "Couldn't find a child genres file, retrieving data." child_genres = {} for genre in root_genres: children = self.api.get_genres(genre['id']) child_names = [] for child in children: child_names.append(child['name']) child_genres[genre['id']] = child_names with open(CHILD_GENRE_FILE, 'w') as fp: pickle.dump(child_genres, fp) print "Child genres file created." return root_genres, child_genres def delete_empty_playlists(self): """ Delete ALL empty playlists. Be careful with this. """ playlists = self.content for playlist in playlists: if len(playlist['tracks'] ) == 0 and playlist['name'] != AGGREGATE_PLAYLIST_NAME: self.api.delete_playlist(playlist['id']) print "Deleted", playlist['name'] def create_playlists(self): """ Create all needed playlists """ print "Creating/updating playlists." self.create_or_retrieve_playlists( [AGGREGATE_PLAYLIST_NAME, SHARED_PLAYLIST_NAME]) self.create_or_retrieve_playlists( [PLAYLIST_PREFIX + genre for genre in GENRE_PLAYLISTS.values()]) def get_playlist_urls(self): """ Get all gopma playlist URLS """ urls = {} for playlist in self.playlists: if PLAYLIST_PREFIX in playlist['name'] and playlist[ 'type'] == 'USER_GENERATED': urls[playlist[ 'name']] = "https://play.google.com/music/playlist/" + playlist[ 'shareToken'] return urls def get_playlist_id(self, name): """ Get the playlist ID for a given playlist name """ playlist = [p for p in self.playlists if p.get('name') == name][0] return playlist['id'] def get_share_token(self, playlist_id): """ Get the share token for a given playlist ID """ playlist = [p for p in self.playlists if p.get('id') == playlist_id] return playlist[0]['shareToken'] def get_playlist_tracks(self, playlist_id): """ Get the tracks for a specified playlist id """ return [p for p in self.content if p.get('id') == playlist_id][0]['tracks'] def get_parent_genre_id(self, genre_name): """ Get the parent id for a given genre name """ # Check the root genres first for genre in self.root_genres: if genre_name == genre['name']: return genre['id'] # Check children genres for gid, genres in self.child_genres.items(): for genre in genres: if genre == genre_name: return gid def wipe_all_playlists(self): """ Wipe all Gopma playlists """ for playlist in self.playlists: if PLAYLIST_PREFIX in playlist[ 'name'] and SHARED_PLAYLIST_NAME not in playlist['name']: print "Wiping playlist: ", playlist['name'] self.wipe_playlist(playlist['id']) def wipe_playlist(self, playlist_id): """ Wipe a given playlist """ playlist_tracks = self.get_playlist_tracks(playlist_id) song_ids = [track['id'] for track in playlist_tracks] self.api.remove_entries_from_playlist(song_ids) def reset_daily_playlists(self): """ Reset the daily playlists """ # Get playlists agg_playlists = self.create_or_retrieve_playlists([TODAY, YESTERDAY]) yest_id = agg_playlists[YESTERDAY] today_id = agg_playlists[TODAY] # Wipe yesterday print "Wiping yesterday's playlist." self.wipe_playlist(yest_id) # Copy today to yesterday print "Copying", TODAY, "to", YESTERDAY today_tracks = self.get_playlist_tracks(today_id) self.api.add_songs_to_playlist(yest_id, [t['trackId'] for t in today_tracks]) # Wipe today print "Wiping today's playlist." self.wipe_playlist(today_id) def update_group_playlist(self): """ Update the big group aggregate and the daily playlist with any new shared songs """ # Get the aggregate playlist songs agg_token = self.get_share_token( self.get_playlist_id(AGGREGATE_PLAYLIST_NAME)) agg_playlists = [ p for p in self.playlists if p.get('type') == 'USER_GENERATED' and p.get('shareToken') == agg_token ] agg_id = agg_playlists[0]['id'] # Get tracks agg_tracks = self.api.get_shared_playlist_contents(agg_token) agg_tracks_ids = [track['trackId'] for track in agg_tracks] print "Updating group playlists." # Get the playlists we want to update with shared_lists = [ p for p in self.playlists if p.get('name') == SHARED_PLAYLIST_NAME ] for playlist in shared_lists: shared_tracks = self.api.get_shared_playlist_contents( playlist['shareToken']) print "\nRetrieving from", playlist[ 'name'], "by", playlist['ownerName'] + ":" # Add songs to aggregate playlist if len(shared_tracks) == 0: print "<< Playlist is empty. >>" else: no_new = True for track in shared_tracks: if track['trackId'] not in agg_tracks_ids: # Add to giant aggregate playlist self.api.add_songs_to_playlist(agg_id, track['trackId']) # Add to daily playlist self.api.add_songs_to_playlist( self.get_playlist_id(TODAY), track['trackId']) # Add to genre relevant playlist self.api.add_songs_to_playlist( self.get_playlist_id( PLAYLIST_PREFIX + GENRE_PLAYLISTS[self.get_parent_genre_id( track['track']['genre'])]), track['trackId']) title = track['track']['title'].encode( 'ascii', 'ignore') artist = track['track']['artist'].encode( 'ascii', 'ignore') print "+", title, "by", artist, "has been added." no_new = False if no_new: print "<< There are no new tracks to be added from this playlist. >>" print "Finished updating group playlists." def update_songs(self): """ Update the database with song information """ # Connect to the database config = ConfigParser.ConfigParser() config.read('config.ini') dbname = config.get('database', 'dbname') dbuser = config.get('database', 'user') dbhost = config.get('database', 'host') dbpass = config.get('database', 'password') try: conn = psycopg2.connect("dbname=" + dbname + " user="******" host=" + dbhost + " password="******"<< Could not connect to the db. >>" print e sys.exit() # Update songs for c in self.content: if c.get('type') == 'USER_GENERATED' and c.get( 'name') == AGGREGATE_PLAYLIST_NAME: songs = c.get('tracks') for s in songs: # Song details details = s['track'] # Date song was added date_added = datetime.fromtimestamp( int(s.get('creationTimestamp')) / 1000000) # Values to save values = [ str(s.get('trackId')), str(details.get('title').encode('UTF-8', 'ignore')), str(details.get('artist').encode('UTF-8', 'ignore')), str(details.get('album').encode('UTF-8', 'ignore')), str(details.get('genre')), date_added ] # SQL query insert_song = "INSERT INTO playlists_song VALUES (%s, %s, %s, %s, %s, %s) ON CONFLICT (tid) DO NOTHING;" # Save to DB self.commit_changes(conn, cur, insert_song, values) print "Songs successfully updated." # Close connection cur.close() conn.close() def commit_changes(self, conn, cur, query, values): try: # Commit our changes made cur.execute(query, values) conn.commit() except psycopg2.Error as exc: print exc sys.exit()
def main(): #### Requests user specifies update library and/or playlists if len(sys.argv) != 3: print('Specify T/F arguments for uploading and updating playlists') print('e.g. python ' + sys.argv[0] + ' 1 0') print('which would:\n--> upload new songs\n--> NOT update playlists') sys.exit(0) #### Parameters music_dir = '/home/conor/Music/' print('Local music directory set to:', music_dir) accepted = input('Type "y" if this is correct directory: ') if accepted.lower() != 'y': print('Edit music_dir variable in source to run script...') print('Ending music management.') sys.exit(0) #### Some general information needed for both tasks is collected here # Get mp3 file names from music folder local_song_paths = glob.glob(music_dir + '*.mp3') # Get individual song names local_song_names = set() for p in local_song_paths: _, song_name = os.path.split(p) local_song_names.add(song_name) # Authenticate mc = Mobileclient() mc.oauth_login('38e42c4b00ca0a10') # Authenticates using on-disk token print('Mobile client authentication complete...') # Create dict of gpm 'song'': 'id' pairs song_ids = {} gpm_songs = mc.get_all_songs() for song in gpm_songs: song_ids[song['title']] = song['id'] #### Manage upload/deletion of songs uploading = sys.argv[1] if uploading == '1': mm = Musicmanager() mm.login(uploader_id='EE:20:80:B4:17:A9' ) # Authenticates using on-disk token print('Music manager authentication complete...') # Delete songs that no longer exist locally to_delete = set() for song in song_ids: if song not in local_song_names: to_delete.add(song) if len(to_delete) == 0: print('No songs to delete.') else: print('{} songs to delete:'.format(len(to_delete))) print([s for s in to_delete]) # delete_songs() method requires a list as input to_delete_ids = [] for s in to_delete: song_id = song_ids[s] to_delete_ids.append(song_id) mc.delete_songs(to_delete_ids) print('Deleted songs.') #### Uploading to_upload = [] for s in local_song_names: if s not in song_ids: to_upload.append(music_dir + s) print('{} songs to upload.'.format(len(to_upload))) if len(to_upload) != 0: accepted = input('Type "y" to commence upload now: ') if accepted.lower() != 'y': print('Ending music management.') sys.exit(0) mm.upload(to_upload) #### Create and edit playlists as required # Works by deleting all playlists and then re-creating from scratch playlisting = sys.argv[2] if playlisting == '1': # Refresh song list # (since we have uploaded new songs since original list generated) song_ids = {} gpm_songs = mc.get_all_songs() for song in gpm_songs: song_ids[song['title']] = song['id'] # Flush old playlists print('Deleting old playlists...') gpm_playlists = mc.get_all_playlists() for pl in gpm_playlists: mc.delete_playlist(pl['id']) print('Playlists deleted.') # Keep a dictionary of created playlists to prevent duplication playlist_ids = {} total = len(song_ids) completed = 0 # Create and update playlists print('Organising songs:') for s in song_ids: sid = song_ids[s] req_pls = required_playlists(s) for pl in req_pls: if pl in playlist_ids: pid = playlist_ids[pl] else: pid = mc.create_playlist(name=pl) playlist_ids[pl] = pid mc.add_songs_to_playlist(pid, sid) completed += 1 # Console output for number of songs sorted sys.stdout.write("\r{}/{} processed".format(completed, total)) sys.stdout.flush() print()
playlistcnx2 = mysql.connector.connect(user=(MySQLUsername), password=(MySQLPassword), host='lattuce-dc', database='music') playlistsongcursor = playlistsongcnx.cursor() playlistcursor = playlistcnx.cursor() playlistcursortodelete = playlistcnxtodelete.cursor() playlistdelcursor = playlistdelcnx.cursor() playlistcursor1 = playlistcnx1.cursor() playlistcursor2 = playlistcnx2.cursor() ################ # Delete playlists which dont exist in the database anymore # TODO: Temp code until i can figure out how to truncate existing google playlists playlists = api.get_all_playlists() for playlist in playlists: id_to_delete = playlist['id'] print("Deleting Playlist:", playlist['name'], [id_to_delete]) api.delete_playlist(id_to_delete) ################ # Delete playlists which dont exist in the database anymore playlists = api.get_all_playlists() for playlist in playlists: print("Fround in Google:", playlist['name']) query = ("select Count(*) as cnt from playlist where playlist_name = '" + playlist['name'] + "'") playlistdelcursor.execute(query) row = playlistdelcursor.fetchone() if row[0] == 0: id_to_delete = playlist['id'] print("Deleting Playlist:", playlist['name'], [id_to_delete], "because it does not exist in the database") api.delete_playlist(id_to_delete) playlistdelcursor.close()
def main(): sys.stdout = codecs.getwriter('utf8')(sys.stdout) sys.stderr = codecs.getwriter('utf8')(sys.stderr) with open('settings.json') as f: settings = json.load(f) with open('settings_schema.json') as f: schema = json.load(f) try: jsonschema.validate(settings, schema) except: print traceback.format_exc() return client_id = settings['client_id'] client_secret = settings['client_secret'] redirect_url = settings['redirect_url'] gmusic_login = settings['gmusic_login'] if 'gmusic_pw' not in settings: gmusic_pw = getpass.getpass( 'Enter your google music password (you only need to do this once): ' ) else: gmusic_pw = base64.b64decode(settings['gmusic_pw']) # client credentials flow print 'Logging into Spotify' client_credentials_manager = SpotifyClientCredentials( client_id, client_secret) sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager) # gmusic controller print 'logging into Google music' gmusic = Mobileclient() logged_in = gmusic.login(gmusic_login, gmusic_pw, Mobileclient.FROM_MAC_ADDRESS) if logged_in: settings['gmusic_pw'] = base64.b64encode(gmusic_pw) with open('settings.json', 'w') as f: json.dump(settings, f, sort_keys=True, indent=2, separators=(',', ': ')) else: print 'Unable to login, check credentials' return all_gmusic_playlists = gmusic.get_all_playlists() errors = [] for playlist_settings in settings['playlists']: # get all names and artists from the particular playlists username = playlist_settings['username'] tid = playlist_settings['id'] playlist = sp.user_playlist(username, tid) print 'Found spotify playlist: ' + playlist['name'] playlist_name = 'Spotify ' + playlist['name'] spotify_tracks = playlist['tracks']['items'] song_names = [t['track']['name'] for t in spotify_tracks] artists = [t['track']['artists'][0]['name'] for t in spotify_tracks] if (len(artists) != len(song_names)): print 'Error: can\'t match up all songs to artists' return spotify_tracks = zip(song_names, artists) # delete existing playlists we imported for playlist in all_gmusic_playlists: if playlist['name'] == playlist_name: gmusic.delete_playlist(playlist['id']) print 'Creating Google music playlist: ' + playlist_name g_playlist = gmusic.create_playlist(playlist_name) for spotify_track in spotify_tracks: try: spotify_song_name = spotify_track[0] spotify_artist_name = spotify_track[1] songs = gmusic.search(spotify_song_name + ' ' + spotify_artist_name)['song_hits'] found_song = False # if we found a song match if (len(songs) > 0): for song in songs: found_song_name = song['track']['title'] found_song_artist = song['track']['albumArtist'] fuzz_ratio_name = fuzz.partial_ratio( found_song_name, spotify_song_name) fuzz_ratio_artist = fuzz.partial_ratio( found_song_artist, spotify_artist_name) # check that it's a close match to what we are looking for if (fuzz_ratio_name + fuzz_ratio_artist > 70): print 'Adding: ' + spotify_song_name + ', ' + spotify_artist_name gmusic.add_songs_to_playlist( g_playlist, song['track']['storeId']) found_song = True break if not found_song: error = 'FuzzRatio not in threshold|spotify: ' + spotify_song_name + ',' + spotify_artist_name +\ '|gmusic: ' + found_song_name + ',' + found_song_artist print error errors.append(error) else: error = 'Unable to add, song: ' + spotify_song_name + ', artist: ' + spotify_artist_name print error errors.append(error) except: error = traceback.format_exc() print error errors.append(error) with codecs.open('errors.log', 'w', 'utf-8') as f: for error in errors: f.write(error + '\n')
class GoogleMusic: def __init__(self): self.api = Mobileclient(debug_logging=False) with open(path + "oauth.cred", 'w+') as tmp: tmp.write(settings['google']['mobileclient']) tmp.close() self.api.oauth_login(Mobileclient.FROM_MAC_ADDRESS, tmp.name) os.remove(tmp.name) def createPlaylist(self, name, songs, public): playlistId = self.api.create_playlist(name=name, description=None, public=public) self.addSongs(playlistId, songs) print("Success: created playlist \"" + name + "\"") def addSongs(self, playlistId, songs): songIds = [] songlist = list(songs) notFound = list() for i, song in enumerate(songlist): song = song.replace(" &", "") result = self.api.search(query=song, max_results=2) if len(result['song_hits']) == 0: notFound.append(song) else: songIds.append(self.get_best_fit_song_id(result['song_hits'], song)) if i % 20 == 0: print(str(i) + ' searched') self.api.add_songs_to_playlist(playlistId, songIds) with open(path + 'noresults.txt', 'w', encoding="utf-8") as f: f.write("\n".join(notFound)) f.close() def removeSongs(self, playlistId): pl = self.api.get_all_user_playlist_contents() tracks = next(x for x in pl if x['id'] == playlistId)['tracks'] self.api.remove_entries_from_playlist([x['id'] for x in tracks]) def getPlaylistId(self, name): pl = self.api.get_all_playlists() return next(x for x in pl if x['name'].find(name) != -1)['id'] def get_best_fit_song_id(self, results, song): match_score = {} for res in results: compare = res['track']['artist'] + ' ' + res['track']['title'] match_score[res['track']['storeId']] = difflib.SequenceMatcher(a=song.lower(), b=compare.lower()).ratio() return max(match_score, key=match_score.get) def remove_playlists(self, pattern): pl = self.api.get_all_playlists() p = re.compile("{0}".format(pattern)) matches = [song for song in pl if p.match(song['name'])] print("The following playlists will be removed:") print("\n".join([song['name'] for song in matches])) print("Please confirm (y/n):") choice = input().lower() if choice[:1] == 'y': [self.api.delete_playlist(song['id']) for song in matches] print(str(len(matches)) + " playlists deleted.") else: print("Aborted. No playlists were deleted.")
class MobileClientWrapper: def __init__(self, config): self.client = Mobileclient(debug_logging=False) login = self.client.login(config.user_name, config.password, Mobileclient.FROM_MAC_ADDRESS) if not login: raise ConnectionError( 'MobileClientWrapper - Login Error Please Check Google Play Username and Password' ) def logout(self): self.client.logout() def get_all_playlist_content(self): """ :return: list of all Playlist content as dictionaries. """ return self.client.get_all_user_playlist_contents() def create_playlist(self, new_playlist_name, description_text, public_bool): """ Creates a Playlist with given information and returns its id :param new_playlist_name: name to give new PlayList :param description_text: description text of new Playlist :param public_bool: True/False value to specify public sharing on new Playlist :return: playlist id """ return self.client.create_playlist(new_playlist_name, description=description_text, public=public_bool) def delete_playlist(self, play_list_id): """ Delete a Playlist with given Id :param play_list_id: playlist ID """ self.client.delete_playlist(play_list_id) def add_songs_to_playlist(self, play_list_id, song_ids): """ Adds given song(s) to given Playlist. :param play_list_id: id of the target Playlist :param song_ids: id(s) of the target Song to add :return: list of Playlist Entry ids added """ return self.client.add_songs_to_playlist(play_list_id, song_ids) def get_track_info(self, store_track_id): """ Returns information on a store track :param store_track_id: target TrackId """ return self.client.get_track_info(store_track_id) def search(self, search_query): """ Searches based on searchQuery :param search_query: query to run through music library :return: dictionary of hits """ return self.client.search(search_query, max_results=10)
from gmusicapi import Mobileclient # google play musicのプレイリストを順に削除 mc = Mobileclient() mc.oauth_login(mc.FROM_MAC_ADDRESS) # google play musicのプレイリストを取得 gPlaylists = mc.get_all_playlists() for gPlaylist in gPlaylists: mc.delete_playlist(gPlaylist['id']) print("deleted playlistName = {p}".format(p=gPlaylist['name']))
filteredPlaylistAndContents['tracks']) # プレイリストから消去 mc.remove_entries_from_playlist( [trackId for trackId in includeTrackIdsIter]) break # プレイリストの登録曲数がgoogle play musicの最大登録数よりも多い場合は iPlaylistItems = len(iPlaylist.items) if (iPlaylistItems > MAX_GPLAYLIST_SONGS_NUM): # オーバーしている旨のメッセージを出す print("playlistName = {p} is over max playlist song size :{n}".format( p=iPlaylist.itunesAttibutes['Name'], n=iPlaylistItems)) # プレイリストが存在している場合は削除する。 if gPlaylistId != None: mc.delete_playlist(gPlaylistId) # return exit() # プレイリストが見つからなかったら新たに作成する。 if gPlaylistId == None: gPlaylistId = mc.create_playlist(iPlaylist.itunesAttibutes['Name']) # google play musicのsong idを取得 def getGSongId(songName, artist, album): # itunesのタイトル、アルバム、アーティストに一致するgoogle play musicのトラックを取得 foundGTrack = [ gTrack for gTrack in gLibrary if gTrack['title'] == songName and gTrack['album'] == album and gTrack['artist'] == artist ]
print "Available genres:" for g in genres_map.keys(): if len(g) == 0: continue # empty genre tag if len(genres_map[g]) >= 20: print g + "\t" + str(len(genres_map[g])) + " tracks --> generating playlist" good_genres.append(g) else: print g + "\t" + str(len(genres_map[g])) + " tracks --> too few tracks" print # remove all existing auto-playlists first playlists = api.get_all_playlists() for p in playlists: if p["name"].startswith("genre auto-playlist"): print "Removing playlist " + p["name"] api.delete_playlist(p["id"]) for genre in good_genres: playlist = genres_map[genre] playlist_name = "genre auto-playlist - " + genre print "Creating playlist " + playlist_name pid = api.create_playlist( playlist_name, description="Test " + genre + " playlist created automatically with a script", public=False ) api.add_songs_to_playlist(pid, playlist)
class GPM(object): _api = None def __init__(self): self._api = Mobileclient(debug_logging=False) if not self._api.login(GPM_EMAIL_ADDRESS, GPM_APP_PASSWORD, Mobileclient.FROM_MAC_ADDRESS): raise Exception("Failed to authenticate with GPM") def _delete_playlist(self, playlist_id): return self._api.delete_playlist(playlist_id) def _create_playlist(self, name, description): return self._api.create_playlist(name, description) def _add_songs_to_playlist(self, playlist_id, song_ids): return self._api.add_songs_to_playlist(playlist_id, song_ids) def _match_song(self, song): query = f'{song.title} {song.artist}' results = self._api.search(query) hits = [song_hit['track'] for song_hit in results.get('song_hits')] # Check if song is a match for hit in hits: if is_match(hit['title'], song.title) and is_match( hit['artist'], song.artist): return hit['storeId'] return None def _get_playlist(self, name): playlists = self._api.get_all_user_playlist_contents() for playlist in playlists: if playlist['name'] == name: return playlist return None def get_playlist(self, name): playlist = self._get_playlist(name) return Playlist.from_gpm(playlist) if playlist else None def create_playlist(self, playlist, override): gpm_playlist = self.get_playlist(playlist.title) gpm_playlist_id = gpm_playlist.id if gpm_playlist else None # Delete if it already exists if gpm_playlist_id and override: self._delete_playlist(gpm_playlist_id) # Create it if we are re-making it or it didn't already exist if not gpm_playlist_id or override: gpm_playlist_id = self._create_playlist(playlist.title, playlist.description) # Get all song_ids and remove results we could not match matches = [self._match_song(song) for song in playlist.songs] song_ids = [match for match in matches if match is not None] self._add_songs_to_playlist(gpm_playlist_id, song_ids) # Return number of songs added to playlist return len(song_ids)
allcontents = api.get_all_user_playlist_contents() playlist_name = 'scout' exists = False existing_tracks = [] exists = False delete_old = False for i in allcontents: if i['name'] == playlist_name: playlist_id = i['id'] if delete_old == True: print(('Deleting old playlist {0}'.format(playlist_name))) print(('Playlist ID: {0}'.format(playlist_id))) api.delete_playlist(playlist_id) else: exists = True existing_tracks = i['tracks'] if exists == False: print(('Creating playlist {0}'.format(playlist_name))) playlist_id = api.create_playlist(playlist_name, description=None, public=False) print(('Playlist ID: {0}'.format(playlist_id))) existing_tracks = [] if exists == False: print(('Creating playlist {0}'.format(playlist_name))) playlist_id = api.create_playlist(playlist_name,
class LivePlaylist: 'Class to handle logging into the GPMAA server and creating the playlist' def __init__(self, url, make=False): self.setup_logging() self.setlist = Setlist(url) self.api = Mobileclient() self.logged_in = self.api.login(EMAIL, TOKEN, Mobileclient.FROM_MAC_ADDRESS) if self.logged_in: self.search_for_songs() if make: self.make_playlist() def setup_logging(self): logger_name = '.'.join([__name__, __class__.__name__]) self.logger = logging.getLogger(logger_name) logging.getLogger('gmusicapi.protocol.shared').setLevel(logging.INFO) logging.getLogger('urllib3.connectionpool').setLevel(logging.WARNING) def info(self, msg): self.logger.info(msg) def debug(self, msg): self.logger.debug(msg) def make_playlist(self): self.songIDs = [self.resdict[s][0]['storeId'] for s in self.resdict.keys()] self.info("Creating playlist...") name = "{} - {}".format(self.setlist.artist, self.setlist.date) self.debug(name) desc = "{} live at {} on {}".format(self.setlist.artist, self.setlist.venue, self.setlist.date) self.debug(desc) self.id = self.api.create_playlist(name, desc) self.info("Playlist id: {}".format(self.id)) self.debug("Song IDs {!s}".format(self.songIDs)) self.api.add_songs_to_playlist(self.id, self.songIDs) return self.id def search_for_songs(self): self.info("Finding song info...") self.resdict = {name: [] for name in self.setlist.song_names} for song_name, r in self.resdict.items(): query = "{} {}".format(self.setlist.artist, song_name) self.debug("Searching".ljust(20, '.') + query) results = self.api.search(query)['song_hits'] results = [x['track'] for x in results] r.extend(results) self.debug('{} results found'.format(len(results))) # Remove songs that had 0 results self.resdict = {name: results for name, results in self.resdict.items() if len(results) > 0} def print_results(self): for k, r in self.resdict.items(): self.info("{:50}|{:35}|{:25}".format("Title", "Album", "Artist")) for result in r: t = result['title'] alb = result['album'] art = result['artist'] self.info("{:50}|{:35}|{:25}".format(t, alb, art)) self.info("-" * 110) def delete_playlist(self): self.info("Deleting playlist id: %s" % self.id) self.api.delete_playlist(self.id)