def authenticate(self, USER_DATA_FILENAME): self.G_username = raw_input("Google Play Account Email: ") self.G_password = getpass.getpass("Google Play Account Pass: "******"PHONE": self.GOOGLE_DEVICE_ID = device["id"] if self.GOOGLE_DEVICE_ID[:2] == '0x': self.GOOGLE_DEVICE_ID = self.GOOGLE_DEVICE_ID[2:] break self.S_username = raw_input("Soundcloud Account Username: "******"Soundcloud Account Password: "******"Soundcloud Client ID: ") self.SOUNDCLOUD_CLIENT_SECRET_ID = raw_input("Soundcloud Secret Client ID: ") File = open(USER_DATA_FILENAME, 'w+') File.write(self.encode(self.enc_key, self.G_username) + '\n') File.write(self.encode(self.enc_key, self.G_password) + '\n') File.write(self.encode(self.enc_key, self.S_username) + '\n') File.write(self.encode(self.enc_key, self.S_password) + '\n') File.write(self.GOOGLE_DEVICE_ID + '\n') File.write(self.SOUNDCLOUD_CLIENT_ID + '\n') File.write(self.SOUNDCLOUD_CLIENT_SECRET_ID + '\n') File.close()
class Player: def __init__(self, library_manager): pygame.init() pygame.mixer.init() self.library_manager = library_manager self.webapi = Webclient() try: self.webapi.login(setting.GUSER, setting.GPASS) except: sys.stderr.write('Problem with authentication on Google server\n') def play(self, songId): f = open('tostream.mp3', 'w') song = self.webapi.get_stream_audio(songId) f.write(song) f.close() #songFile = StringIO.StringIO(song) pygame.mixer.music.load('tostream.mp3') pygame.mixer.music.play() print('streaming audio: ' + songId) while pygame.mixer.music.get_busy(): pygame.time.Clock().tick(10)
def start(self): """ Start the sync """ api = Webclient() apim = Mobileclient() apim.login(self.email, self.password) try: api.login(self.email, self.password) xml_file = open('self.xml_file', 'r').read() print "Parsing songs from iTunes XML file..." itunes_song_list = self.__get_itunes_song_list(xml_file) print "iTunes XML file parsing complete" print "Retrieving songs from Google Music..." gmusic_song_list = self.__get_gmusic_song_list(apim) print "Google Music song retrieval complete" print "Computing the intersection of the song lists..." song_list = self.__get_intersection(gmusic_songs=gmusic_song_list, itunes_songs=itunes_song_list, only_no_rating=self.only_no_rating) print "Song list intersection computed" print "Syncing song ratings..." self.__sync_song_ratings(api, song_list) print "Song ratings sync complete!" except CallFailure: print "Error: Couldn't log in to Google Music!" except IOError: print "Error: iTunes XML file not found"
def getDeviceId(verbose=False): cred_path = os.path.join(os.path.expanduser('~'), '.gmusicfs') if not os.path.isfile(cred_path): raise NoCredentialException( 'No username/password was specified. No config file could ' 'be found either. Try creating %s and specifying your ' 'username/password there. Make sure to chmod 600.' % cred_path) if not oct(os.stat(cred_path)[os.path.stat.ST_MODE]).endswith('00'): raise NoCredentialException( 'Config file is not protected. Please run: ' 'chmod 600 %s' % cred_path) config = configparser.ConfigParser() config.read(cred_path) username = config.get('credentials', 'username') password = config.get('credentials', 'password') if not username or not password: raise NoCredentialException( 'No username/password could be read from config file' ': %s' % cred_path) api = GoogleMusicWebAPI(debug_logging=verbose) log.info('Logging in...') api.login(username, password) log.info('Login successful.') for device in api.get_registered_devices(): if not device['name']: device['name'] = 'NoName' if device['id'][1] == 'x': print('%s : %s' % (device['name'], device['id']))
def getDeviceId(verbose=False): cred_path = os.path.join(os.path.expanduser('~'), '.gmusicfs') if not os.path.isfile(cred_path): raise NoCredentialException( 'No username/password was specified. No config file could ' 'be found either. Try creating %s and specifying your ' 'username/password there. Make sure to chmod 600.' % cred_path) if not oct(os.stat(cred_path)[os.path.stat.ST_MODE]).endswith('00'): raise NoCredentialException( 'Config file is not protected. Please run: ' 'chmod 600 %s' % cred_path) config = ConfigParser.ConfigParser() config.read(cred_path) username = config.get('credentials','username') password = config.get('credentials','password') if not username or not password: raise NoCredentialException( 'No username/password could be read from config file' ': %s' % cred_path) api = GoogleMusicWebAPI(debug_logging=verbose) log.info('Logging in...') api.login(username, password) log.info('Login successful.') for device in api.get_registered_devices(): if not device['name']: device['name']='NoName' if device['id'][1]=='x': print '%s : %s' % (device['name'], device['id'])
def initthread(mwc, mc): library = mwc.library mwc.status_msg("Initializing..") wc = Webclient() wc.login(config.user, config.password) devices = wc.get_registered_devices() mwc.status_msg("Retrieving usable device ID..") for dev in devices: if dev["type"] == "PHONE": # strip 0x if present config.devid = dev["id"][2:] if dev["id"].startswith("0x") else dev["id"] print("Found a usable device id: " + config.devid) break else: md = Gtk.MessageDialog(parent=mwc.ui, buttons=Gtk.ButtonsType.OK, message_type=Gtk.MessageType.ERROR, message_format="Could not find a usable device id. Please run the Google Play Music app at least once on your phone.") GLib.idle_add(modal_dialog_func, md) mc.login(config.user, config.password) player = Player(mc, config.devid) mwc.setplayer(player) def getalbumart(structure): if "albumArtRef" in structure: a = structure["albumArtRef"] for entry in a: if "url" in entry: return entry["url"] return None mwc.status_msg("Retrieving library..") songs = mc.get_all_songs() for song in songs: track = Track(song["id"], song["title"], song["artist"], song["album"], song["trackNumber"] if "trackNumber" in song else 0) track.albumarturl = getalbumart(song) library.add_track(track) mwc.status_msg("Retrieving playlists..") playlists = mc.get_all_user_playlist_contents() for x in playlists: tracks = [] for t in x["tracks"]: if t["trackId"].startswith("T"): # all access track trackEntry = t["track"] track = Track(t["trackId"], trackEntry["title"], trackEntry["artist"], trackEntry["album"], trackEntry["trackNumber"]) track.albumarturl = getalbumart(trackEntry) tracks.append(track) else: libtrack = library.find_track(t["trackId"]) if libtrack is not None: tracks.append(libtrack) library.add_list(Playlist(x["name"], tracks)) mwc.status_msg("Idle")
class User: def __init__(self, cshUsername, cshHomeDirectory): self.cshlibrary = [] self.cshUsername = cshUsername self.cshHomeDirectory = cshHomeDirectory def playLogin(self, username, password): self.api = Webclient() self.api.login(username, password) self.playlibrary = self.api.get_all_songs()
class GoogleMusic(object): def __init__(self): self.webclient = Webclient() self.mobileclient = Mobileclient() def is_authenticated(self): if not self.webclient.is_authenticated(): if self.mobileclient.is_authenticated(): return True return False def login(self, username, password): if not self.is_authenticated(): try: self.mobileclient.login(username, password, Mobileclient.FROM_MAC_ADDRESS) self.webclient.login(username, password) except Exception as e: raise Exception('Couldn\'t log into Google Music: ' + e.message) def search(self, query, kind): if self.is_authenticated(): results = self.mobileclient.search(query)[kind + '_hits'] return results def get_track(self, store_id): return self.mobileclient.get_track_info(store_id) def save_stream(self, track, destination): if self.is_authenticated(): with open(destination, 'w+b') as stream_file: url = self.mobileclient.get_stream_url(track.get('storeId')) stream_file.truncate(0) stream_file.seek(0, 2) audio = self.webclient.session._rsession.get(url).content stream_file.write(audio) tag = easyid3.EasyID3() tag['title'] = track.get('title').__str__() tag['artist'] = track.get('artist').__str__() tag['album'] = track.get('album').__str__() tag['date'] = track.get('year').__str__() tag['discnumber'] = track.get('discNumber').__str__() tag['tracknumber'] = track.get('trackNumber').__str__() tag['performer'] = track.get('albumArtist').__str__() tag.save(destination) tag = mp3.MP3(destination) tag.tags.add( id3.APIC(3, 'image/jpeg', 3, 'Front cover', urllib.urlopen(track.get('albumArtRef')[0].get('url')).read()) ) tag.save()
class UrlGetter: def __init__(self, sck_path, user, passwd): pygame.init() pygame.mixer.init() self.sck_path = sck_path self.webapi = Webclient() self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) # Look if socket has been created try: os.remove(self.sck_path) except OSError: pass # GMusic login try: self.webapi.login(user, passwd) except: sys.stderr.write('Problem with authentication on Google server\n') self.init_socket() def init_socket(self): self.socket.bind(self.sck_path) self.socket.listen(3) while 1: conn, addr = self.socket.accept() self.manage_connection(conn) def manage_connection(self, conn): data = conn.recv(50) if data: try: stream_url = self.webapi.get_stream_urls(data) except exceptions.CallFailure: conn.close() return conn.send(stream_url[0]) print('url_getter.py: Ottenuta URL -> ' + stream_url[0]) conn.close()
def login_to_google_music(user): api = Webclient() apiMobile = Mobileclient() attempts = 0 while attempts < 3: if user == None: user = raw_input("Google username or email: ") # Try to read the password from a file # If file doesn't exist, ask for password # This is useful for 2-step authentication only # Don't store your regular password in plain text! try: pw_file = open("pass.txt") password = pw_file.readline() print "Reading password from pass.txt." except IOError: password = getpass() print "\nLogging in..." if apiMobile.login(user,password) and api.login(user, password): return api, apiMobile else: print "Login failed." # Set the username to none so it is prompted to be re-entered on the next loop iteration user = None attempts += 1 print str(attempts) + " failed login attempts. Giving up." exit(0)
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 gmObject: def __init__(self): self.mc = Mobileclient() self.wc = Webclient() self.mm = Musicmanager() def login(self, username, password): error.e = 0 if not self.mc.login(username, password): gmtPrintV("gmObject.login: Wrong username or password (or no internet connection)") error.e = error.LOGIN_FAILED return if not self.wc.login(username, password): gmtPrintV("gmObject.login: Wrong username or password (or no internet connection)") error.e = error.LOGIN_FAILED return if not self.mm.login(config.cred_path): gmtPrintV("gmObject.login: Wrong credentials (or no internet connection)") error.e = error.LOGIN_FAILED return def logout(self): error.e = 0 try: self.mc.logout() self.wc.logout() self.mm.logout() except: gmtPrintV("gmObject.logout: Logout failed") error.e = error.LOGOUT_FAILED
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 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 setup_web_api(): global web_api web_api = Webclient() web_logged_in = web_api.login(username, password) if not web_logged_in: print "Failed to log in to the web API, ensure your details are correct and try again." sys.exit(0)
def writeAlbumArt(): #TODO: https://github.com/simon-weber/gmusicapi/issues/352 # see branch: https://github.com/simon-weber/gmusicapi/issues/242 wc = Webclient() wc.__init__() #wc.oauth_login(Mobileclient.FROM_MAC_ADDRESS) if wc.login(uname, password): print "webclient login successful" else: print "LOGIN FAILED for Webclient"
def initDevice(self): device_id = self.settings.getSetting('device_id') if not device_id: self.main.log('Trying to fetch the device_id') webclient = Webclient(debug_logging=False,validate=False) self.checkCredentials() username = self.settings.getSetting('username') password = self.settings.getSetting('password') webclient.login(username, password) if webclient.is_authenticated(): devices = webclient.get_registered_devices() for device in devices: if device["type"] == "PHONE": device_id = str(device["id"]) break if device_id.lower().startswith('0x'): device_id = device_id[2:] self.settings.setSetting('device_id',device_id) self.main.log('device_id: '+device_id)
def get_deviceid(self, username, password): logger.warning(u'No mobile device ID configured. ' u'Trying to detect one.') webapi = Webclient(validate=False) webapi.login(username, password) devices = webapi.get_registered_devices() deviceid = None for device in devices: if device['type'] == 'PHONE' and device['id'][0:2] == u'0x': # Omit the '0x' prefix deviceid = device['id'][2:] break webapi.logout() if deviceid is None: logger.error(u'No valid mobile device ID found. ' u'Playing songs will not work.') else: logger.info(u'Using mobile device ID %s', deviceid) return deviceid
def initDevice(self): device_id = self.settings.getSetting('device_id') if not device_id: self.main.log('Trying to fetch the device_id') webclient = Webclient(debug_logging=False, validate=False) self.checkCredentials() username = self.settings.getSetting('username') password = self.settings.getSetting('password') webclient.login(username, password) if webclient.is_authenticated(): devices = webclient.get_registered_devices() for device in devices: if device["type"] == "PHONE": device_id = str(device["id"]) break if device_id.lower().startswith('0x'): device_id = device_id[2:] self.settings.setSetting('device_id', device_id) self.main.log('device_id: ' + device_id)
def _get_client(clienttype, user): global CLIENTS try: return CLIENTS[clienttype][user] except KeyError: client = Webclient() if clienttype == 'webclient' else Mobileclient() LOGGER.debug("Logging in %s for %s", clienttype, user.name) success = client.login(user.username, user.password) if not success: raise Exception("Failed to log in as {} to webclient".format(user)) CLIENTS[clienttype][user] = client return client
def ask_for_credentials(): """Make an instance of the api and attempts to login with it. Return the authenticated api. """ # We're not going to upload anything, so the webclient is what we want. api = Webclient() logged_in = False attempts = 0 while not logged_in and attempts < 3: email = raw_input("Email: ") password = getpass() logged_in = api.login(email, password) attempts += 1 return api
def main(): parser = argparse.ArgumentParser( description='List all devices registered for Google Play Music') parser.add_argument('username', help='Your Google Play Music username') parser.add_argument('password', help='Your very secret password') args = parser.parse_args() api = Webclient(validate=False) if not api.login(args.username, args.password): print "Could not login to Google Play Music. Incorrect username or password." return for device in api.get_registered_devices(): print '%s | %s | %s | %s' % (device['name'], device.get('manufacturer'), device['model'], device['id']) api.logout()
def main(): parser = argparse.ArgumentParser(description = 'List all devices registered for Google Play Music') parser.add_argument('username', help = 'Your Google Play Music username') parser.add_argument('password', help = 'Your very secret password') args = parser.parse_args() api = Webclient(validate = False) if not api.login(args.username, args.password): print "Could not login to Google Play Music. Incorrect username or password." return for device in api.get_registered_devices(): print '%s | %s | %s | %s' % (device['name'], device.get('manufacturer'), device['model'], device['id']) api.logout()
from gmusicapi import Webclient import json api = Webclient() api.login('*****@*****.**', 'biffyclyro') # => True library = api.get_all_songs() print json.dumps(library)
import sys from gmusicapi import Webclient if __name__ == "__main__": if sys.argv[1] == "1": wc = Webclient() success = wc.login(sys.argv[2], sys.argv[3]) if success == True: devices = wc.get_registered_devices() valid = [ device['id'][2:] + " (" + device['model'] + ")" for device in devices if device['type'] == 'PHONE' ] deviceid = valid[0].split(' ', 1)[0] print(deviceid) if sys.argv[1] == "2": print("Spotify is not yet supported.")
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 MusicLibrary(object): 'Read information about your Google Music library' def __init__(self, username=None, password=None, true_file_size=False): self.__artists = {} # 'artist name' -> {'album name' : Album(), ...} self.__albums = [] # [Album(), ...] self.__login(username, password) self.__aggregate_albums() self.true_file_size = true_file_size def __login(self, username=None, password=None): # If credentials are not specified, get them from $HOME/.gmusicfs if not username or not password: cred_path = os.path.join(os.path.expanduser('~'), '.gmusicfs') if not os.path.isfile(cred_path): raise NoCredentialException( 'No username/password was specified. No config file could ' 'be found either. Try creating %s and specifying your ' 'username/password there. Make sure to chmod 600.' % cred_path) if not oct(os.stat(cred_path)[os.path.stat.ST_MODE]).endswith('00'): raise NoCredentialException( 'Config file is not protected. Please run: ' 'chmod 600 %s' % cred_path) config = ConfigParser.ConfigParser() config.read(cred_path) username = config.get('credentials','username') password = config.get('credentials','password') if not username or not password: raise NoCredentialException( 'No username/password could be read from config file' ': %s' % cred_path) self.api = GoogleMusicAPI() log.info('Logging in...') self.api.login(username, password) log.info('Login successful.') def __aggregate_albums(self): 'Get all the tracks in the library, parse into artist and album dicts' all_artist_albums = {} # 'Artist|||Album' -> Album() log.info('Gathering track information...') tracks = self.api.get_all_songs() for track in tracks: # Prefer the album artist over the track artist if there is one: artist = track['albumArtistNorm'] if artist.strip() == '': artist = track['artistNorm'] # Get the Album object if it already exists: key = '%s|||%s' % (formatNames(artist), formatNames(track['albumNorm'])) album = all_artist_albums.get(key, None) if not album: # New Album if artist == '': artist = 'unknown' album = all_artist_albums[key] = Album( self, formatNames(track['albumNorm'])) self.__albums.append(album) artist_albums = self.__artists.get(artist, None) if artist_albums: artist_albums[formatNames(album.normtitle)] = album else: self.__artists[artist] = {album.normtitle: album} artist_albums = self.__artists[artist] album.add_track(track) log.debug('%d tracks loaded.' % len(tracks)) log.debug('%d artists loaded.' % len(self.__artists)) log.debug('%d albums loaded.' % len(self.__albums)) def get_artists(self): return self.__artists def get_albums(self): return self.__albums def get_artist_albums(self, artist): log.debug(artist) return self.__artists[artist]
class MusicLibrary(object): 'Read information about your Google Music library' def __init__(self, username=None, password=None, true_file_size=False, scan=True, verbose=0): self.verbose = False if verbose > 1: self.verbose = True self.__login_and_setup(username, password) if scan: self.rescan() self.true_file_size = true_file_size def rescan(self): self.__artists = {} # 'artist name' -> {'album name' : Album(), ...} self.__albums = [] # [Album(), ...] self.__aggregate_albums() def __login_and_setup(self, username=None, password=None): # If credentials are not specified, get them from $HOME/.gmusicfs if not username or not password: cred_path = os.path.join(os.path.expanduser('~'), '.gmusicfs') if not os.path.isfile(cred_path): raise NoCredentialException( 'No username/password was specified. No config file could ' 'be found either. Try creating %s and specifying your ' 'username/password there. Make sure to chmod 600.' % cred_path) if not oct(os.stat(cred_path)[os.path.stat.ST_MODE]).endswith('00'): raise NoCredentialException( 'Config file is not protected. Please run: ' 'chmod 600 %s' % cred_path) self.config = ConfigParser.ConfigParser() self.config.read(cred_path) username = self.config.get('credentials','username') password = self.config.get('credentials','password') if not username or not password: raise NoCredentialException( 'No username/password could be read from config file' ': %s' % cred_path) self.api = GoogleMusicAPI(debug_logging=self.verbose) log.info('Logging in...') self.api.login(username, password) log.info('Login successful.') def __aggregate_albums(self): 'Get all the tracks in the library, parse into artist and album dicts' all_artist_albums = {} # 'Artist|||Album' -> Album() log.info('Gathering track information...') tracks = self.api.get_all_songs() for track in tracks: # Prefer the album artist over the track artist if there is one: artist = track['albumArtistNorm'] if artist.strip() == '': artist = track['artistNorm'] # Get the Album object if it already exists: key = '%s|||%s' % (formatNames(artist), formatNames(track['albumNorm'])) album = all_artist_albums.get(key, None) if not album: # New Album if artist == '': artist = 'unknown' album = all_artist_albums[key] = Album( self, formatNames(track['albumNorm'])) self.__albums.append(album) artist_albums = self.__artists.get(artist, None) if artist_albums: artist_albums[formatNames(album.normtitle)] = album else: self.__artists[artist] = {album.normtitle: album} artist_albums = self.__artists[artist] album.add_track(track) log.debug('%d tracks loaded.' % len(tracks)) log.debug('%d artists loaded.' % len(self.__artists)) log.debug('%d albums loaded.' % len(self.__albums)) def get_artists(self): return self.__artists def get_albums(self): return self.__albums def get_artist_albums(self, artist): log.debug(artist) return self.__artists[artist] def cleanup(self): pass
class GoogleMusicLogin(): def __init__(self): self.main = sys.modules["__main__"] self.xbmcgui = self.main.xbmcgui self.xbmc = self.main.xbmc self.settings = self.main.settings #self.gmusicapi = gmusicapi self.initDevice() if self.getDevice(): self.gmusicapi = Mobileclient(debug_logging=True, validate=False) else: self.gmusicapi = Webclient(debug_logging=True, validate=False) def checkCookie(self): # Remove cookie data if it is older then 14 days if self.settings.getSetting('cookie-date') != None and len( self.settings.getSetting('cookie-date')) > 0: if (datetime.now() - datetime( *time.strptime(self.settings.getSetting('cookie-date'), '%Y-%m-%d %H:%M:%S.%f')[0:6])).days >= 14: self.clearCookie() def checkCredentials(self): if not self.settings.getSetting('username'): self.settings.openSettings() def getApi(self): return self.gmusicapi def getDevice(self): return self.settings.getSetting('device_id') def initDevice(self): device_id = self.settings.getSetting('device_id') if not device_id: self.main.log('Trying to fetch the device_id') webclient = Webclient(debug_logging=False, validate=False) self.checkCredentials() username = self.settings.getSetting('username') password = self.settings.getSetting('password') webclient.login(username, password) if webclient.is_authenticated(): devices = webclient.get_registered_devices() for device in devices: if device["type"] == "PHONE": device_id = str(device["id"]) break if device_id.lower().startswith('0x'): device_id = device_id[2:] self.settings.setSetting('device_id', device_id) self.main.log('device_id: ' + device_id) def clearCookie(self): self.settings.setSetting('logged_in', "") self.settings.setSetting('authtoken', "") self.settings.setSetting('cookie-xt', "") self.settings.setSetting('cookie-sjsaid', "") self.settings.setSetting('device_id', "") def login(self, nocache=False): # Continue with normal procedure if nocache or not self.settings.getSetting('logged_in'): #if not self.gmusicapi.session.is_authenticated: self.main.log('Logging in') username = self.settings.getSetting('username') password = self.settings.getSetting('password') try: self.gmusicapi.login(username, password) except Exception as e: self.main.log(repr(e)) if not self.gmusicapi.is_authenticated(): self.main.log("Login failed") self.settings.setSetting('logged_in', "") self.language = self.settings.getLocalizedString dialog = self.xbmcgui.Dialog() dialog.ok(self.language(30101), self.language(30102)) else: self.main.log("Login succeeded") if not nocache: self.settings.setSetting('logged_in', "1") self.settings.setSetting('authtoken', self.gmusicapi.session._authtoken) self.settings.setSetting( 'cookie-xt', self.gmusicapi.session._rsession.cookies['xt']) self.settings.setSetting( 'cookie-sjsaid', self.gmusicapi.session._rsession.cookies['sjsaid']) self.settings.setSetting('cookie-date', str(datetime.now())) else: self.main.log("Loading auth from cache") self.gmusicapi.session._authtoken = self.settings.getSetting( 'authtoken') self.gmusicapi.session._rsession.cookies[ 'xt'] = self.settings.getSetting('cookie-xt') self.gmusicapi.session._rsession.cookies[ 'sjsaid'] = self.settings.getSetting('cookie-sjsaid') self.gmusicapi.session.is_authenticated = True
class GMusic(object): def __init__(self): self.mob_client = Mobileclient() self.web_client = Webclient() self.logfile = None self.logfile_open = False # logged_in is True if login was successful logged_in = self.mob_client.login(MY_GMAIL, MY_PASSWORD, Mobileclient.FROM_MAC_ADDRESS) if logged_in: print("GoogleMusic MobileClient Logged In") else: raise Exception("Couldn't log in, exiting...") logged_in = self.web_client.login(MY_GMAIL, MY_PASSWORD) if logged_in: print("GoogleMusic WebClient Logged In") else: raise Exception("Couldn't log in, exiting...") def build_play_list_dummy(self): library = self.mob_client.get_all_songs() tracks = [track for track in library if track['artist'] == 'Adhesive Wombat' and "night shade" in track['title'].lower()] # for track in sweet_tracks: # print(track) playlist_id = self.mob_client.create_playlist('Test playlist') for track in tracks: self.mob_client.add_songs_to_playlist(playlist_id, track['id']) return playlist_id def _setlogfile(self, logfile): if self.logfile_open: self._print_and_log("logfile {} already opened! Not opening again!") else: self.logfile = logfile with open(self.logfile, "w") as logfile: logfile.write("LOGSTART: {}, script: {}\n".format(asctime(localtime()), __file__)) self.logfile_open = True def _print_and_log(self, msg): if self.logfile: with open(self.logfile, "a") as logfile: logfile.write(msg+"\n") print msg def find_duplicate_songs(self, outfile=None): duplicates = [] if outfile: if path.exists(path.dirname(outfile)): self._setlogfile(outfile) else: raise IOError("Output filename given: {} is in an none-existing dir".format(outfile)) library = self.mob_client.get_all_songs() tracks = [track for track in library] while tracks: track = tracks[0] dup_list = [] dup_idx_list = [] for idx, track_i in enumerate(tracks): if track['artist'].lower() == track_i['artist'].lower() and\ track['album'].lower() == track_i['album'].lower() and\ track['discNumber'] == track_i['discNumber'] and\ track['trackNumber'] == track_i['trackNumber'] and\ track['title'].lower() == track_i['title'].lower(): dup_idx_list.append(idx) dup_list.append(track_i) # Remove them: for index in sorted(dup_idx_list, reverse=True): del tracks[index] if len(dup_list) > 1: duplicates.append(dup_list) for idx, dup_list in enumerate(duplicates): self._print_and_log("{}: '{}' was found {} times!".format(idx+1, dup_list[0]['title'].encode("utf-8"), len(dup_list))) self._print_and_log("Found a total of {} duplicate songs!".format(len(duplicates))) # Display important stuff for idx, track_list in enumerate(duplicates): self._print_and_log("{}: BAND: {}, NAME: '{}'".format(idx+1, track_list[0]['artist'], track_list[0]['title'].encode("utf-8"))) for el in track_list[0]: for track in track_list: if el not in track: track[el] = "NO VALUE" if track[el] != track_list[0][el] and el not in ['id', 'url', 'recentTimestamp', 'storeId', 'nid', 'clientId']: # unicode? try: r_val = track_list[0][el].encode("utf-8") except: r_val = track_list[0][el] # unicode? try: l_val = track[el].encode("utf-8") except: l_val = track[el] self._print_and_log("track_id {}: {}='{}'".format(track_list[0]['id'], el, r_val)) self._print_and_log("track_id {}: {}='{}'".format(track['id'], el, l_val)) # raw_input("Press any key to continue...") return duplicates def delete_duplicates(self, duplicates): self._print_and_log("Cleaning duplicates [removing oldest of each duplicant]:") old_song_ids = [] for idx, dup_list in enumerate(duplicates): self._print_and_log("{}: BAND: {}, NAME: '{}'".format(idx+1, dup_list[0]['artist'], dup_list[0]['title'].encode("utf-8"))) track_timstamp = None oldest_id = None for el in dup_list: if track_timstamp is None and oldest_id is None: track_timstamp = el["timestamp"] oldest_id = el["id"] elif el["timestamp"] < track_timstamp: track_timstamp = el["timestamp"] oldest_id = el["id"] # finished with dup_list - log oldest id: self._print_and_log("Will delete {}, track_id: {}".format(el["title"], el["id"])) old_song_ids.append(oldest_id) self.mob_client.delete_songs(old_song_ids) self._print_and_log("track_ids deleted:\n{}".format(old_song_ids))
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!')
def get_webc(): client = Webclient(validate=False) client.login(email, password) return client
class GoogleMusic(object): def __init__(self): self.webclient = Webclient() self.mobileclient = Mobileclient() def is_authenticated(self): if self.webclient.is_authenticated(): if self.mobileclient.is_authenticated(): return True return False def login(self, username, password): if not self.is_authenticated(): try: self.mobileclient.login(username, password) self.webclient.login(username, password) except: raise Exception('Couldn\'t log into Google Music') def search(self, query, kind): if self.is_authenticated(): results = self.mobileclient.search_all_access(query)[kind + '_hits'] return results def get_track(self, store_id): return self.mobileclient.get_track_info(store_id) def save_stream(self, track, destination): if self.is_authenticated(): with open(destination, 'w+b') as stream_file: urls = self.webclient.get_stream_urls(track.get('storeId')) if len(urls) == 1: stream_file.write( self.webclient.session._rsession.get(urls[0]).content) range_pairs = [[int(s) for s in val.split('-')] for url in urls for key, val in parse_qsl(urlparse(url)[4]) if key == 'range'] for url, (start, end) in zip(urls, range_pairs): stream_file.truncate(start) stream_file.seek(0, 2) audio = self.webclient.session._rsession.get(url).content stream_file.write(audio) tag = easyid3.EasyID3() tag['title'] = track.get('title').__str__() tag['artist'] = track.get('artist').__str__() tag['album'] = track.get('album').__str__() tag['date'] = track.get('year').__str__() tag['discnumber'] = track.get('discNumber').__str__() tag['tracknumber'] = track.get('trackNumber').__str__() tag['performer'] = track.get('albumArtist').__str__() tag.save(destination) tag = mp3.MP3(destination) tag.tags.add( id3.APIC( 3, 'image/jpeg', 3, 'Front cover', urllib.urlopen( track.get('albumArtRef')[0].get('url')).read())) tag.save()
device_id = '' if email == '': email = raw_input("Email: ") if password == '': password = raw_input("Password: "******"Logging in..." logged_in = web_client.login(email, password) logged_in = mobile_client.login(email, password) # logged_in is True if login was successful if logged_in == True: print "Successfully logged in" if device_id == '': devices = web_client.get_registered_devices() valid = [device['id'][2:] + " (" + device['model'] + ")" for device in devices if device['type'] == 'PHONE'] print valid id_index = int(raw_input("Device ID: ")) device_id = valid[id_index].split(' ', 1)[0] while True: song_name = raw_input("Song title: ")
class GoogleMusicLogin(): def __init__(self): self.main = sys.modules["__main__"] self.xbmcgui = self.main.xbmcgui self.xbmc = self.main.xbmc self.settings = self.main.settings #self.gmusicapi = gmusicapi self.initDevice() if self.getDevice(): self.gmusicapi = Mobileclient(debug_logging=True,validate=False) else: self.gmusicapi = Webclient(debug_logging=True,validate=False) def checkCookie(self): # Remove cookie data if it is older then 14 days if self.settings.getSetting('cookie-date') != None and len(self.settings.getSetting('cookie-date')) > 0: if (datetime.now() - datetime(*time.strptime(self.settings.getSetting('cookie-date'), '%Y-%m-%d %H:%M:%S.%f')[0:6])).days >= 14: self.clearCookie() def checkCredentials(self): if not self.settings.getSetting('username'): self.settings.openSettings() def getApi(self): return self.gmusicapi def getDevice(self): return self.settings.getSetting('device_id') def initDevice(self): device_id = self.settings.getSetting('device_id') if not device_id: self.main.log('Trying to fetch the device_id') webclient = Webclient(debug_logging=False,validate=False) self.checkCredentials() username = self.settings.getSetting('username') password = self.settings.getSetting('password') webclient.login(username, password) if webclient.is_authenticated(): devices = webclient.get_registered_devices() for device in devices: if device["type"] == "PHONE": device_id = str(device["id"]) break if device_id.lower().startswith('0x'): device_id = device_id[2:] self.settings.setSetting('device_id',device_id) self.main.log('device_id: '+device_id) def clearCookie(self): self.settings.setSetting('logged_in', "") self.settings.setSetting('authtoken', "") self.settings.setSetting('cookie-xt', "") self.settings.setSetting('cookie-sjsaid', "") self.settings.setSetting('device_id', "") def login(self,nocache=False): # Continue with normal procedure if nocache or not self.settings.getSetting('logged_in'): #if not self.gmusicapi.session.is_authenticated: self.main.log('Logging in') username = self.settings.getSetting('username') password = self.settings.getSetting('password') try: self.gmusicapi.login(username, password) except Exception as e: self.main.log(repr(e)) if not self.gmusicapi.is_authenticated(): self.main.log("Login failed") self.settings.setSetting('logged_in', "") self.language = self.settings.getLocalizedString dialog = self.xbmcgui.Dialog() dialog.ok(self.language(30101), self.language(30102)) else: self.main.log("Login succeeded") if not nocache: self.settings.setSetting('logged_in', "1") self.settings.setSetting('authtoken', self.gmusicapi.session._authtoken) self.settings.setSetting('cookie-xt', self.gmusicapi.session._rsession.cookies['xt']) self.settings.setSetting('cookie-sjsaid', self.gmusicapi.session._rsession.cookies['sjsaid']) self.settings.setSetting('cookie-date', str(datetime.now())) else: self.main.log("Loading auth from cache") self.gmusicapi.session._authtoken = self.settings.getSetting('authtoken') self.gmusicapi.session._rsession.cookies['xt'] = self.settings.getSetting('cookie-xt') self.gmusicapi.session._rsession.cookies['sjsaid'] = self.settings.getSetting('cookie-sjsaid') self.gmusicapi.session.is_authenticated = True
ALBUM = raw_input("Name of Album to fix in GPM:\n") ALBUM_DIR = raw_input( "Folder path containing the songs with the correct artwork embedded:\n") BACKED_UP_FOLDER_ALBUM = False BACKED_UP_FOLDER = False VERBOSE = True api = Mobileclient() webapi = Webclient() clear = lambda: os.system('cls') if VERBOSE: print "Logging in...\n" api_logged_in = api.login( USERNAME, PASSWORD, ANDROID_ID) if ANDROID_ID else api.login( USERNAME, PASSWORD, Mobileclient.FROM_MAC_ADDRESS) web_logged_in = webapi.login(USERNAME, PASSWORD) if not api_logged_in and not web_logged_in: raise ('Both Mobile and Web logins failed!') elif api_logged_in and not web_logged_in: raise ('Web login failed!') elif web_logged_in and not api_logged_in: raise ('Mobile login failed!') elif api_logged_in and web_logged_in: if VERBOSE: print "Logged in!\n" ### THROWING AWAY YOUR PASSWORD! ### USERNAME = '' PASSWORD = '' ANDROID_ID = ''
from django.core.cache import cache from django.http import HttpResponseRedirect, HttpResponse from django.core.urlresolvers import reverse from django.shortcuts import render_to_response from django.template import RequestContext from django.utils import simplejson from play_pi.models import * from play_pi.settings import GPLAY_USER, GPLAY_PASS, SITE_ROOT import logging logger = logging.getLogger('play_pi') api = Webclient() api.login(GPLAY_USER, GPLAY_PASS) client = mpd.MPDClient() client.connect("localhost", 6600) def home(request): if GPLAY_USER == "" or GPLAY_PASS == "": return render_to_response('error.html', context_instance=RequestContext(request)) artists = Artist.objects.all().order_by('name') return render_to_response('index.html', { 'list': artists, 'view': 'artist' }, context_instance=RequestContext(request))
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('\\', '/'))
def get_registered_devices(login, password): websession = Webclient() websession.login(login, password) return websession.get_registered_devices()
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 GMusic(object): def __init__(self): self.webclient = Webclient(debug_logging=False) self.mobileclient = Mobileclient(debug_logging=False) self.email = None self.password = None self.mc_authenticated = False self.wc_authenticated = False self.authenticated = False self.device = None self.all_songs = list() self.playlists = list() ########################################################################### # Name: authenticate() # # Description: Attempts to authenticate class Mobileclient and Webclient # # instances. # # Inputs: login credentials: email, password # # Outputs: returns True if both Mobileclient and Webclient auth is True # ########################################################################### def authenticate(self, email=None, password=None): if email: self.email = email if password: self.password = password try: Log("Authenticating mobileclient...") self.mc_authenticated = self.mobileclient.login( self.email, self.password) except AlreadyLoggedIn: self.mc_authenticated = True try: Log("Authenticating webclient...") self.wc_authenticated = self.webclient.login( self.email, self.password) except AlreadyLoggedIn: self.wc_authenticated = True self.authenticated = self.mc_authenticated and self.wc_authenticated return self.authenticated ########################################################################### # Name: get_all_songs() # # Description: Returns a list of all songs # # Inputs: None # # Outputs: A list of all the songs a user owns. # ########################################################################### def get_all_songs(self): try: self.all_songs = self.mobileclient.get_all_songs() except NotLoggedIn: if self.authenticate(): self.all_songs = self.mobileclient.get_all_songs() else: Log("LOGIN FAILURE") return return self.all_songs def get_all_playlists(self): try: self.playlists = self.mobileclient.get_all_playlist_ids() except NotLoggedIn: if self.authenticate(): self.playlists = self.mobileclient.get_all_playlist_ids() else: Log("LOGIN FAILURE") return return self.playlists def get_stream_url(self, song_id): try: stream_url = self.mobileclient.get_stream_url(song_id) except NotLoggedIn: if self.authenticate(): stream_url = self.mobileclient.get_stream_url(song_id) else: Log("LOGIN FAILURE") return return stream_url
class GMusic(object): def __init__(self): self.authenticated = False self.all_access = False self._device = None self._webclient = Webclient(debug_logging=False) self._mobileclient = Mobileclient(debug_logging=False) self._playlists = [] self._playlist_contents = [] self._all_songs = [] self._all_artists = {} self._all_albums = {} self._all_genres = {} self._stations = [] def _get_device_id(self): if self.authenticated: devices = self._webclient.get_registered_devices() for dev in devices: if dev['type'] == 'PHONE': self._device = dev['id'][2:] break def _set_all_access(self): settings = self._webclient._make_call(webclient.GetSettings, '') self.all_access = True if 'isSubscription' in settings['settings'] and settings['settings']['isSubscription'] == True else False def authenticate(self, email, password): try: mcauthenticated = self._mobileclient.login(email, password) except AlreadyLoggedIn: mcauthenticated = True try: wcauthenticated = self._webclient.login(email, password) except AlreadyLoggedIn: wcauthenticated = True self.authenticated = mcauthenticated and wcauthenticated self._get_device_id() self._set_all_access() return self.authenticated def get_all_songs(self, id=None): if len(self._all_songs) == 0: try: self._all_songs = self._mobileclient.get_all_songs() except NotLoggedIn: if self.authenticate(): self._all_songs = self._mobileclient.get_all_songs() else: return [] if id: return [x for x in self._all_songs if x['id'] == id][0] else: return self._all_songs def get_all_artists(self): if not self._all_artists: songs = self.get_all_songs() for song in songs: artist = song['artist'] thumb = None if artist not in self._all_artists: self._all_artists[artist] = [] track = {'title': song['title'], 'album': song['album'], 'artist': artist, 'durationMillis': song['durationMillis'], 'trackType': song['trackNumber'], 'id': song['id']} if 'albumArtRef' in song: track['albumArtRef'] = song['albumArtRef'] if 'artistArtRef' in song: thumb = song['artistArtRef'][0]['url'] if 'storeId' in song: track['storeId'] = song['storeId'] self._all_artists[artist].append({'track': track, 'thumb': thumb, 'id': song['id']}) return self._all_artists def get_all_albums(self): if not self._all_albums: songs = self.get_all_songs() for song in songs: album = song['album'] thumb = None if album not in self._all_albums: self._all_albums[album] = [] track = {'title': song['title'], 'album': album, 'artist': song['artist'], 'durationMillis': song['durationMillis'], 'trackType': song['trackNumber'], 'id': song['id']} if 'albumArtRef' in song: track['albumArtRef'] = song['albumArtRef'] thumb = song['albumArtRef'][0]['url'] if 'storeId' in song: track['storeId'] = song['storeId'] self._all_albums[album].append({'track': track, 'thumb': thumb, 'id': song['id']}) return self._all_albums def get_all_genres(self): if not self._all_genres: songs = self.get_all_songs() for song in songs: genre = song['genre'] if genre not in self._all_genres: self._all_genres[genre] = [] track = {'title': song['title'], 'album': song['album'], 'artist': song['artist'], 'durationMillis': song['durationMillis'], 'trackType': song['trackNumber'], 'id': song['id']} if 'albumArtRef' in song: track['albumArtRef'] = song['albumArtRef'] if 'storeId' in song: track['storeId'] = song['storeId'] self._all_genres[genre].append({'track': track, 'id': song['id']}) return self._all_genres def get_all_playlists(self): if len(self._playlists) == 0: try: self._playlists = self._mobileclient.get_all_playlists() except NotLoggedIn: if self.authenticate(): self._playlists = self._mobileclient.get_all_playlists() else: return [] return self._playlists def get_all_user_playlist_contents(self, id): tracks = [] if len(self._playlist_contents) == 0: try: self._playlist_contents = self._mobileclient.get_all_user_playlist_contents() except NotLoggedIn: if self.authenticate(): self._playlist_contents = self._mobileclient.get_all_user_playlist_contents() else: return [] for playlist in self._playlist_contents: if id == playlist['id']: tracks = playlist['tracks'] break return tracks def get_shared_playlist_contents(self, token): playlist = [] try: playlist = self._mobileclient.get_shared_playlist_contents(token) except NotLoggedIn: if self.authenticate(): playlist = self._mobileclient.get_shared_playlist_contents(token) else: return [] return playlist def get_all_stations(self): if len(self._stations) == 0: try: self._stations = self._mobileclient.get_all_stations() except NotLoggedIn: if self.authenticate(): self._stations = self._mobileclient.get_all_stations() else: return [] return self._stations def get_station_tracks(self, id, num_tracks=200): tracks = [] try: tracks = self._mobileclient.get_station_tracks(id, num_tracks) except NotLoggedIn: if self.authenticate(): tracks = self._mobileclient.get_station_tracks(id, num_tracks) else: return [] return tracks def get_genres(self): genres = [] try: genres = self._mobileclient.get_genres() except NotLoggedIn: if self.authenticate(): genres = self._mobileclient.get_genres() else: return [] return genres def create_station(self, name, id): station = None try: station = self._mobileclient.create_station(name=name, genre_id=id) except NotLoggedIn: if self.authenticate(): station = self._mobileclient.create_station(name=name, genre_id=id) else: return [] return station def search_all_access(self, query, max_results=50): results = None try: results = self._mobileclient.search_all_access(query, max_results) except NotLoggedIn: if self.authenticate(): results = self._mobileclient.search_all_access(query, max_results) else: return [] return results def get_artist_info(self, id, include_albums=True, max_top_tracks=5, max_rel_artist=5): results = None try: results = self._mobileclient.get_artist_info(id, include_albums=include_albums, max_top_tracks=max_top_tracks, max_rel_artist=max_rel_artist) except NotLoggedIn: if self.authenticate(): results = self._mobileclient.get_artist_info(id, include_albums=include_albums, max_top_tracks=max_top_tracks, max_rel_artist=max_rel_artist) else: return [] return results def get_album_info(self, id, include_tracks=True): results = None try: results = self._mobileclient.get_album_info(id, include_tracks=include_tracks) except NotLoggedIn: if self.authenticate(): results = self._mobileclient.get_album_info(id, include_tracks=include_tracks) else: return [] return results def get_stream_url(self, id): try: stream_url = self._mobileclient.get_stream_url(id, self._device) except NotLoggedIn: if self.authenticate(): stream_url = self._mobileclient.get_stream_url(id, self._device) else: return '' except CallFailure: raise CallFailure('Could not play song with id: ' + id, 'get_stream_url') return stream_url
def generate_data_file(): import time, os, stat, sys lifetime = 86401 try: lifetime = time.time() - os.stat('assets/api/songs_all.json')[ stat.ST_MTIME] except Exception, e: pass if lifetime < 86400: return from gmusicapi import Webclient import json webclient = Webclient() webclient.login(get_conf().account['user'], get_conf().account['password']) devices = webclient.get_registered_devices() print devices f = open('assets/api/songs_all.json', 'w') f.write( json.dumps(api.get_all_songs(), ensure_ascii=False).encode('utf-8')) f.close() api = Mobileclient() logged_in = api.login(get_conf().account['user'], get_conf().account['password']) app = Flask(__name__) app.debug = True
class GMusic(object): def __init__(self): self.authenticated = False self.all_access = False self.library_loaded = False self.all_songs = [] self.letters = {} self.artists = {} self.albums = {} self.genres = {} self.tracks_by_letter = {} self.tracks_by_artist = {} self.tracks_by_album = {} self.tracks_by_genre = {} self._device = None self._webclient = Webclient(debug_logging=False) self._mobileclient = Mobileclient(debug_logging=False) self._playlists = [] self._playlist_contents = [] self._stations = [] def _get_device_id(self): if self.authenticated: devices = self._webclient.get_registered_devices() for dev in devices: if dev['type'] == 'PHONE': self._device = dev['id'][2:] break elif dev['type'] == 'IOS': self._device = dev['id'] break def _set_all_access(self): settings = self._webclient._make_call(webclient.GetSettings, '') self.all_access = True if 'isSubscription' in settings[ 'settings'] and settings['settings'][ 'isSubscription'] == True else False def _set_all_songs(self): if len(self.all_songs) == 0: try: self.all_songs = self._mobileclient.get_all_songs() except NotLoggedIn: if self.authenticate(): self.all_songs = self._mobileclient.get_all_songs() else: return [] else: return self.all_songs def authenticate(self, email, password): try: mcauthenticated = self._mobileclient.login(email, password) except AlreadyLoggedIn: mcauthenticated = True try: wcauthenticated = self._webclient.login(email, password) except AlreadyLoggedIn: wcauthenticated = True self.authenticated = mcauthenticated and wcauthenticated self._set_all_access() self._get_device_id() return self.authenticated def load_data(self): self._set_all_songs() for song in self.all_songs: thumb = None letter = song['title'][0] artist = song['artist'] album = song['album'] genre = song['genre'] if 'genre' in song else '(None)' if letter not in self.tracks_by_letter: self.tracks_by_letter[letter] = [] self.letters[letter] = None if artist not in self.tracks_by_artist: self.tracks_by_artist[artist] = [] self.artists[artist] = None if album not in self.tracks_by_album: self.tracks_by_album[album] = [] self.albums[album] = None if genre not in self.tracks_by_genre: self.tracks_by_genre[genre] = [] self.genres[genre] = None track = {'artist': artist, 'album': album} if 'title' in song: track['title'] = song['title'] if 'album' in song: track['album'] = song['album'] if 'artist' in song: track['artist'] = song['artist'] if 'durationMillis' in song: track['durationMillis'] = song['durationMillis'] if 'id' in song: track['id'] = song['id'] if 'trackNumber' in song: track['trackType'] = song['trackNumber'] if 'storeId' in song: track['storeId'] = song['storeId'] if 'albumArtRef' in song: track['albumArtRef'] = song['albumArtRef'] thumb = song['albumArtRef'][0]['url'] self.letters[letter] = thumb self.artists[artist] = thumb self.albums[album] = thumb self.genres[genre] = thumb self.tracks_by_letter[letter].append({ 'track': track, 'thumb': thumb, 'id': song['id'] }) self.tracks_by_artist[artist].append({ 'track': track, 'thumb': thumb, 'id': song['id'] }) self.tracks_by_album[album].append({ 'track': track, 'thumb': thumb, 'id': song['id'] }) self.tracks_by_genre[genre].append({ 'track': track, 'thumb': thumb, 'id': song['id'] }) self.library_loaded = True def get_tracks_for_type(self, type, name): type = type.lower() if type == 'artists': return self.tracks_by_artist[name] elif type == 'albums': return self.tracks_by_album[name] elif type == 'genres': return self.tracks_by_genre[name] elif type == 'songs by letter': return self.tracks_by_letter[name] else: return {} def get_song(self, id): return [x for x in self.all_songs if x['id'] == id][0] def get_all_playlists(self): if len(self._playlists) == 0: try: self._playlists = self._mobileclient.get_all_playlists() except NotLoggedIn: if self.authenticate(): self._playlists = self._mobileclient.get_all_playlists() else: return [] return self._playlists def get_all_user_playlist_contents(self, id): tracks = [] if len(self._playlist_contents) == 0: try: self._playlist_contents = self._mobileclient.get_all_user_playlist_contents( ) except NotLoggedIn: if self.authenticate(): self._playlist_contents = self._mobileclient.get_all_user_playlist_contents( ) else: return [] for playlist in self._playlist_contents: if id == playlist['id']: tracks = playlist['tracks'] break return tracks def get_shared_playlist_contents(self, token): playlist = [] try: playlist = self._mobileclient.get_shared_playlist_contents(token) except NotLoggedIn: if self.authenticate(): playlist = self._mobileclient.get_shared_playlist_contents( token) else: return [] return playlist def get_all_stations(self): if len(self._stations) == 0: try: self._stations = self._mobileclient.get_all_stations() except NotLoggedIn: if self.authenticate(): self._stations = self._mobileclient.get_all_stations() else: return [] return self._stations def get_station_tracks(self, id, num_tracks=200): tracks = [] try: tracks = self._mobileclient.get_station_tracks(id, num_tracks) except NotLoggedIn: if self.authenticate(): tracks = self._mobileclient.get_station_tracks(id, num_tracks) else: return [] return tracks def get_genres(self): genres = [] try: genres = self._mobileclient.get_genres() except NotLoggedIn: if self.authenticate(): genres = self._mobileclient.get_genres() else: return [] return genres def create_station(self, name, id): station = None try: station = self._mobileclient.create_station(name=name, genre_id=id) except NotLoggedIn: if self.authenticate(): station = self._mobileclient.create_station(name=name, genre_id=id) else: return [] return station def search_all_access(self, query, max_results=50): results = None try: results = self._mobileclient.search_all_access(query, max_results) except NotLoggedIn: if self.authenticate(): results = self._mobileclient.search_all_access( query, max_results) else: return [] return results def get_artist_info(self, id, include_albums=True, max_top_tracks=5, max_rel_artist=5): results = None try: results = self._mobileclient.get_artist_info( id, include_albums=include_albums, max_top_tracks=max_top_tracks, max_rel_artist=max_rel_artist) except NotLoggedIn: if self.authenticate(): results = self._mobileclient.get_artist_info( id, include_albums=include_albums, max_top_tracks=max_top_tracks, max_rel_artist=max_rel_artist) else: return [] return results def get_album_info(self, id, include_tracks=True): results = None try: results = self._mobileclient.get_album_info( id, include_tracks=include_tracks) except NotLoggedIn: if self.authenticate(): results = self._mobileclient.get_album_info( id, include_tracks=include_tracks) else: return [] return results def add_aa_track(self, id): track = None try: track = self._mobileclient.add_aa_track(id) except NotLoggedIn: if self.authenticate(): track = self._mobileclient.add_aa_track(id) else: return None return track def add_songs_to_playlist(self, playlist_id, song_ids): tracks = None try: tracks = self._mobileclient.add_songs_to_playlist( playlist_id, song_ids) except NotLoggedIn: if self.authenticate(): tracks = self._mobileclient.add_songs_to_playlist( playlist_id, song_ids) else: return None return tracks def get_stream_url(self, id): try: stream_url = self._mobileclient.get_stream_url(id, self._device) except NotLoggedIn: if self.authenticate(): stream_url = self._mobileclient.get_stream_url( id, self._device) else: return '' except CallFailure: raise CallFailure('Could not play song with id: ' + id, 'get_stream_url') return stream_url
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 Pygmy( Gtk.Window ): #directories = [ #"/home/kevin/player/songs"# , # "/mnt/stuff/tunez" #] artist_dictionary = {} def __init__( self ): Gtk.Window.__init__( self, title = "pygmy" ) # set default window size self.set_default_size( 800, 400 ) # initialize gobject threads GObject.threads_init() # initialize glib threads # glib.threads_init() # initialize gstreamer Gst.init( None ) # need to switch from webclient eventually, because it's being deprecated # i don't think mobileclient works because of the android id thing self.api = Webclient() self.player = Gst.ElementFactory.make( "playbin", None ) #self.bus = self.player.get_bus() #self.bus.connect("message", self.on_message) self.playing = False self.artist_store = Gtk.ListStore( str ) self.artist_sorted = Gtk.TreeModelSort( model = self.artist_store ) self.album_store = Gtk.ListStore( str ) self.album_sorted = Gtk.TreeModelSort( model = self.album_store ) # full file path, track #, title, artist, album, year, time self.song_store = Gtk.ListStore( str, str, int, str, str, str, str, str ) self.song_sorted = Gtk.TreeModelSort( model = self.song_store ) # self.album_store.append(["test"]) self.build_login() def on_message( self, bus, message ): t = message.type print(message) if t == Gst.Message.EOS: self.player.set_state(Gst.State.NULL) self.playing = False elif t == Gst.Message.ERROR: self.player.set_state(Gst.State.NULL) err, debug = message.parse_error() #print "Error: %s" % err, debug self.playing = False def build_login( self ): self.login_box = Gtk.Grid() self.login_box.set_halign( Gtk.Align.CENTER ) self.login_box.set_valign( Gtk.Align.CENTER ) login_label = Gtk.Label( label = "Login to Google Play" ) self.entry_username = Gtk.Entry() self.entry_username.set_placeholder_text( "User" ) self.entry_password = Gtk.Entry() self.entry_password.set_visibility( False ) self.entry_password.set_placeholder_text( "Password" ) login_button = Gtk.Button( label = "Login" ) login_button.connect( "clicked", self.do_login ) self.login_box.add( login_label ) self.login_box.attach_next_to( self.entry_username, login_label, Gtk.PositionType.BOTTOM, 1, 1 ) self.login_box.attach_next_to( self.entry_password, self.entry_username, Gtk.PositionType.BOTTOM, 1, 1 ) self.login_box.attach_next_to( login_button, self.entry_password, Gtk.PositionType.BOTTOM, 1, 1 ) self.add( self.login_box ) def do_login( self, widget ): # add a loading bar up here if self.api.login( self.entry_username.get_text(), self.entry_password.get_text() ): self.login_box.destroy() self.build_ui() else: print( "Authentication with Google failed" ) def build_ui( self ): grid = Gtk.Grid() self.add( grid ) # toolbar stuff #fixed = Gtk.Fixed() # fixed.set_size_request( -1, 38 ) toolbar_parent = Gtk.VBox() toolbar = Gtk.HBox() toolbar_parent.pack_start( toolbar, True, True, 3 ) #fixed.add( toolbar ) # previous button self.button_previous = Gtk.Button() self.button_previous.set_image( self.get_image( icon = Gtk.STOCK_MEDIA_PREVIOUS ) ) #self.button_previous.connect("clicked", self.on_button_previous_clicked) toolbar.pack_start( self.button_previous, False, False, 1 ) # play/pause button self.button_play = Gtk.Button() self.button_play.set_image( self.get_image( icon = Gtk.STOCK_MEDIA_PLAY ) ) self.button_play.connect( "clicked", self.play_pause ) toolbar.pack_start( self.button_play, False, False, 1 ) # stop button self.button_stop = Gtk.Button() self.button_stop.set_sensitive( False ) self.button_stop.set_image( self.get_image( icon = Gtk.STOCK_MEDIA_STOP ) ) self.button_stop.connect( "clicked", self.do_stop ) toolbar.pack_start( self.button_stop, False, False, 1 ) # next button self.button_next = Gtk.Button() self.button_next.set_image( self.get_image( icon = Gtk.STOCK_MEDIA_NEXT ) ) #self.button_next.connect("clicked", self.on_button_play_clicked) toolbar.pack_start( self.button_next, False, False, 1 ) #box.pack_start(fixed, True, True, 0) # add the fixed button bar to the grid grid.add( toolbar_parent ) # browser stuff browser = Gtk.VPaned() #browser_paned = Gtk.VPaned() #browser.add(browser_paned) grid.attach_next_to( browser, toolbar_parent, Gtk.PositionType.BOTTOM, 1, 1 ) # create columns for artist/album filters columns = Gtk.HBox() columns.set_size_request( 0, 150 ) # define cell renderer cell_renderer = Gtk.CellRendererText() # add ellipsis with pango cell_renderer.props.ellipsize = Pango.EllipsizeMode.END # artist list artists_scroll = Gtk.ScrolledWindow( hexpand = True, vexpand = True ) self.artists = Gtk.TreeView( self.artist_sorted ) artist_column = Gtk.TreeViewColumn( "Artist", cell_renderer, text = 0 ) self.artists.append_column( artist_column ) self.artists.get_selection().set_mode( Gtk.SelectionMode.MULTIPLE ) self.artist_sorted.set_sort_column_id( 0, Gtk.SortType.ASCENDING ) artists_scroll.add( self.artists ) #album list albums_scroll = Gtk.ScrolledWindow( hexpand = True, vexpand = True ) self.albums = Gtk.TreeView( self.album_sorted ) album_column = Gtk.TreeViewColumn( "Album", cell_renderer, text = 0 ) self.albums.append_column( album_column ) self.albums.get_selection().set_mode( Gtk.SelectionMode.MULTIPLE ) self.album_sorted.set_sort_column_id( 0, Gtk.SortType.ASCENDING ) albums_scroll.add( self.albums ) # add items to the columns columns.pack_start( artists_scroll, False, True, 0 ) columns.pack_start( albums_scroll, False, True, 0 ) #columns.add(self.artists) # song list songs_scroll = Gtk.ScrolledWindow( hexpand = True, vexpand = True ) self.songs = Gtk.TreeView( self.song_sorted ) self.songs.get_selection().set_mode( Gtk.SelectionMode.MULTIPLE ) self.songs.connect( "row-activated", self.on_song_activate ) songs_columns = { "playing": Gtk.TreeViewColumn( title = "", cell_renderer = cell_renderer, text = 0 ), "track": Gtk.TreeViewColumn( title = "#", cell_renderer = cell_renderer, text = 2 ), "title": Gtk.TreeViewColumn( title = "Title", cell_renderer = cell_renderer, text = 3 ), "artist": Gtk.TreeViewColumn( title = "Artist", cell_renderer = cell_renderer, text = 4 ), "album": Gtk.TreeViewColumn( title = "Album", cell_renderer = cell_renderer, text = 5 ), "year": Gtk.TreeViewColumn( title = "Year", cell_renderer = cell_renderer, text = 6 ), "time": Gtk.TreeViewColumn( title = "Time", cell_renderer = cell_renderer, text = 7 ) } # set all columns except playing as resizable for column in songs_columns: if column != "playing": songs_columns[column].set_sizing( Gtk.TreeViewColumnSizing.AUTOSIZE ) songs_columns[column].set_resizable( True ) songs_columns[column].set_reorderable( True ) # songs_columns[ "track" ].set_sort_column_id( 2 ) songs_columns[ "title" ].set_sort_column_id( 3 ) songs_columns[ "artist" ].set_sort_column_id( 4 ) songs_columns[ "album" ].set_sort_column_id( 5 ) songs_columns[ "year" ].set_sort_column_id( 6 ) songs_columns[ "time" ].set_sort_column_id( 7 ) self.song_sorted.set_sort_column_id( 4, Gtk.SortType.ASCENDING ) # self.song_sorted.set_sort_func( 2, self.compare, None ) # set title, artist, and album to expand #songs_columns[ "title" ].set_expand( True ) #songs_columns[ "artist" ].set_expand( True ) #songs_columns[ "album" ].set_expand( True ) # make sure we add them in the proper order self.songs.append_column( songs_columns[ "playing" ] ) self.songs.append_column( songs_columns[ "track" ] ) self.songs.append_column( songs_columns[ "title" ] ) self.songs.append_column( songs_columns[ "artist" ] ) self.songs.append_column( songs_columns[ "album" ] ) self.songs.append_column( songs_columns[ "year" ] ) self.songs.append_column( songs_columns[ "time" ] ) songs_scroll.add( self.songs ) # put together the browser window browser.add( columns ) browser.add( songs_scroll ) self.find_songs() # demo comparison for sorting treemodelsorted def compare( self, model, row1, row2, user_data ): sort_column, _ = model.get_sort_column_id() value1 = model.get_value(row1, sort_column) value2 = model.get_value(row2, sort_column) if value1 < value2: return -1 elif value1 == value2: return 0 else: return 1 def on_song_activate( self, widget, path, col ): # set the player state to null self.player.set_state( Gst.State.NULL ) # set the player uri to the activated song url # HEYYYYYY self.player.set_property( "uri", self.api.get_stream_urls( self.song_store[ path ][ 1 ] )[ 0 ] ) # set the player state to playing self.player.set_state( Gst.State.PLAYING ) def add_artist_to_store( self, artist ): if not artist in self.artist_dictionary: self.artist_dictionary[ artist ] = 0 self.artist_dictionary[ artist ] += 1 def add_song_to_store( self, track ): this_artist = track[ "artist" ] if not track[ "artist" ] == "" else "Unknown" self.add_artist_to_store( this_artist ) # format the time to minutes:seconds and remove the leading 0 time_string = re.sub( "^0", "", time.strftime( "%H:%M:%S", time.gmtime( int( track[ "durationMillis" ] ) / 1000 ) ) ) self.song_store.append([ "", track["id"], track["track"], track["title"] if not track[ "title" ] == "" else "Unknown", this_artist, track["album"] if not track[ "album" ] == "" else "Unknown", str( track[ "year" ] if not track[ "year" ] == 0 else "" ), str( time_string ) ]) def find_songs( self ): if not self.api.is_authenticated() == True: return self.library = self.api.get_all_songs() for track in self.library: self.add_song_to_store( track ) for artist in self.artist_dictionary: self.artist_store.append([ artist + " (" + str( self.artist_dictionary[ artist ] ) + ")" ]) self.artist_store.append([ "All " + str( len( self.artist_dictionary ) ) + " artists (" + str( len( self.song_store ) ) + ")" ]) self.show_all() # parse through every directory listed in the library #for directory in self.directories: # parse through all sub-folders looking for audio audio files #for r,d,f in os.walk( directory ): #for filename in f: # mime = mimetypes.guess_type( filename ) #mime = magic.from_file( os.path.join( r, filename ), mime = True ) #print(mime) # make sure mime-type is not None, otherwise the match will throw an error on some files #if not mime == None: #match = re.match( "^audio", mime ) #if match: # it's an audio file, add it to the library even though we're not sure gstreamer can play it #self.add_song_to_store( r, filename ) def get_image( self, icon ): image = Gtk.Image() image.set_from_stock( icon, Gtk.IconSize.BUTTON ) return image def play_pause( self, widget ): if self.playing == False: #filepath = self.entry.get_text() #if os.path.isfile(filepath): self.playing = True self.button_stop.set_sensitive( True ) image = self.get_image( Gtk.STOCK_MEDIA_PAUSE ) #self.player.set_property("uri", "file://" + filepath) #self.player.set_state(gst.STATE_PLAYING) else: self.playing = False image = self.get_image( Gtk.STOCK_MEDIA_PLAY ) self.button_play.set_image( image ) def do_stop( self, w ): self.button_play.set_image( self.get_image( Gtk.STOCK_MEDIA_PLAY ) ) #self.player.set_state(gst.STATE_NULL) self.playing = False self.button_stop.set_sensitive( False )
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"
from django.core.cache import cache from django.http import HttpResponseRedirect, HttpResponse from django.core.urlresolvers import reverse from django.shortcuts import render_to_response from django.template import RequestContext from django.utils import simplejson from play_pi.models import * from play_pi.settings import GPLAY_USER, GPLAY_PASS, SITE_ROOT import logging logger = logging.getLogger('play_pi') api = Webclient() api.login(GPLAY_USER,GPLAY_PASS) client = mpd.MPDClient() client.connect("localhost", 6600) def home(request): if GPLAY_USER == "" or GPLAY_PASS == "": return render_to_response('error.html', context_instance=RequestContext(request)) artists = Artist.objects.all().order_by('name') return render_to_response('index.html', {'list': artists, 'view':'artist'}, context_instance=RequestContext(request)) def artist(request,artist_id): artist = Artist.objects.get(id=artist_id) albums = Album.objects.filter(artist=artist)
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('\\', '/'))