class GMusic(object): def __init__(self): self.webclient = Webclient(debug_logging=False) self.email = None self.password = None self.authenticated = False self.all_songs = list() self.playlists = list() def authenticate(self, email=None, password=None): if email: self.email = email if password: self.password = password try: Log("AUTHENTICATING!!!!111") self.authenticated = self.webclient.login(self.email, self.password) except AlreadyLoggedIn: self.authenticated = True return self.authenticated def get_all_songs(self): try: self.all_songs = self.webclient.get_all_songs() except NotLoggedIn: if self.authenticate(): self.all_songs = self.webclient.get_all_songs() else: Log("LOGIN FAILURE") return return self.all_songs def get_all_playlists(self): try: self.playlists = self.webclient.get_all_playlist_ids() except NotLoggedIn: if self.authenticate(): self.playlists = self.webclient.get_all_playlist_ids() else: Log("LOGIN FAILURE") return return self.playlists def get_stream_url(self, song_id): try: stream_url = self.webclient.get_stream_url(song_id) except NotLoggedIn: if self.authenticate(): stream_url = self.webclient.get_stream_url(song_id) else: Log("LOGIN FAILURE") return return stream_url
class gMusicClient(object): logged_in = False api = None playlists = dict() library = dict() def __init__(self, email, password): self.api = Webclient() logged_in = False attempts = 0 if len(password) is 0: password = getpass("Google password:"******"title"] if song["artist"] == "": song_artist = "Unknown Artist" else: song_artist = song["artist"] if song["album"] == "": song_album = "Unknown Album" else: song_album = song["album"] if not (song_artist in self.library): albums_dict = dict() self.library[song_artist] = albums_dict if not (song_album in self.library[song_artist]): song_list = list() self.library[song_artist][song_album] = song_list self.library[song_artist][song_album].append(song) plists = self.api.get_all_playlist_ids(auto=True, user=True) for u_playlist, u_playlist_id in plists["user"].iteritems(): self.playlists[u_playlist] = self.api.get_playlist_songs(u_playlist_id[0]) self.playlists["Thumbs Up"] = [song for song in songs if song['rating'] == 5] def getSongStream(self, song): return self.api.get_stream_urls(song["id"]) def getStreamAudio(self, song): return self.api.get_stream_audio(song["id"]) def thumbsUp(self, song): try: song["rating"] = 5 song_list = [song] self.api.change_song_metadata(song_list) print "Gave a Thumbs Up to {0} by {1} on Google Play.".format(song["title"].encode("utf-8"), song["artist"].encode("utf-8")) except: print "Error giving a Thumbs Up on Google Play."
class GMusicSession(object): def __init__(self): super(GMusicSession, self).__init__() logger.info('Mopidy uses Google Music') self.api = Webclient() def login(self, username, password): if self.api.is_authenticated(): self.api.logout() try: self.api.login(username, password) except CallFailure as error: logger.error(u'Failed to login as "%s": %s', username, error) return self.api.is_authenticated() def logout(self): if self.api.is_authenticated(): return self.api.logout() else: return True def get_all_songs(self): if self.api.is_authenticated(): return self.api.get_all_songs() else: return {} def get_stream_url(self, song_id): if self.api.is_authenticated(): try: return self.api.get_stream_urls(song_id)[0] except CallFailure as error: logger.error(u'Failed to lookup "%s": %s', song_id, error) def get_all_playlist_ids(self): if self.api.is_authenticated(): return self.api.get_all_playlist_ids() else: return {} def get_playlist_songs(self, playlist_id): if self.api.is_authenticated(): return self.api.get_playlist_songs(playlist_id) else: return {}
def list(): mm = Webclient() token = request.form['token'] mm.setToken(token) playlists = mm.get_all_playlist_ids() output = "[" songs = mm.get_all_songs(incremental=False) output += "{'title': 'Full library', 'songs' : " output += json.dumps(songs) output += "}," for (key,values) in playlists['user'].items(): for playlistid in values: output += "{ 'title':'"+key+"', 'songs' :" songs=mm.get_playlist_songs(playlistid) output += json.dumps(songs) output += "}," output += "]" return output
def main(): api = Webclient() login(api) playlists = api.get_all_playlist_ids().pop('user') indexed_playlist_names = index_playlists(playlists) curlist = choose_playlist(api, indexed_playlist_names, playlists)[0] songs = api.get_playlist_songs(curlist) print songs curpos = 0 cursongid = songs[curpos]['id'] cursongurl = api.get_stream_url(cursongid) print cursongurl #cursong = play(cursongurl) while 1: if cursong.poll() is not None: curpos += 1 cursongid = songs[curpos]['id'] cursong = play(get_stream_url(cursongid)) c = getch() if (c == 'q'): api.logout() break
def main(): api = Webclient() login(api) playlists = api.get_all_playlist_ids().pop('user') indexed_playlist_names = index_playlists(playlists) curlist = choose_playlist(api, indexed_playlist_names, playlists)[0] songs = api.get_playlist_songs(curlist) print songs curpos = 0; cursongid = songs[curpos]['id'] cursongurl = api.get_stream_url(cursongid) print cursongurl #cursong = play(cursongurl) while 1: if cursong.poll() is not None: curpos += 1 cursongid = songs[curpos]['id'] cursong = play(get_stream_url(cursongid)) c = getch() if (c == 'q'): api.logout() break
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.wc.get_all_playlist_ids(auto=False) print "Got %d playlists." % len(self.playlists["user"]) print "" def auth(self): self.logged_in = self.wc.login(self.email, self.password) self.logged_in = self.mc.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 add_rhapsody_playlist(self, filename, remove_missing=False): filename = self.get_platform_path(filename) os.chdir(os.path.dirname(filename)) # playlist_title = os.path.splitext(os.path.basename(filename))[0] print "Synching File: %s" % filename print "Parsing Songs from %s" % filename pc_songs = self.get_songs_from_file(filename) # print (pc_songs) print "%d songs in local file: %s" % (len(pc_songs), filename) # 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 song in pc_songs: playlist_title = song["playlist"] if playlist_title not in self.playlists["user"]: self.playlists["user"][playlist_title] = [self.mc.create_playlist(playlist_title)] time.sleep(0.7) print "Starting Playlist Sync with Google music..." for song in pc_songs: # print song plid = "" print "--------------------------------" print "" print "Playlist: %s" % song["playlist"] print "Artist: %s" % song["artist"] print "Song: %s" % song["title"] print "Album: %s" % song["album"] playlist_title = song["playlist"] plid = self.playlists["user"][playlist_title][0] goog_songs = self.wc.get_playlist_songs(plid) if self.song_already_in_list(song, goog_songs): existing_files += 1 print "Result: Song Already Added" continue print "Total %d songs in Google playlist: %s" % (len(goog_songs), playlist_title) print "%s - %s, didn't exist...Will try to add..." % (song["artist"], song["title"]) print "" print "--------------------------------" results = self.mc.search_all_access(song["title"], max_results=50) nid = self.filter_search_results(results, song) print "AA nId: %s " % nid if nid: song_id = self.mc.add_aa_track(nid) added = self.wc.add_songs_to_playlist(plid, song_id) print "Playlist UUid: %s" % plid print "Song ID: %s" % song_id time.sleep(0.3) # Don't spam the server too fast... print "Result: done adding to playlist" added_files += 1 continue else: query = "%s %s" % (song["artist"], song["title"].split(" ")[0]) print "Query %s" % query results = self.mc.search_all_access(query, max_results=50) nid = self.filter_search_results(results, song) if nid: song_id = self.mc.add_aa_track(nid) added = self.wc.add_songs_to_playlist(plid, song_id) print "Playlist UUid: %s" % plid print "Song ID: %s" % song_id time.sleep(0.3) # Don't spam the server too fast... print " -- done adding to playlist" added_files += 1 continue print "Result: NID Blank, Song not Found in All Access" 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_songs_from_file(self, filename): songs = [] f = codecs.open(filename, encoding="utf-8") for line in f: line = line.rstrip().replace(u"\ufeff", u"") if line == "" or line[0] == "#": continue la = line.split("\\") regex_filter = "[^A-Za-z0-9\,\-\.\ \(\)'\!\?\$\/ \& \:]" artist = re.sub(regex_filter, "", la[1]) playlist = re.sub(regex_filter, "", la[0]) album = re.sub(regex_filter, "", la[2]) title = re.sub(regex_filter, "", la[3]) # print "Filtered Strings:" # print "Artist: %s" % artist # print "Playlist: %s" % playlist # print "Song: %s" % title # print "Album: %s" % album dt = {"playlist": playlist, "artist": artist, "album": album, "title": title} # print (dt) songs.append(dt) f.close() return songs def get_songs_from_playlist(self, filename): songs = [] 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 songs.append(path) f.close() return songs def get_files_from_playlist(self, filename): files = [] 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 song_already_in_list(self, song, goog_songs): # tag = self.get_id3_tag(filename) i = 0 while i < len(goog_songs): # print goog_songs if self.tag_compare(goog_songs[i], song): goog_songs.pop(i) return True i += 1 return False def file_already_in_list(self, filename, goog_songs): tag = self.get_id3_tag(filename) i = 0 while i < len(goog_songs): if self.tag_compare(goog_songs[i], tag): 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, plid): tag = self.get_id3_tag(filename) print "Song Tag: %s " % tag print "Filename: %s" % filename ws_plids = [] ws_plids.append(plid) print (ws_plids) playlists = self.wc.get_all_playlist_ids() print (playlists) results = self.wc.get_playlist_songs(ws_plids) # NOTE - dianostic print here to check results if you're creating duplicates print results print "%s ][ %s ][ %s ][ %s" % (tag["title"], tag["artist"], tag["album"], tag["track"]) for r in results: if self.tag_compare(r, tag): # TODO: add rough time check to make sure its "close" return r return None def filter_search_results(self, results, song): # Try Exact Matching for g_song in results["song_hits"]: if self.tag_compare(g_song["track"], song): return g_song["track"]["nid"] elif self.song_compare(g_song["track"], song, "artist"): # try just the artist return g_song["track"]["nid"] elif self.song_compare(g_song["track"], song, "part-song"): # try part of song and artist return g_song["track"]["nid"] return None def song_compare(self, g_song, tag, type): if "track" not in g_song: g_song["track"] = 0 title_parts = tag["title"].split("(") # removing shit like (featuring wiz) tp = title_parts[0].split(" ") # First word maybe if "artist" in type: return g_song["artist"].lower() == tag["artist"].lower() if "part-song" in type: return g_song["title"].find(tp[0]) and g_song["artist"].lower() == tag["artist"].lower() return None def tag_compare(self, g_song, tag): if "track" not in g_song: g_song["track"] = 0 return ( g_song["title"].split(" ")[0].lower() == tag["title"].split(" ")[0].lower() and g_song["artist"].lower() == tag["artist"].lower() ) def delete_song(self, sid): self.wc.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() 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.wc.get_all_playlist_ids(auto=False) print "Got %d playlists." % len(self.playlists['user']) print "" def auth(self): 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, artist_title_array, playlist_title = -99): if playlist_title == -99: title = "GMusicSync Playlist %3d"%time.time() else: title = str(playlist_title) print "Synching playlist: %s" % title if title not in self.playlists['user']: print " didn't exist... creating..." self.playlists['user'][title] = [self.wc.create_playlist(title)] print "" 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 = artist_title_array print "%d songs in local playlist" % len(pc_songs) # 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): existing_files += 1 continue print "" try: print "Adding: %s - %s"%(fn[0],fn[1]) except: print "Incorrect format for %r, expecting ('artist','title')"%fn continue online = self.find_song(fn) song_id = None if online: song_id = online['id'] print " already uploaded [%s]" % song_id else: print " Sorry, can't find song." if not song_id: failed_files += 1 continue added = self.wc.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 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='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, artist_title, goog_songs): i = 0 while i < len(goog_songs): if self.song_compare(goog_songs[i], artist_title): goog_songs.pop(i) return True i += 1 return False def find_song(self, artist_title): try: artist = artist_title[0] title = artist_title[1] except: return None results = self.wc.search(title) print "\t",results[:2] for r in results['song_hits']: if self.song_compare(r, artist_title): return r return None def song_compare(self, g_song, artist_title): try: artist = artist_title[0] title = artist_title[1] except: return False # TODO: add fuzzy matching return g_song['title'].lower() == title.lower() and\ g_song['artist'].lower() == artist.lower() 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 Music(Command): def __init__(self, credentials): self.keywords = ['music'] self.gmusic = Webclient() self.gmusic.login(credentials['u'], credentials['pass']) self.currentPlaylist = list() self.currentSong = dict() self.isPlaying = False self.playlistIndex = 0 self.updateSongs() self.player = PCM() def updateSongs(self): self.playlists = self.gmusic.get_all_playlist_ids()["user"] if len(self.currentPlaylist) == 0: self.currentPlaylist= self.gmusic.get_playlist_songs(self.playlists['Megalist'][0]) random.shuffle(self.currentPlaylist) if not self.currentSong: self.currentSong = self.currentPlaylist[self.playlistIndex] self.library = self.gmusic.get_all_songs() def play(self, cs = None): if cs == None: cs = self.currentPlaylist[self.playlistIndex] self.currentSong = cs self.isPlaying = True # self.player.write(self.gmusic.get_stream_audio(self.currentSong[u'id'])) print 'play' + self.currentSong['title'] def pause(self): self.isPlaying = False print 'pausing' def nextSong(self): self.playlistIndex += 1 if self.playlistIndex >= len(self.currentPlaylist): self.playlistIndex = 0 self.pause() else: self.play() def previousSong(self): self.playlistIndex -= 1 if self.playlistIndex < 0: self.playlistIndex = 0 self.play() def rickRoll(self): self.playlist = list() for song in self.library: if song['titleNorm'] == 'never gonna give you up': self.currentPlaylist = [song] self.playlistIndex = 0 self.play() def playSong(self, songname): for song in self.library: if songname in song['titleNorm']: self.play(cs = song) self.currentPlaylist = [song] # tempplaylist = self.gmusic.get_playlist_songs(self.playlists['Megalist'][0]) # random.shuffle(tempplaylist) # self.currentPlaylist += tempplaylist break def playAlbum(self, albumname): tempplaylist = list() for song in self.library: if albumname in song["albumNorm"] or albumname in song["album"]: tempplaylist += [song] if len(tempplaylist) > 0: self.currentPlaylist = sorted(tempplaylist, key=lambda k: k['track']) self.play() def playArtist(self, artistname): tempplaylist = list() for song in self.library: if artistname in song["artistNorm"] or artistname in song["artist"]: tempplaylist += [song] if len(templaylist) > 0: self.currentPlaylist = tempplaylist random.shuffle(self.currentPlaylist) self.playlistIndex = 0 self.play() def playPlaylist(self, playlistname): self.currentPlaylist = self.gmusic.get_playlist_songs(self.playlists[playlistname][0]) random.shuffle(self.currentPlaylist) self.playlistIndex = 0 self.play() def run(self, commandlist): if len(commandlist) == 0: if self.isPlaying == True: self.pause() else: self.play() print "music toggle" elif commandlist[0] == "play": if len(commandlist) == 1: if self.isPlaying == False: self.play() print "play music" elif commandlist [1] == "playlist": self.playPlaylist(" ".join(commandlist[2:])) elif commandlist [1] == "song": self.playSong(" ".join(commandlist[2:])) elif commandlist [1] == "artist": self.playArtist(" ".join(commandlist[2:])) elif commandlist[1] == "album": self.playAlbum(" ".join(commandlist[2:])) elif commandlist[0] == "pause": if self.isPlaying == True: self.pause() elif commandlist[0] == "next": self.nextSong() elif commandlist[0] == "previous": self.previousSong() else: print "m err"
def handle(self, *args, **options): if GPLAY_PASS == "" or GPLAY_USER == "": self.stdout.write('Credentials not set up. Please edit settings.py') return api = Webclient() if not api.login(GPLAY_USER,GPLAY_PASS): self.stdout.write('Incorrect credentials, login failed') return self.stdout.write('Connected to Google Music, downloading data...') library = api.get_all_songs() self.stdout.write('Data downloaded!') self.stdout.write('Clearing DB...') cursor = connection.cursor() # This can take a long time using ORM commands on the Pi, so lets Truncate cursor.execute('DELETE FROM ' + Track._meta.db_table) cursor.execute('DELETE FROM ' + Album._meta.db_table) cursor.execute('DELETE FROM ' + Artist._meta.db_table) cursor.execute('DELETE FROM ' + Playlist._meta.db_table) cursor.execute('DELETE FROM ' + PlaylistConnection._meta.db_table) self.stdout.write('Parsing new data...') # Easier to keep track of who we've seen like this... artists = [] albums = [] for song in library: track = Track() if song['albumArtist'] == "": if song['artist'] == "": a = "Unknown Artist" else: a = song['artist'] else: a = song['albumArtist'] if a not in artists: artist = Artist() artist.name = a try: artist.art_url = song['artistImageBaseUrl'] except: artist.art_url = "" artist.save() artists.append(a) self.stdout.write('Added artist: '+ a) else: artist = Artist.objects.get(name=a) track.artist = artist if song['album'] not in albums: album = Album() album.name = song['album'] album.artist = artist try: album.art_url = song['albumArtUrl'] except: album.art_url = "" album.save() albums.append(song['album']) else: album = Album.objects.get(name=song['album']) track.album = album track.name = song['title'] track.stream_id = song['id'] try: track.track_no = song['track'] except: track.track_no = 0 track.save() self.stdout.write('All tracks saved!') self.stdout.write('Getting Playlists...') playlists = api.get_all_playlist_ids(auto=False, user=True) self.stdout.write('Saving playlists...') for name in playlists['user']: for pid in playlists['user'][name]: p = Playlist() p.pid = pid p.name = name p.save() for playlist in Playlist.objects.all(): self.stdout.write('Getting playlist contents for ' + playlist.name) songs = api.get_playlist_songs(playlist.pid) for song in songs: track = Track.objects.get(stream_id=song['id']) pc = PlaylistConnection() pc.playlist = playlist pc.track = track pc.save() self.stdout.write('Library saved!')
class MusicSync(object): def __init__(self, email=None, password=None): self.mm = Musicmanager() self.wc = Webclient() 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.wc.get_all_playlist_ids(auto=False) print "Got %d playlists." % len(self.playlists['user']) print "" def auth(self): 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, artist_title_array, playlist_title=-99): if playlist_title == -99: title = "GMusicSync Playlist %3d" % time.time() else: title = str(playlist_title) print "Synching playlist: %s" % title if title not in self.playlists['user']: print " didn't exist... creating..." self.playlists['user'][title] = [self.wc.create_playlist(title)] print "" 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 = artist_title_array print "%d songs in local playlist" % len(pc_songs) # 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): existing_files += 1 continue print "" try: print "Adding: %s - %s" % (fn[0], fn[1]) except: print "Incorrect format for %r, expecting ('artist','title')" % fn continue online = self.find_song(fn) song_id = None if online: song_id = online['id'] print " already uploaded [%s]" % song_id else: print " Sorry, can't find song." if not song_id: failed_files += 1 continue added = self.wc.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 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='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, artist_title, goog_songs): i = 0 while i < len(goog_songs): if self.song_compare(goog_songs[i], artist_title): goog_songs.pop(i) return True i += 1 return False def find_song(self, artist_title): try: artist = artist_title[0] title = artist_title[1] except: return None results = self.wc.search(title) print "\t", results[:2] for r in results['song_hits']: if self.song_compare(r, artist_title): return r return None def song_compare(self, g_song, artist_title): try: artist = artist_title[0] title = artist_title[1] except: return False # TODO: add fuzzy matching return g_song['title'].lower() == title.lower() and\ g_song['artist'].lower() == artist.lower() 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() 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.wc.get_all_playlist_ids(auto=False) print "Got %d playlists." % len(self.playlists['user']) print "Fetching songs from Google..." self.songs = self.wc.get_all_songs() print "Got %d songs." % len(self.songs) def auth(self): self.logged_in = self.wc.login(self.email, self.password) if not self.logged_in: print "Login failed..." exit() print "Logged in as %s" % self.email 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" 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 in self.playlists['user']: 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) # 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 # print "Google songs: %s" % goog_songs for fn in pc_songs: if self.file_already_in_list(fn, goog_songs): existing_files += 1 continue print " adding: %s" % os.path.basename(fn) 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 "Too many disconnections - quitting. Please try running the script again." exit() print "Connection Error -- Reattempting login" fatal_count += 1 self.wc.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" if not song_id: failed_files += 1 continue added = self.wc.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 s in goog_songs: print " removing: %s" % s['title'] self.wc.remove_songs_from_playlist(plid, s.id) time.sleep(.3) # Don't spam the server too fast... removed_files += 1 print "%d songs unmodified" % existing_files print "%d songs added" % added_files print "%d songs failed" % failed_files print "%d songs removed" % removed_files print "Ended: %s" % filename else: print " playlist %s didn't exist - skipping" % filename def get_files_from_playlist(self, filename): files = [] 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): tag = self.get_id3_tag(filename) i = 0 while i < len(goog_songs): # print "checking: %s" % tag # print "against: %s" % goog_songs[i] if self.tag_compare(goog_songs[i], tag): 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): tag = self.get_id3_tag(filename) # NOTE - diagnostic print here to check results if you're creating duplicates print " [%s][%s][%s][%s]" % (tag['title'], tag['artist'], tag['album'], tag['track']) for s in self.songs: if self.tag_compare(s, tag): print " %s matches %s" % (s['title'], tag['title']) return s print " No matches for %s" % tag['title'] 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 'track' not in g_song: g_song['track'] = 0 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.wc.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('\\', '/'))
from gmusicapi import Webclient import os import getpass api = Webclient() api.__init__() while (api.login(raw_input('Email: '), getpass.getpass()) == False): print 'Error, try again' i = 1 for playlist in api.get_all_playlist_ids()['user']: print str(i) + '. ' + playlist i += 1 while True: chosen_number = int(raw_input('Choose a playlist to export (enter the number): ')) if chosen_number < i and chosen_number >= 0: break else: print 'Error, try again' i = 1 for playlist in api.get_all_playlist_ids()['user']: if i == chosen_number: chosen_id = api.get_all_playlist_ids()['user'][playlist][0] chosen_name = playlist break else: i += 1
def handle(self, *args, **options): if GPLAY_PASS == "" or GPLAY_USER == "": self.stdout.write( 'Credentials not set up. Please edit settings.py') return api = Webclient() if not api.login(GPLAY_USER, GPLAY_PASS): self.stdout.write('Incorrect credentials, login failed') return self.stdout.write('Connected to Google Music, downloading data...') library = api.get_all_songs() self.stdout.write('Data downloaded!') self.stdout.write('Clearing DB...') cursor = connection.cursor() # This can take a long time using ORM commands on the Pi, so lets Truncate cursor.execute('DELETE FROM ' + Track._meta.db_table) cursor.execute('DELETE FROM ' + Album._meta.db_table) cursor.execute('DELETE FROM ' + Artist._meta.db_table) cursor.execute('DELETE FROM ' + Playlist._meta.db_table) cursor.execute('DELETE FROM ' + PlaylistConnection._meta.db_table) self.stdout.write('Parsing new data...') # Easier to keep track of who we've seen like this... artists = [] albums = [] for song in library: track = Track() if song['albumArtist'] == "": if song['artist'] == "": a = "Unknown Artist" else: a = song['artist'] else: a = song['albumArtist'] if a not in artists: artist = Artist() artist.name = a try: artist.art_url = song['artistImageBaseUrl'] except: artist.art_url = "" artist.save() artists.append(a) self.stdout.write('Added artist: ' + a) else: artist = Artist.objects.get(name=a) track.artist = artist if song['album'] not in albums: album = Album() album.name = song['album'] album.artist = artist try: album.art_url = song['albumArtUrl'] except: album.art_url = "" album.save() albums.append(song['album']) else: album = Album.objects.get(name=song['album']) track.album = album track.name = song['title'] track.stream_id = song['id'] try: track.track_no = song['track'] except: track.track_no = 0 track.save() self.stdout.write('All tracks saved!') self.stdout.write('Getting Playlists...') playlists = api.get_all_playlist_ids(auto=False, user=True) self.stdout.write('Saving playlists...') for name in playlists['user']: for pid in playlists['user'][name]: p = Playlist() p.pid = pid p.name = name p.save() for playlist in Playlist.objects.all(): self.stdout.write('Getting playlist contents for ' + playlist.name) songs = api.get_playlist_songs(playlist.pid) for song in songs: track = Track.objects.get(stream_id=song['id']) pc = PlaylistConnection() pc.playlist = playlist pc.track = track pc.save() self.stdout.write('Library saved!')
class MusicSync(object): def __init__(self, email=None, password=None): self.mm = Musicmanager() self.wc = Webclient() 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.wc.get_all_playlist_ids(auto=False) print "Got %d playlists." % len(self.playlists['user']) print "" def auth(self): 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=False): filename = self.get_platform_path(filename) os.chdir(os.path.dirname(filename)) title = os.path.splitext(os.path.basename(filename))[0] print "Synching 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 = 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) # 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): existing_files += 1 continue print "" print "Adding: %s" % os.path.basename(fn) 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.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" if not song_id: failed_files += 1 continue added = self.wc.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 s in goog_songs: print "" print "Removing: %s" % s['title'] 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='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): tag = self.get_id3_tag(filename) i = 0 while i < len(goog_songs): if self.tag_compare(goog_songs[i], tag): 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): tag = self.get_id3_tag(filename) results = self.wc.search(tag['title']) # NOTE - dianostic print here to check results if you're creating duplicates #print results['song_hits'] #print "%s ][ %s ][ %s ][ %s" % (tag['title'], tag['artist'], tag['album'], tag['track']) for r in results['song_hits']: if self.tag_compare(r, tag): # TODO: add rough time check to make sure its "close" return r 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 'track' not in g_song: g_song['track'] = 0 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.wc.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('\\', '/'))