class GMusicWS: def __init__(self, user, password, playlistName): self.playlistName = playlistName self.api = Mobileclient() print("Logging into MobileClient API") self.api.login(user, password, "android_id") #insert unique android_id here def mapUnknownTracks(self, db): playlist = db.unmappedTracks() for track in playlist: searchstr = track.artist + " " + track.song print("Searching for %s" % (searchstr)) try: result = self.api.search_all_access(searchstr, max_results=1) print("Found " + result['song_hits'][0]['track']['artist'] + " - " + result['song_hits'][0]['track']['title']) nid = result['song_hits'][0]['track']['nid'] db.storemapping(track.song, track.artist, nid) except: print("Error parsing result: " + str(result)) time.sleep(1) def maintain(self, tracks): print("Searching for playlist %s" % (self.playlistName)) found = False searchres = self.api.get_all_playlists() for list in searchres: if list['name'] == self.playlistName: found = True pid = list['id'] if not found: print("Not found - creating") pid = self.api.create_playlist(self.playlistName) print("Playlist id is %s" % (pid)) print("Getting current contents") playlists = self.api.get_all_user_playlist_contents() currentEntries = [] for playlist in playlists: if playlist['name'] == self.playlistName: for entry in playlist['tracks']: currentEntries.append(entry['id']) print("Removing songs") self.api.remove_entries_from_playlist(currentEntries) print("Adding songs") self.api.add_songs_to_playlist(pid, tracks)
class GMusicWS: def __init__(self, user, password, playlistName): self.playlistName = playlistName self.api = Mobileclient() print ("Logging into MobileClient API") self.api.login(user, password,"android_id") #insert unique android_id here def mapUnknownTracks(self, db): playlist = db.unmappedTracks() for track in playlist: searchstr = track.artist + " " + track.song print ("Searching for %s" % (searchstr)) try: result = self.api.search_all_access(searchstr, max_results=1) print ("Found " + result['song_hits'][0]['track']['artist'] + " - " + result['song_hits'][0]['track']['title']) nid = result['song_hits'][0]['track']['nid'] db.storemapping(track.song, track.artist, nid) except: print ("Error parsing result: " + str(result)) time.sleep(1) def maintain(self, tracks): print ("Searching for playlist %s" % (self.playlistName)) found = False searchres = self.api.get_all_playlists() for list in searchres: if list['name'] == self.playlistName: found = True pid = list['id'] if not found: print ("Not found - creating") pid = self.api.create_playlist(self.playlistName) print ("Playlist id is %s" % (pid)) print ("Getting current contents") playlists = self.api.get_all_user_playlist_contents() currentEntries = [] for playlist in playlists: if playlist['name'] == self.playlistName: for entry in playlist['tracks']: currentEntries.append(entry['id']) print ("Removing songs") self.api.remove_entries_from_playlist(currentEntries) print ("Adding songs") self.api.add_songs_to_playlist(pid, tracks)
class GMusicAPI(): def __init__(self, username=None, encrypted_pass=None): self._api = Mobileclient() self.logged_in = False if username and encrypted_pass: self.login(username, encrypted_pass) def login(self, username, encrypted_pass): self.logged_in = self._api.login(username, decrypt(encrypted_pass), Mobileclient.FROM_MAC_ADDRESS) def logout(self): self._api.logout() self.logged_in = False def clear_playlist(self, playlist_name): playlists = self._api.get_all_user_playlist_contents() playlist = [playlist for playlist in playlists if playlist['name'] == playlist_name][0] entry_ids = [entry['id'] for entry in playlist['tracks']] removed = self._api.remove_entries_from_playlist(entry_ids) return len(removed) def search(self, *args): """ Returns the best-fitting track dict for the given information. :param args: Strings which can be artist, song title, album etc. :return: """ query = sanitise_query(' '.join(args)) result = self._api.search(query) song_results = result['song_hits'] if not song_results: warnings.warn('Warning: query {} returned no song hits.'.format(query)) return None tracks = [song_result['track'] for song_result in song_results[:5]] for track in tracks: if not is_tribute(track, query): return track warnings.warn('Warning: query {} returned no non-tribute song hits.'.format(query)) return None def get_playlist_id(self, playlist_name): for playlist in self._api.get_all_playlists(): if playlist['name'] == playlist_name: return playlist['id'] raise ValueError("Playlist '{}' not found".format(playlist_name)) def add_songs(self, playlist_name, tracks): playlist_id = self.get_playlist_id(playlist_name) track_ids = [track['nid'] for track in tracks if track] self._api.add_songs_to_playlist(playlist_id, track_ids)
class GmSession: def __init__(self): self.session = Mobileclient() self.device_id = gmusic_device_id self.cred_path = gmusic_cred_path self.playlist_id = gmusic_playlist_id def login(self): self.session.oauth_login(device_id=self.device_id, oauth_credentials=self.cred_path) def logout(self): self.session.logout() def search(self, artist, song): search_string = f'{artist.lower()}' + f', {song.lower()}' results = self.session.search(search_string, max_results=20) if len(results['song_hits']) > 0: first_result = results['song_hits'][0]['track'] if 'storeId' in first_result.keys(): return first_result['storeId'] elif 'id' in first_result.keys(): print('bad id') return first_result['id'] elif 'nid' in first_result.keys(): print('bad id') return results['song_hits'][0]['track']['nid'] else: print('No songs found...') def add_to_playlist(self, song_list): playlists = self.session.get_all_user_playlist_contents() for playlist in playlists: if playlist['id'] == self.playlist_id: to_remove = [] for track in playlist['tracks']: to_remove.append(track['id']) print('Adding new songs...') res = self.session.add_songs_to_playlist( self.playlist_id, song_list) print('Removing previous songs...') out = self.session.remove_entries_from_playlist(to_remove) print('Finished')
# Foreach deleted entry, check if it's undeleted in any of the source playlists # If so, delete it for row in deletedTracks: trackId = row[0] sql = """ SELECT `gpm_entryid` FROM `gpm_playlist_entries` JOIN `gpm_playlists` USING (`gpm_playlistid`) WHERE `gpm_playlists`.`deleted` = 0 AND `gpm_playlists`.`name` LIKE 'Background %%' AND `gpm_playlist_entries`.`deleted` = 0 AND `gpm_trackid` = %(trackId)s """ params = { "trackId": trackId, } cursor.execute(sql, params) otherListEntries = cursor.fetchall() if len(otherListEntries) < 1: continue logger.info("Deleted track " + trackId + " was found in another playlist... deleting") otherEntryIds = [] for otherRow in otherListEntries: otherEntryIds.append(otherRow[0]) logger.info("Deleting playlist entries: "+ ", ".join(otherEntryIds)) gpm.remove_entries_from_playlist(otherEntryIds) logger.info("DONE!")
big_playlist = [p for p in playlists if p['name'] == secret.BIG_PLAYLIST][0] uncategorized_lst = [p for p in playlists if p['name'] == secret.UNCATEGORIZED] category_a_lst = [p for p in playlists if p['name'] == secret.CATEGORY_A] category_b_lst = [p for p in playlists if p['name'] == secret.CATEGORY_B] # If "Uncategorized" playlist already exists, remove all songs from it. # Otherwise create the playlist. if uncategorized_lst: uncategorized_playlist = uncategorized_lst[0] if 'tracks' in uncategorized_playlist: old_uncategorized_songs_set = { song['id'] for song in uncategorized_playlist['tracks'] } old_uncategorized_songs_lst = list(old_uncategorized_songs_set) api.remove_entries_from_playlist(old_uncategorized_songs_lst) print("Cleared all songs from uncategorized playlist named", secret.UNCATEGORIZED) else: api.create_playlist(secret.UNCATEGORIZED) print("Created playlist for uncategorized songs, named", secret.UNCATEGORIZED) # If "Category A"playlist does not exist, create it if not category_a_lst: api.create_playlist(secret.CATEGORY_A) print("Created playlist named", secret.CATEGORY_A) # If "Category B"playlist does not exist, create it if not category_b_lst: api.create_playlist(secret.CATEGORY_B)
class MusicSync(object): def __init__(self, email=None, password=None): self.mm = Musicmanager() self.wc = Webclient() self.mc = Mobileclient() if not email: email = raw_input("Email: ") if not password: password = getpass() self.email = email self.password = password self.logged_in = self.auth() print "Fetching playlists from Google..." self.playlists = self.mc.get_all_user_playlist_contents() #self.playlists = self.mc.get_all_playlists() #self.playlists = self.wc.get_all_playlist_ids(auto=False) self.all_songs = self.mc.get_all_songs() #print "Got %d playlists." % len(self.playlists['user']) print "Got %d playlists containing %d songs." % (len( self.playlists), len(self.all_songs)) print "" def auth(self): self.logged_in = self.mc.login(self.email, self.password) #self.logged_in = self.wc.login(self.email, self.password) if not self.logged_in: print "Login failed..." exit() print "" print "Logged in as %s" % self.email print "" if not os.path.isfile(OAUTH_FILEPATH): print "First time login. Please follow the instructions below:" self.mm.perform_oauth() self.logged_in = self.mm.login() if not self.logged_in: print "OAuth failed... try deleting your %s file and trying again." % OAUTH_FILEPATH exit() print "Authenticated" print "" def sync_playlist(self, filename, remove_missing): #def sync_playlist(self, filename, remove_missing=False): filename = self.get_platform_path(filename) os.chdir(os.path.dirname(filename)) title = os.path.splitext(os.path.basename(filename))[0] print "Syncing playlist: %s" % filename #if title not in self.playlists['user']: #print " didn't exist... creating..." #self.playlists['user'][title] = [self.wc.create_playlist(title)] print "" plid = "" for pl in self.playlists: if pl['name'] == title: plid = pl['id'] goog_songs = pl['tracks'] if plid == "": print " didn't exist... creating..." plid = self.mc.create_playlist(self, title) #plid = self.playlists['user'][title][0] #goog_songs = self.wc.get_playlist_songs(plid) print "%d songs already in Google Music playlist" % len(goog_songs) pc_songs = self.get_files_from_playlist(filename) print "%d songs in local playlist" % len(pc_songs) print "" # Sanity check max 1000 songs per playlist if len(pc_songs) > MAX_SONGS_IN_PLAYLIST: print " Google music doesn't allow more than %d songs in a playlist..." % MAX_SONGS_IN_PLAYLIST print " Will only attempt to sync the first %d songs." % MAX_SONGS_IN_PLAYLIST del pc_songs[MAX_SONGS_IN_PLAYLIST:] existing_files = 0 added_files = 0 failed_files = 0 removed_files = 0 fatal_count = 0 for fn in pc_songs: if self.file_already_in_list(fn, goog_songs, self.all_songs): existing_files += 1 continue print "" print "Adding: %s" % os.path.basename(fn).encode('cp1252') #print "Adding: %s" % os.path.basename(fn) #online = False online = self.find_song(fn, goog_songs, self.all_songs) #online = self.find_song(fn) song_id = None if online: song_id = online['id'] print " already uploaded [%s]" % song_id else: attempts = 0 result = [] while not result and attempts < MAX_UPLOAD_ATTEMPTS_PER_FILE: print " uploading... (may take a while)" attempts += 1 try: result = self.mm.upload(fn) except (BadStatusLine, CannotSendRequest): # Bail out if we're getting too many disconnects if fatal_count >= MAX_CONNECTION_ERRORS_BEFORE_QUIT: print "" print "Too many disconnections - quitting. Please try running the script again." print "" exit() print "Connection Error -- Reattempting login" fatal_count += 1 self.wc.logout() self.mc.logout() self.mm.logout() result = [] time.sleep(STANDARD_SLEEP) except: result = [] time.sleep(STANDARD_SLEEP) try: if result[0]: song_id = result[0].itervalues().next() else: song_id = result[1].itervalues().next() print " upload complete [%s]" % song_id except: print " upload failed - skipping" tag = self.get_id3_tag(fn) print " failed song:\t%s\t%s\t%s" % ( tag['title'].encode('cp1252'), tag['artist'].encode('cp1252'), tag['album'].encode('cp1252')) if not song_id: failed_files += 1 continue added = self.mc.add_songs_to_playlist(plid, song_id) time.sleep(.3) # Don't spam the server too fast... print " done adding to playlist" added_files += 1 if remove_missing: for g in goog_songs: for s in self.all_songs: if g['trackId'] == s['id']: print "" print "Removing: %s" % s['title'].encode('cp1252') self.mc.remove_entries_from_playlist(g['id']) #self.wc.remove_songs_from_playlist(plid, s.id) time.sleep(.3) # Don't spam the server too fast... removed_files += 1 print "" print "---" print "%d songs unmodified" % existing_files print "%d songs added" % added_files print "%d songs failed" % failed_files print "%d songs removed" % removed_files def get_files_from_playlist(self, filename): files = [] f = codecs.open(filename, encoding='cp1252') #f = codecs.open(filename, encoding='utf-8') for line in f: line = line.rstrip().replace(u'\ufeff', u'') if line == "" or line[0] == "#": continue path = os.path.abspath(self.get_platform_path(line)) if not os.path.exists(path): print "File not found: %s" % line continue files.append(path) f.close() return files def file_already_in_list(self, filename, goog_songs, all_songs): tag = self.get_id3_tag(filename) print "Searching for\t%s\t%s\t%s" % (tag['title'].encode('cp1252'), tag['artist'].encode('cp1252'), tag['album'].encode('cp1252')) i = 0 while i < len(goog_songs): for s in all_songs: if goog_songs[i]['trackId'] == s['id']: if self.tag_compare(s, tag): print "Found match\t%s\t%s\t%s" % ( s['title'].encode('cp1252'), s['artist'].encode('cp1252'), s['album'].encode('cp1252')) goog_songs.pop(i) return True i += 1 return False def get_id3_tag(self, filename): data = mutagen.File(filename, easy=True) r = {} if 'title' not in data: title = os.path.splitext(os.path.basename(filename))[0] print 'Found song with no ID3 title, setting using filename:' print ' %s' % title print ' (please note - the id3 format used (v2.4) is invisible to windows)' data['title'] = [title] data.save() r['title'] = data['title'][0] r['track'] = int(data['tracknumber'][0].split('/') [0]) if 'tracknumber' in data else 0 # If there is no track, try and get a track number off the front of the file... since thats # what google seems to do... # Not sure how google expects it to be formatted, for now this is a best guess if r['track'] == 0: m = re.match("(\d+) ", os.path.basename(filename)) if m: r['track'] = int(m.group(0)) r['artist'] = data['artist'][0] if 'artist' in data else '' r['album'] = data['album'][0] if 'album' in data else '' return r def find_song(self, filename, goog_songs, all_songs): tag = self.get_id3_tag(filename) print "Searching for\t%s\t%s\t%s" % (tag['title'].encode('cp1252'), tag['artist'].encode('cp1252'), tag['album'].encode('cp1252')) #results = self.wc.search(tag['title']) # NOTE - diagnostic print here to check results if you're creating duplicates #print results['song_hits'] #for r in goog_songs: #for r in results['song_hits']: for s in all_songs: #if r['trackId'] == s['id']: if self.tag_compare(s, tag): # TODO: add rough time check to make sure its "close" print "Found match\t%s\t%s\t%s" % ( s['title'].encode('cp1252'), s['artist'].encode('cp1252'), s['album'].encode('cp1252')) return s return None def tag_compare(self, g_song, tag): # If a google result has no track, google doesn't return a field for it if 'title' not in g_song: g_song['title'] = "" if 'artist' not in g_song: g_song['artist'] = "" if 'album' not in g_song: g_song['album'] = "" if 'track' not in g_song: g_song['track'] = 0 if (g_song['title'].lower() == tag['title'].lower() and g_song['artist'].lower() == tag['artist'].lower()) or\ (g_song['album'].lower() == tag['album'].lower() and g_song['title'].lower() == tag['title'].lower()) or\ (g_song['artist'].lower() == tag['artist'].lower() and g_song['album'].lower() == tag['album'].lower() and g_song['track'] == tag['track']): print "Partial match\t%s\t%s\t%s" % ( g_song['title'].encode('cp1252'), g_song['artist'].encode('cp1252'), g_song['album'].encode('cp1252')) return g_song['title'].lower() == tag['title'].lower() and\ g_song['artist'].lower() == tag['artist'].lower() and\ g_song['album'].lower() == tag['album'].lower() #and\ #g_song['track'] == tag['track'] def delete_song(self, sid): self.mc.delete_songs(sid) print "Deleted song by id [%s]" % sid def get_platform_path(self, full_path): # Try to avoid messing with the path if possible if os.sep == '/' and '\\' not in full_path: return full_path if os.sep == '\\' and '\\' in full_path: return full_path if '\\' not in full_path: return full_path return os.path.normpath(full_path.replace('\\', '/'))
class MusicSync(object): def __init__(self, email=None, password=None): self.mm = Musicmanager() self.wc = Webclient() self.mc = Mobileclient() if not email: email = raw_input("Email: ") if not password: password = getpass() self.email = email self.password = password self.logged_in = self.auth() print "Fetching playlists from Google..." self.playlists = self.mc.get_all_user_playlist_contents() #self.playlists = self.mc.get_all_playlists() #self.playlists = self.wc.get_all_playlist_ids(auto=False) self.all_songs = self.mc.get_all_songs() #print "Got %d playlists." % len(self.playlists['user']) print "Got %d playlists containing %d songs." % (len(self.playlists), len(self.all_songs)) print "" def auth(self): self.logged_in = self.mc.login(self.email, self.password) #self.logged_in = self.wc.login(self.email, self.password) if not self.logged_in: print "Login failed..." exit() print "" print "Logged in as %s" % self.email print "" if not os.path.isfile(OAUTH_FILEPATH): print "First time login. Please follow the instructions below:" self.mm.perform_oauth() self.logged_in = self.mm.login() if not self.logged_in: print "OAuth failed... try deleting your %s file and trying again." % OAUTH_FILEPATH exit() print "Authenticated" print "" def sync_playlist(self, filename, remove_missing): #def sync_playlist(self, filename, remove_missing=False): filename = self.get_platform_path(filename) os.chdir(os.path.dirname(filename)) title = os.path.splitext(os.path.basename(filename))[0] print "Syncing playlist: %s" % filename #if title not in self.playlists['user']: #print " didn't exist... creating..." #self.playlists['user'][title] = [self.wc.create_playlist(title)] print "" plid = "" for pl in self.playlists: if pl['name'] == title: plid = pl['id'] goog_songs = pl['tracks'] if plid == "": print " didn't exist... creating..." plid = self.mc.create_playlist(self, title) #plid = self.playlists['user'][title][0] #goog_songs = self.wc.get_playlist_songs(plid) print "%d songs already in Google Music playlist" % len(goog_songs) pc_songs = self.get_files_from_playlist(filename) print "%d songs in local playlist" % len(pc_songs) print "" # Sanity check max 1000 songs per playlist if len(pc_songs) > MAX_SONGS_IN_PLAYLIST: print " Google music doesn't allow more than %d songs in a playlist..." % MAX_SONGS_IN_PLAYLIST print " Will only attempt to sync the first %d songs." % MAX_SONGS_IN_PLAYLIST del pc_songs[MAX_SONGS_IN_PLAYLIST:] existing_files = 0 added_files = 0 failed_files = 0 removed_files = 0 fatal_count = 0 for fn in pc_songs: if self.file_already_in_list(fn, goog_songs, self.all_songs): existing_files += 1 continue print "" print "Adding: %s" % os.path.basename(fn).encode('cp1252') #print "Adding: %s" % os.path.basename(fn) #online = False online = self.find_song(fn, goog_songs, self.all_songs) #online = self.find_song(fn) song_id = None if online: song_id = online['id'] print " already uploaded [%s]" % song_id else: attempts = 0 result = [] while not result and attempts < MAX_UPLOAD_ATTEMPTS_PER_FILE: print " uploading... (may take a while)" attempts += 1 try: result = self.mm.upload(fn) except (BadStatusLine, CannotSendRequest): # Bail out if we're getting too many disconnects if fatal_count >= MAX_CONNECTION_ERRORS_BEFORE_QUIT: print "" print "Too many disconnections - quitting. Please try running the script again." print "" exit() print "Connection Error -- Reattempting login" fatal_count += 1 self.wc.logout() self.mc.logout() self.mm.logout() result = [] time.sleep(STANDARD_SLEEP) except: result = [] time.sleep(STANDARD_SLEEP) try: if result[0]: song_id = result[0].itervalues().next() else: song_id = result[1].itervalues().next() print " upload complete [%s]" % song_id except: print " upload failed - skipping" tag = self.get_id3_tag(fn) print " failed song:\t%s\t%s\t%s" % (tag['title'].encode('cp1252'), tag['artist'].encode('cp1252'), tag['album'].encode('cp1252')) if not song_id: failed_files += 1 continue added = self.mc.add_songs_to_playlist(plid, song_id) time.sleep(.3) # Don't spam the server too fast... print " done adding to playlist" added_files += 1 if remove_missing: for g in goog_songs: for s in self.all_songs: if g['trackId'] == s['id']: print "" print "Removing: %s" % s['title'].encode('cp1252') self.mc.remove_entries_from_playlist(g['id']) #self.wc.remove_songs_from_playlist(plid, s.id) time.sleep(.3) # Don't spam the server too fast... removed_files += 1 print "" print "---" print "%d songs unmodified" % existing_files print "%d songs added" % added_files print "%d songs failed" % failed_files print "%d songs removed" % removed_files def get_files_from_playlist(self, filename): files = [] f = codecs.open(filename, encoding='cp1252') #f = codecs.open(filename, encoding='utf-8') for line in f: line = line.rstrip().replace(u'\ufeff',u'') if line == "" or line[0] == "#": continue path = os.path.abspath(self.get_platform_path(line)) if not os.path.exists(path): print "File not found: %s" % line continue files.append(path) f.close() return files def file_already_in_list(self, filename, goog_songs, all_songs): tag = self.get_id3_tag(filename) print "Searching for\t%s\t%s\t%s" % (tag['title'].encode('cp1252'), tag['artist'].encode('cp1252'), tag['album'].encode('cp1252')) i = 0 while i < len(goog_songs): for s in all_songs: if goog_songs[i]['trackId'] == s['id']: if self.tag_compare(s, tag): print "Found match\t%s\t%s\t%s" % (s['title'].encode('cp1252'), s['artist'].encode('cp1252'), s['album'].encode('cp1252')) goog_songs.pop(i) return True i += 1 return False def get_id3_tag(self, filename): data = mutagen.File(filename, easy=True) r = {} if 'title' not in data: title = os.path.splitext(os.path.basename(filename))[0] print 'Found song with no ID3 title, setting using filename:' print ' %s' % title print ' (please note - the id3 format used (v2.4) is invisible to windows)' data['title'] = [title] data.save() r['title'] = data['title'][0] r['track'] = int(data['tracknumber'][0].split('/')[0]) if 'tracknumber' in data else 0 # If there is no track, try and get a track number off the front of the file... since thats # what google seems to do... # Not sure how google expects it to be formatted, for now this is a best guess if r['track'] == 0: m = re.match("(\d+) ", os.path.basename(filename)) if m: r['track'] = int(m.group(0)) r['artist'] = data['artist'][0] if 'artist' in data else '' r['album'] = data['album'][0] if 'album' in data else '' return r def find_song(self, filename, goog_songs, all_songs): tag = self.get_id3_tag(filename) print "Searching for\t%s\t%s\t%s" % (tag['title'].encode('cp1252'), tag['artist'].encode('cp1252'), tag['album'].encode('cp1252')) #results = self.wc.search(tag['title']) # NOTE - diagnostic print here to check results if you're creating duplicates #print results['song_hits'] #for r in goog_songs: #for r in results['song_hits']: for s in all_songs: #if r['trackId'] == s['id']: if self.tag_compare(s, tag): # TODO: add rough time check to make sure its "close" print "Found match\t%s\t%s\t%s" % (s['title'].encode('cp1252'), s['artist'].encode('cp1252'), s['album'].encode('cp1252')) return s return None def tag_compare(self, g_song, tag): # If a google result has no track, google doesn't return a field for it if 'title' not in g_song: g_song['title'] = "" if 'artist' not in g_song: g_song['artist'] = "" if 'album' not in g_song: g_song['album'] = "" if 'track' not in g_song: g_song['track'] = 0 if (g_song['title'].lower() == tag['title'].lower() and g_song['artist'].lower() == tag['artist'].lower()) or\ (g_song['album'].lower() == tag['album'].lower() and g_song['title'].lower() == tag['title'].lower()) or\ (g_song['artist'].lower() == tag['artist'].lower() and g_song['album'].lower() == tag['album'].lower() and g_song['track'] == tag['track']): print "Partial match\t%s\t%s\t%s" % (g_song['title'].encode('cp1252'), g_song['artist'].encode('cp1252'), g_song['album'].encode('cp1252')) return g_song['title'].lower() == tag['title'].lower() and\ g_song['artist'].lower() == tag['artist'].lower() and\ g_song['album'].lower() == tag['album'].lower() #and\ #g_song['track'] == tag['track'] def delete_song(self, sid): self.mc.delete_songs(sid) print "Deleted song by id [%s]" % sid def get_platform_path(self, full_path): # Try to avoid messing with the path if possible if os.sep == '/' and '\\' not in full_path: return full_path if os.sep == '\\' and '\\' in full_path: return full_path if '\\' not in full_path: return full_path return os.path.normpath(full_path.replace('\\', '/'))
# google play musicの一致するプレイリストを取得 filteredPlaylistsAndContentsIter = filter( lambda v: v['name'] == iPlaylist.itunesAttibutes['Name'], gPlaylistsAndContents) # 一致するプレイリストが見つかったら for filteredPlaylistAndContents in filteredPlaylistsAndContentsIter: # googleplaymusicのプレイリストIDを取得 gPlaylistId = filteredPlaylistAndContents['id'] # プレイリストに含まれるトラックidのリストを取得して includeTrackIdsIter = map(lambda v: v['id'], 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() # プレイリストが見つからなかったら新たに作成する。
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 MusicPlayer(object): def __init__(self): self.playlist = [] # Array of all tracks self.playlist_id = 0 # Id of playlist self.current_track_index = 0 # Index of current song self.player = Player() # MPlayer instance self.webclient = Webclient() # Client for WebInterface self.mobileclient = Mobileclient() # Client for MobileInterface self.timer = None # Timer to start next track self.deviceid = 0 # DeviceId to use self.playtype = PlayType.LINEAR # LINEAR or SHUFFLE def login(self, username, password): """ Login to Google Music. Keyword arguments: username -- the username password -- the password Returns: True if successful else False """ # If either the web client or the mobile client failed to login return False if not self.webclient.login(username, password) or not self.mobileclient.login(username, password): return False # Use first found devices as ID devices = self.webclient.get_registered_devices(); # Convert HEX to INT self.deviceid = int(devices[0]['id'], 16) return True def load_playlist(self, playlist_name): # Load playlist for playlist in self.mobileclient.get_all_user_playlist_contents(): if playlist['name'] == playlist_name: for track_obj in playlist['tracks']: track_obj['track']['id'] = track_obj['id'] self.playlist.append(track_obj['track']) # Set playlist_id self.playlist_id = playlist['id'] break; # If playlist has not been found, create it if self.playlist_id == 0: self.playlist_id = self.mobileclient.create_playlist(playlist_name) def add_track_to_playlist(self, track): """ Append a track to the end of playlist Keyword arguments: track -- a dictionary containing the track informations """ track_id = self.mobileclient.add_songs_to_playlist(self.playlist_id, track['nid'])[0] track['id'] = track_id self.playlist.append(track) # Notify all clients about the new track factory.forwarder.dispatch(PLAYLIST_EVENT_TRACK_ADDED, json.dumps(track)) def remove_track_from_playlist(self, track_id): """ Removes a track from the playlist Keyword arguments: track_id -- The id of the track to remove """ self.mobileclient.remove_entries_from_playlist(track_id) index_to_remove = self._find_index_of_track_id(track_id) del self.playlist[index_to_remove] factory.forwarder.dispatch(PLAYLIST_EVENT_TRACK_REMOVED, track_id) def play_track(self, track_id): """ Play a track Keyword arguments: track_id -- Id of the track to play """ index_of_track = self._find_index_of_track_id(track_id) track_to_play = self.playlist[index_of_track] if track_to_play is not None: # Request stream url from google music stream_url = self.mobileclient.get_stream_url(track_to_play["storeId"], self.deviceid) # Load stream url to mplayer self.player.loadfile(stream_url) # For some reason OSX needs to unpause mplayer if sys.platform == "darwin": self.player.pause() # Set track self.current_track_index = index_of_track # Cancel previous timer if self.timer is not None: self.timer.cancel() # How many minutes does the track last track_duration = long(track_to_play["durationMillis"]) / 1000 # Set Timer to play next track when trackDuration is over self.timer = Timer(track_duration, self.play_next_track) self.timer.daemon = True self.timer.start() print "playing", track_to_play["artist"], " - ", track_to_play["title"], " : ", stream_url # Fire event that a new track is playing factory.forwarder.dispatch(TRACK_EVENT_PLAYBACK, json.dumps(track_to_play)) return True else: return False def play_next_track(self): """ Play the next track in the playlist. Returns: True or False """ if self.playtype == PlayType.LINEAR: # Index of next track to play next_track_index = self.current_track_index + 1 # Restart at index 0 if end of playlist is reached if next_track_index >= len(self.playlist): next_track_index = 0 elif self.playtype == PlayType.SHUFFLE: # Index of next track to play at random next_track_index = random.randrange(0, len(self.playlist), 1) # Obtain the id of the next track to play next_track_id = self.playlist[next_track_index]['id'] # Play track with that id return self.play_track(next_track_id) def play_previous_track(self): """ Play the previous track in the playlist. Returns: True or False """ if self.playtype == PlayType.LINEAR: # Index of previous track to play previous_track_index = self.current_track_index - 1 # Contiune from the end of the playlist if previous_track_index <= 0: previous_track_index = len(self.playlist) - 1 elif self.playtype == PlayType.SHUFFLE: # Index of the previous track is random previous_track_index = random.randrange(0, len(self.playlist), 1) # Obtain the id of the previous track to play previous_track_id = self.playlist[previous_track_index]['id'] # Play track with that id return self.play_track(previous_track_id) def stop(self): """ Stop playback. """ if self.timer is not None: self.timer.cancel() if self.player is not None: self.player.stop() def play(self): """ Start playing current track Returns: True if track has been started. Else False """ current_track_id = self.playlist[self.current_track_index] return self.play_track(current_track_id) def _find_index_of_track_id(self, track_id): index = 0 for track in self.playlist: if track['id'] == track_id: return index index += 1 return None
# Get contents of our playlist playlist = list( filter(lambda p: p['id'] == playlistId, mc.get_all_user_playlist_contents()))[0] # If a track's been modified since it was added, it's been played. # Find all the played tracks at the start of the playlist. playedTracks = list( takewhile( lambda pt: pt['creationTimestamp'] < list( filter(lambda t: t['id'] == pt['trackId'], allTracks))[0][ 'lastModifiedTimestamp'], playlist['tracks'])) playedTrackIds = list(map(lambda pt: pt['id'], playedTracks)) # Remove the played tracks from the playlist mc.remove_entries_from_playlist(playedTrackIds) print('Removed {0} played tracks'.format(len(playedTrackIds))) trackCount = len(playlist['tracks']) - len(playedTrackIds) print('{0} tracks on playlist'.format(trackCount)) # Pick out all the albums from the songs our library and shuffle them albums = list( set(map(lambda t: t['albumArtist'] + '/' + t['album'], allTracks))) random.shuffle(albums) # Keep adding albums until we've got at least 900 tracks on the playlist while trackCount < 900: album = albums.pop(0) # Get the tracks on the album sorted by track number
class PlaylistManager(object): def __init__(self, email_file): self.login(email_file) self._get_songs() self._get_playlists() def login(self, email_file): with open(os.path.expanduser(email_file), 'r') as gmail_email_file: gmail_email = gmail_email_file.read() print "Password for " + gmail_email.strip('\n') + ":" pw = getpass.getpass() self.client = Mobileclient() self.client.login(gmail_email, pw) def _get_songs(self): self.all_songs = self.client.get_all_songs() assert isinstance(self.all_songs, list) self.all_songs_by_id = {} for song in self.all_songs: self.all_songs_by_id[song['id']] = song def _playlist_entry_dict(self, entry_dict, playlist_name): track_dict = self.all_songs_by_id[entry_dict['trackId']] track_hash = hash(playlist_name + track_dict['title'] + track_dict['artist'] + track_dict['album']) return {'title': track_dict['title'], 'entry_id': entry_dict['id'], 'track_id': entry_dict['trackId'], 'hash': track_hash} def _get_playlists(self): self.all_playlists = self.client.get_all_user_playlist_contents() assert isinstance(self.all_playlists, list) def sort_and_deduplicate_playlists(self): """de-duplicates and then sorts all user playlists""" playlist_entry_ids_to_be_removed = [] for playlist in self.all_playlists: current_playlist = [] current_playlist_entry_hashes = [] for track in playlist['tracks']: if not track['deleted']: current_track = self._playlist_entry_dict(track, playlist['name']) if not current_track['hash'] in current_playlist_entry_hashes: current_playlist.append(current_track) current_playlist_entry_hashes.append(current_track['hash']) else: # we will remove these duplicates later, so they don't mess up our sorting playlist_entry_ids_to_be_removed.append(current_track['entry_id']) if playlist_entry_ids_to_be_removed != []: print "De-duplicated " + playlist['name'] get_track_title = lambda track_dict: track_dict['title'] sorted_songs = sorted(current_playlist, key=get_track_title) sorted_track_ids = [] sorted_entry_ids = [] for track in sorted_songs: sorted_track_ids.append(track['track_id']) sorted_entry_ids.append(track['entry_id']) # if the playlist is already sorted, don't bother sorting it if sorted_songs != current_playlist: # remove all things at once for maximum efficiency self.client.add_songs_to_playlist(playlist['id'], sorted_track_ids) playlist_entry_ids_to_be_removed += sorted_entry_ids print "Re-ordered " + playlist['name'] if playlist_entry_ids_to_be_removed != []: # remove all things to be removed at once self.client.remove_entries_from_playlist(playlist_entry_ids_to_be_removed) def export_songs(self, csv_output): """writes a csv file containing info on all the songs""" # these are the field names. More might exist, but I haven't found them field_names = [u'comment', u'rating', u'composer', u'year', u'creationTimestamp', u'id', u'album', u'totalDiscCount', u'title', u'recentTimestamp', u'albumArtist', u'trackNumber', u'discNumber', u'deleted', u'totalTrackCount', u'estimatedSize', u'beatsPerMinute', u'genre', u'playCount', u'kind', u'artist', u'lastModifiedTimestamp', u'clientId', u'durationMillis', u'albumArtRef', u'artistId', u'storeId', u'nid', u'albumId', u'artistArtRef', u'trackType', u'trackOrigin', u'contentType', u'lastRatingChangeTimestamp'] with open(csv_output, 'w') as output_file_obj: csv_writer = csv.DictWriter(output_file_obj, field_names) csv_writer.writeheader() for song in self.all_songs: for x in song: # remove the unicode, replacing bad characters with "?" if isinstance(song[x], unicode): song[x] = song[x].encode('ascii', 'replace') csv_writer.writerow(song) def export_playlists(self, output_path): """writes the csv contents of each playlist to the playlist-named file in the specified folder""" if not os.path.exists(output_path): os.mkdir(output_path) if not os.path.isdir(output_path): raise Exception("Not a folder!") playlist_entry_keys = [u'absolutePosition', u'clientId', u'creationTimestamp', u'deleted', u'id', u'kind', u'lastModifiedTimestamp', u'playlistId', u'source', u'trackId'] for playlist in self.all_playlists: file_name = os.path.join(output_path, playlist[u'name'] + '.csv') with open(file_name, 'w') as output_file: csv_writer = csv.DictWriter(output_file, playlist_entry_keys) csv_writer.writeheader() for track in playlist[u'tracks']: for x in track: # remove the unicode, replacing bad characters with "?" if isinstance(track[x], unicode): track[x] = track[x].encode('ascii', 'replace') csv_writer.writerow(track) def make_local_xspf_playlists(self): """write playlists in xspf format to named files in the playlist folder. Credit to https://github.com/alastair/xspf for the wonderful xspf python module""" # output_path = 'playlists' output_path = os.path.expanduser('~/Music/Playlists') music_path = os.path.expanduser('~/Music') extension = '.mp3' if not os.path.exists(output_path): os.mkdir(output_path) if not os.path.isdir(output_path): raise Exception("Not a folder!") for playlist in self.all_playlists: output_file_path = os.path.join(output_path, playlist[u'name'] + '.xspf') playlist_xspf = xspf.Xspf() playlist_xspf.title = playlist[u'name'] for track in playlist['tracks']: track_xspf = xspf.Track() track_id = track['trackId'] track_dict = self.all_songs_by_id[track_id] artist = track_dict['artist'] album = track_dict['album'] title = track_dict['title'] track_xspf.title = title track_xspf.album = album track_xspf.creator = artist # replace is to fix the slash in 'AC/DC' track_path = 'file://' + os.path.join(music_path, artist.replace('/', ','), album.replace('/', ','), title.replace('/', ',') + extension) track_xspf.location = track_path length = str(int(track_dict['durationMillis']) / 1000) track_xspf.duration = length playlist_xspf.add_track(track_xspf) with open(output_file_path, 'wb') as output_file: # we write this header so that Sublime Text recognizes it as an XML file, and sets syntax accordingly output_file.write('<?xml version="1.0" encoding="UTF-8"?>\n') output_file.write(playlist_xspf.toXml(pretty_print=True))
index = -1 # Ensure no duplicate songs in the playlist while (unused_index == False): # Randomly select a number from the total length of songs index = random.randint(0, len(songs) - 1) try: # Will error if the number has not already been used used_index.index(index) except ValueError: # If it errors, add the value and continue used_index.append(index) # Break out of the loop unused_index = True reshuffled_songs.append(songs[index]) # Get all current songs in the reshuffled playlist current_songs = mc.get_all_user_playlist_contents() # Delete all songs from current playlist for playlist in current_songs: # Find the correct playlist if playlist.get('id') == reshuffled_playlist_id: print('Deleting ', len(playlist.get('tracks')), ' old songs from the reshuffled playlist') # Iterate over the tracks in it for song in playlist.get('tracks'): mc.remove_entries_from_playlist(song.get('id')) # Add new to playlist print('Adding new songs') for song in reshuffled_songs: mc.add_songs_to_playlist(reshuffled_playlist_id, song.get('id')) # End print('Done')
category_a_playlist = [p for p in playlists if p['name'] == secret.CATEGORY_A][0] category_b_playlist = [p for p in playlists if p['name'] == secret.CATEGORY_B][0] # Splitting up songs by whether they are categorized or not all_songs_set = get_trackids_set(big_playlist) cat_a_songs_set = get_trackids_set(category_a_playlist) cat_b_songs_set = get_trackids_set(category_b_playlist) all_categorized_songs_set = cat_a_songs_set | cat_b_songs_set uncategorized_songs_set = all_songs_set - all_categorized_songs_set # Remove songs from uncategorized that have been categorized already print("Removing newly categorized songs from the uncategorized playlist named", secret.UNCATEGORIZED) uncategorized_playlist_songs_set = get_trackids_set(uncategorized_playlist) already_categorized_songs_set = all_categorized_songs_set & uncategorized_playlist_songs_set already_categorized_songs_ids = [song['id'] for song in uncategorized_playlist['tracks'] if song['trackId'] in already_categorized_songs_set] api.remove_entries_from_playlist(already_categorized_songs_ids) print("Removed", len(already_categorized_songs_ids), "songs from the uncategorized playlist named", secret.UNCATEGORIZED) # Add songs that are not categorized, to uncategorized # First, don't re-add songs that are still uncategorized print("Adding uncategorized songs to playlist named", secret.UNCATEGORIZED) newly_uncategorized_songs_set = uncategorized_songs_set - uncategorized_playlist_songs_set api.add_songs_to_playlist(uncategorized_playlist['id'], list(newly_uncategorized_songs_set)) print("Success! Added", len(newly_uncategorized_songs_set), "songs to playlist named", secret.UNCATEGORIZED) api.logout() print("Logged out")
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()
return s1 in s2 or s2 in s1 similar = {} print("starting now") for i in range(len(songs)): if not songs[i] in used: for j in range(i + 1, len(songs)): if not songs[j] in used: if isSimilar(songs[i], songs[j]): used.append(songs[j]) if songs[i]["title"] not in similar: similar[songs[i]["title"]] = [songs[i]] similar[songs[i]["title"]].append(songs[j]) for sim in similar: print("---" + sim + "---") delete = True while delete: ss = similar[sim] for i in range(len(ss)): print(str(i) + " " + ss[i]["title"] + " by " + ss[i]["artist"]) which = int(input("which one to delete? (if none then type n+1)")) if which >= len(ss): delete = False else: print( "deleted" + str(client.remove_entries_from_playlist(ss[which]["entryId"]))) ss.pop(which)
rfcTitle = data[['artist','title','energy','tempo','danceability','artist_discovery','speechiness','year','duration','trackType','acousticness','liveness','loudness','time_signature','valence','id','albumArtRef','storeId']] rfcTitle = rfcTitle.dropna(subset = filter(lambda x: x != "albumArtRef", rfcTitle.columns)) rfc = rfcTitle[['energy','tempo','danceability','artist_discovery','speechiness','year','trackType','acousticness','liveness','loudness','time_signature','valence']] km = pickle.load(open("/home/drew/tempo_scripts/tempo_model.p", "rb" )) klbls = km.labels_ rfcTitle['label'] = klbls results = [] for index, value in enumerate(rfcTitle.values): results.append({'artist': value[0], 'title': value[1], 'energy': value[2], 'tempo': value[3], 'danceability': value[4], 'artist_discovery': value[5], 'speechiness': value[6], 'year': value[7], 'duration': value[8], 'trackType': value[9], 'acousticness': value[10], 'liveness': value[11], 'loudness': value[12], 'time_signature': value[13], 'valence': value[14], 'cluster': value[18], 'id': value[15], 'albumArtRef': value[16], 'storeId': value[17]}) #playlists = api.get_all_playlists() #print json.dumps(playlists, indent=4, separators=(',', ': ')) plsongs = api.get_all_user_playlist_contents() #print json.dumps(plsongs, indent=4, separators=(',', ': ')) data = pd.read_csv("/home/drew/gpmusic_fixed.csv") ret = {'results': []} for i,v in enumerate(plsongs[0]['tracks']): for i2,v2 in enumerate(results): #print v2['storeId'], "==", plsongs[i]['track']['storeId'] if v2['id'] == v['trackId']: ret['results'].append(v2) break api.remove_entries_from_playlist("1c5aa722-db07-3801-8966-54b6cef43513") print json.dumps(plsongs, indent=4, separators=(',', ': ')) print json.dumps(ret, indent=4, separators=(',', ': '))