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
def main(): api = Webclient() loggedIn = connect(api, raw_input('Username: '******'Password: ')) if not loggedIn: print "Authorization unsuccessful" sys.exit(0) else: print "Authorization successful!" print api.get_all_songs()[0]
def main(): api = Webclient() loggedIn = connect(api, raw_input('Username: '******'Password: ')) if not loggedIn: print "Authorization unsuccessful" sys.exit(0) else: print "Authorization successful!" print api.get_all_songs()[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."
def download_song(): print "Request : Download url" mm = Webclient() token = request.form['token'] songid = request.form['songid'] mm.setToken(token) songs = mm.get_all_songs(incremental=False) url = mm.get_stream_url(songid) return url
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 GMusicSession(object): def __init__(self): super(GMusicSession, self).__init__() logger.info('Mopidy uses Google Music') self.api = Webclient() def login(self, username, password): if self.api.is_authenticated(): self.api.logout() try: self.api.login(username, password) except CallFailure as error: logger.error(u'Failed to login as "%s": %s', username, error) return self.api.is_authenticated() def logout(self): if self.api.is_authenticated(): return self.api.logout() else: return True def get_all_songs(self): if self.api.is_authenticated(): return self.api.get_all_songs() else: return {} def get_stream_url(self, song_id): if self.api.is_authenticated(): try: return self.api.get_stream_urls(song_id)[0] except CallFailure as error: logger.error(u'Failed to lookup "%s": %s', song_id, error) def get_all_playlist_ids(self): if self.api.is_authenticated(): return self.api.get_all_playlist_ids() else: return {} def get_playlist_songs(self, playlist_id): if self.api.is_authenticated(): return self.api.get_playlist_songs(playlist_id) else: return {}
def list(): mm = Webclient() token = request.form['token'] mm.setToken(token) playlists = mm.get_all_playlist_ids() output = "[" songs = mm.get_all_songs(incremental=False) output += "{'title': 'Full library', 'songs' : " output += json.dumps(songs) output += "}," for (key,values) in playlists['user'].items(): for playlistid in values: output += "{ 'title':'"+key+"', 'songs' :" songs=mm.get_playlist_songs(playlistid) output += json.dumps(songs) output += "}," output += "]" return output
def list(): mm = Webclient() token = request.form['token'] mm.setToken(token) songs = mm.get_all_songs(incremental=False) return json.dumps(songs)
def handle(self, *args, **options): if GPLAY_PASS == "" or GPLAY_USER == "": self.stdout.write( 'Credentials not set up. Please edit settings.py') return api = Webclient() if not api.login(GPLAY_USER, GPLAY_PASS): self.stdout.write('Incorrect credentials, login failed') return self.stdout.write('Connected to Google Music, downloading data...') library = api.get_all_songs() self.stdout.write('Data downloaded!') self.stdout.write('Clearing DB...') cursor = connection.cursor() # This can take a long time using ORM commands on the Pi, so lets Truncate cursor.execute('DELETE FROM ' + Track._meta.db_table) cursor.execute('DELETE FROM ' + Album._meta.db_table) cursor.execute('DELETE FROM ' + Artist._meta.db_table) cursor.execute('DELETE FROM ' + Playlist._meta.db_table) cursor.execute('DELETE FROM ' + PlaylistConnection._meta.db_table) self.stdout.write('Parsing new data...') # Easier to keep track of who we've seen like this... artists = [] albums = [] for song in library: track = Track() if song['albumArtist'] == "": if song['artist'] == "": a = "Unknown Artist" else: a = song['artist'] else: a = song['albumArtist'] if a not in artists: artist = Artist() artist.name = a try: artist.art_url = song['artistImageBaseUrl'] except: artist.art_url = "" artist.save() artists.append(a) self.stdout.write('Added artist: ' + a) else: artist = Artist.objects.get(name=a) track.artist = artist if song['album'] not in albums: album = Album() album.name = song['album'] album.artist = artist try: album.art_url = song['albumArtUrl'] except: album.art_url = "" album.save() albums.append(song['album']) else: album = Album.objects.get(name=song['album']) track.album = album track.name = song['title'] track.stream_id = song['id'] try: track.track_no = song['track'] except: track.track_no = 0 track.save() self.stdout.write('All tracks saved!') self.stdout.write('Getting Playlists...') playlists = api.get_all_playlist_ids(auto=False, user=True) self.stdout.write('Saving playlists...') for name in playlists['user']: for pid in playlists['user'][name]: p = Playlist() p.pid = pid p.name = name p.save() for playlist in Playlist.objects.all(): self.stdout.write('Getting playlist contents for ' + playlist.name) songs = api.get_playlist_songs(playlist.pid) for song in songs: track = Track.objects.get(stream_id=song['id']) pc = PlaylistConnection() pc.playlist = playlist pc.track = track pc.save() self.stdout.write('Library saved!')
class MusicSync(object): def __init__(self, email=None, password=None): self.mm = Musicmanager() self.wc = Webclient() if not email: email = raw_input("Email: ") if not password: password = getpass() self.email = email self.password = password self.logged_in = self.auth() print "Fetching playlists from Google..." self.playlists = self.wc.get_all_playlist_ids(auto=False) print "Got %d playlists." % len(self.playlists['user']) print "Fetching songs from Google..." self.songs = self.wc.get_all_songs() print "Got %d songs." % len(self.songs) def auth(self): self.logged_in = self.wc.login(self.email, self.password) if not self.logged_in: print "Login failed..." exit() print "Logged in as %s" % self.email if not os.path.isfile(OAUTH_FILEPATH): print "First time login. Please follow the instructions below:" self.mm.perform_oauth() self.logged_in = self.mm.login() if not self.logged_in: print "OAuth failed... try deleting your %s file and trying again." % OAUTH_FILEPATH exit() print "Authenticated" def sync_playlist(self, filename, remove_missing=False): filename = self.get_platform_path(filename) os.chdir(os.path.dirname(filename)) title = os.path.splitext(os.path.basename(filename))[0] print "Syncing playlist: %s" % filename if title in self.playlists['user']: plid = self.playlists['user'][title][0] goog_songs = self.wc.get_playlist_songs(plid) print " %d songs already in Google Music playlist" % len(goog_songs) pc_songs = self.get_files_from_playlist(filename) print " %d songs in local playlist" % len(pc_songs) # Sanity check max 1000 songs per playlist if len(pc_songs) > MAX_SONGS_IN_PLAYLIST: print " Google music doesn't allow more than %d songs in a playlist..." % MAX_SONGS_IN_PLAYLIST print " Will only attempt to sync the first %d songs." % MAX_SONGS_IN_PLAYLIST del pc_songs[MAX_SONGS_IN_PLAYLIST:] existing_files = 0 added_files = 0 failed_files = 0 removed_files = 0 fatal_count = 0 # print "Google songs: %s" % goog_songs for fn in pc_songs: if self.file_already_in_list(fn, goog_songs): existing_files += 1 continue print " adding: %s" % os.path.basename(fn) online = self.find_song(fn) song_id = None if online: song_id = online['id'] print " already uploaded [%s]" % song_id else: attempts = 0 result = [] while not result and attempts < MAX_UPLOAD_ATTEMPTS_PER_FILE: print " uploading... (may take a while)" attempts += 1 try: result = self.mm.upload(fn) except (BadStatusLine, CannotSendRequest): # Bail out if we're getting too many disconnects if fatal_count >= MAX_CONNECTION_ERRORS_BEFORE_QUIT: print "Too many disconnections - quitting. Please try running the script again." exit() print "Connection Error -- Reattempting login" fatal_count += 1 self.wc.logout() self.mm.logout() result = [] time.sleep(STANDARD_SLEEP) except: result = [] time.sleep(STANDARD_SLEEP) try: if result[0]: song_id = result[0].itervalues().next() else: song_id = result[1].itervalues().next() print " upload complete [%s]" % song_id except: print " upload failed - skipping" if not song_id: failed_files += 1 continue added = self.wc.add_songs_to_playlist(plid, song_id) time.sleep(.3) # Don't spam the server too fast... print " done adding to playlist" added_files += 1 if remove_missing: for s in goog_songs: print " removing: %s" % s['title'] self.wc.remove_songs_from_playlist(plid, s.id) time.sleep(.3) # Don't spam the server too fast... removed_files += 1 print "%d songs unmodified" % existing_files print "%d songs added" % added_files print "%d songs failed" % failed_files print "%d songs removed" % removed_files print "Ended: %s" % filename else: print " playlist %s didn't exist - skipping" % filename def get_files_from_playlist(self, filename): files = [] f = codecs.open(filename, encoding='utf-8') for line in f: line = line.rstrip().replace(u'\ufeff',u'') if line == "" or line[0] == "#": continue path = os.path.abspath(self.get_platform_path(line)) if not os.path.exists(path): print " file not found: %s" % line continue files.append(path) f.close() return files def file_already_in_list(self, filename, goog_songs): tag = self.get_id3_tag(filename) i = 0 while i < len(goog_songs): # print "checking: %s" % tag # print "against: %s" % goog_songs[i] if self.tag_compare(goog_songs[i], tag): goog_songs.pop(i) return True i += 1 return False def get_id3_tag(self, filename): data = mutagen.File(filename, easy=True) r = {} if 'title' not in data: title = os.path.splitext(os.path.basename(filename))[0] print ' found song with no ID3 title, setting using filename:' print ' %s' % title print ' (please note - the id3 format used (v2.4) is invisible to windows)' data['title'] = [title] data.save() r['title'] = data['title'][0] r['track'] = int(data['tracknumber'][0].split('/')[0]) if 'tracknumber' in data else 0 # If there is no track, try and get a track number off the front of the file... since thats # what google seems to do... # Not sure how google expects it to be formatted, for now this is a best guess if r['track'] == 0: m = re.match("(\d+) ", os.path.basename(filename)) if m: r['track'] = int(m.group(0)) r['artist'] = data['artist'][0] if 'artist' in data else '' r['album'] = data['album'][0] if 'album' in data else '' return r def find_song(self, filename): tag = self.get_id3_tag(filename) # NOTE - diagnostic print here to check results if you're creating duplicates print " [%s][%s][%s][%s]" % (tag['title'], tag['artist'], tag['album'], tag['track']) for s in self.songs: if self.tag_compare(s, tag): print " %s matches %s" % (s['title'], tag['title']) return s print " No matches for %s" % tag['title'] return None def tag_compare(self, g_song, tag): # If a google result has no track, google doesn't return a field for it if 'track' not in g_song: g_song['track'] = 0 return g_song['title'].lower() == tag['title'].lower() and\ g_song['artist'].lower() == tag['artist'].lower() and\ g_song['album'].lower() == tag['album'].lower() and\ g_song['track'] == tag['track'] def delete_song(self, sid): self.wc.delete_songs(sid) print " deleted song by id [%s]" % sid def get_platform_path(self, full_path): # Try to avoid messing with the path if possible if os.sep == '/' and '\\' not in full_path: return full_path if os.sep == '\\' and '\\' in full_path: return full_path if '\\' not in full_path: return full_path return os.path.normpath(full_path.replace('\\', '/'))
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
from gmusicapi import Webclient import json api = Webclient() api.login('*****@*****.**', 'biffyclyro') # => True library = api.get_all_songs() print json.dumps(library)
class Music(Command): def __init__(self, credentials): self.keywords = ['music'] self.gmusic = Webclient() self.gmusic.login(credentials['u'], credentials['pass']) self.currentPlaylist = list() self.currentSong = dict() self.isPlaying = False self.playlistIndex = 0 self.updateSongs() self.player = PCM() def updateSongs(self): self.playlists = self.gmusic.get_all_playlist_ids()["user"] if len(self.currentPlaylist) == 0: self.currentPlaylist= self.gmusic.get_playlist_songs(self.playlists['Megalist'][0]) random.shuffle(self.currentPlaylist) if not self.currentSong: self.currentSong = self.currentPlaylist[self.playlistIndex] self.library = self.gmusic.get_all_songs() def play(self, cs = None): if cs == None: cs = self.currentPlaylist[self.playlistIndex] self.currentSong = cs self.isPlaying = True # self.player.write(self.gmusic.get_stream_audio(self.currentSong[u'id'])) print 'play' + self.currentSong['title'] def pause(self): self.isPlaying = False print 'pausing' def nextSong(self): self.playlistIndex += 1 if self.playlistIndex >= len(self.currentPlaylist): self.playlistIndex = 0 self.pause() else: self.play() def previousSong(self): self.playlistIndex -= 1 if self.playlistIndex < 0: self.playlistIndex = 0 self.play() def rickRoll(self): self.playlist = list() for song in self.library: if song['titleNorm'] == 'never gonna give you up': self.currentPlaylist = [song] self.playlistIndex = 0 self.play() def playSong(self, songname): for song in self.library: if songname in song['titleNorm']: self.play(cs = song) self.currentPlaylist = [song] # tempplaylist = self.gmusic.get_playlist_songs(self.playlists['Megalist'][0]) # random.shuffle(tempplaylist) # self.currentPlaylist += tempplaylist break def playAlbum(self, albumname): tempplaylist = list() for song in self.library: if albumname in song["albumNorm"] or albumname in song["album"]: tempplaylist += [song] if len(tempplaylist) > 0: self.currentPlaylist = sorted(tempplaylist, key=lambda k: k['track']) self.play() def playArtist(self, artistname): tempplaylist = list() for song in self.library: if artistname in song["artistNorm"] or artistname in song["artist"]: tempplaylist += [song] if len(templaylist) > 0: self.currentPlaylist = tempplaylist random.shuffle(self.currentPlaylist) self.playlistIndex = 0 self.play() def playPlaylist(self, playlistname): self.currentPlaylist = self.gmusic.get_playlist_songs(self.playlists[playlistname][0]) random.shuffle(self.currentPlaylist) self.playlistIndex = 0 self.play() def run(self, commandlist): if len(commandlist) == 0: if self.isPlaying == True: self.pause() else: self.play() print "music toggle" elif commandlist[0] == "play": if len(commandlist) == 1: if self.isPlaying == False: self.play() print "play music" elif commandlist [1] == "playlist": self.playPlaylist(" ".join(commandlist[2:])) elif commandlist [1] == "song": self.playSong(" ".join(commandlist[2:])) elif commandlist [1] == "artist": self.playArtist(" ".join(commandlist[2:])) elif commandlist[1] == "album": self.playAlbum(" ".join(commandlist[2:])) elif commandlist[0] == "pause": if self.isPlaying == True: self.pause() elif commandlist[0] == "next": self.nextSong() elif commandlist[0] == "previous": self.previousSong() else: print "m err"
def handle(self, *args, **options): if GPLAY_PASS == "" or GPLAY_USER == "": self.stdout.write('Credentials not set up. Please edit settings.py') return api = Webclient() if not api.login(GPLAY_USER,GPLAY_PASS): self.stdout.write('Incorrect credentials, login failed') return self.stdout.write('Connected to Google Music, downloading data...') library = api.get_all_songs() self.stdout.write('Data downloaded!') self.stdout.write('Clearing DB...') cursor = connection.cursor() # This can take a long time using ORM commands on the Pi, so lets Truncate cursor.execute('DELETE FROM ' + Track._meta.db_table) cursor.execute('DELETE FROM ' + Album._meta.db_table) cursor.execute('DELETE FROM ' + Artist._meta.db_table) cursor.execute('DELETE FROM ' + Playlist._meta.db_table) cursor.execute('DELETE FROM ' + PlaylistConnection._meta.db_table) self.stdout.write('Parsing new data...') # Easier to keep track of who we've seen like this... artists = [] albums = [] for song in library: track = Track() if song['albumArtist'] == "": if song['artist'] == "": a = "Unknown Artist" else: a = song['artist'] else: a = song['albumArtist'] if a not in artists: artist = Artist() artist.name = a try: artist.art_url = song['artistImageBaseUrl'] except: artist.art_url = "" artist.save() artists.append(a) self.stdout.write('Added artist: '+ a) else: artist = Artist.objects.get(name=a) track.artist = artist if song['album'] not in albums: album = Album() album.name = song['album'] album.artist = artist try: album.art_url = song['albumArtUrl'] except: album.art_url = "" album.save() albums.append(song['album']) else: album = Album.objects.get(name=song['album']) track.album = album track.name = song['title'] track.stream_id = song['id'] try: track.track_no = song['track'] except: track.track_no = 0 track.save() self.stdout.write('All tracks saved!') self.stdout.write('Getting Playlists...') playlists = api.get_all_playlist_ids(auto=False, user=True) self.stdout.write('Saving playlists...') for name in playlists['user']: for pid in playlists['user'][name]: p = Playlist() p.pid = pid p.name = name p.save() for playlist in Playlist.objects.all(): self.stdout.write('Getting playlist contents for ' + playlist.name) songs = api.get_playlist_songs(playlist.pid) for song in songs: track = Track.objects.get(stream_id=song['id']) pc = PlaylistConnection() pc.playlist = playlist pc.track = track pc.save() self.stdout.write('Library saved!')
class 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 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 GoogleMusic(RadiopieModule): def run(self): log.info("Google Music started") self._lcd.setFirst(" Google") self.__player = None self.__api = None self.__library = None self.loadConfiguration() self.googleMusicConnection() while not self._terminate.isSet(): if(self._ok.isSet()): self._ok.clear() self.playCurrentSong() if(self._left.isSet()): self._left.clear() self._terminate.set() time.sleep(1) self.setdown() def googleMusicConnection(self): log.info("Login as user " + self.__user + " ...") self._lcd.setLast(" Login..") self.__api = Webclient() self.__api.login(self.__user, self.__password) log.info("Loading Library") self._lcd.setLast(" Loading") self.__library = self.__api.get_all_songs() self._lcd.setLast(" Ready") def playCurrentSong(self): log.info("Playing a song") if(self.__player == None): self.setup() else: self.__player.set_state(gst.STATE_NULL) self.__currentsong = self.__library[random.randint(0,len(self.__library))] self._lcd.setLast(self.__currentsong["title"].encode("utf-8")) url = self.__api.get_stream_urls(self.__currentsong["id"]) self.__player.set_property("uri", url[0]) self.__player.set_state(gst.STATE_PLAYING) log.info("Playing song " + self.__currentsong["title"] + " ... ") def setup(self): self.__player = gst.element_factory_make("playbin2", "player") bus = self.__player.get_bus() bus.add_signal_watch() bus.connect("message", self.on_status) def loadConfiguration(self): log.info("Loading settings from json ...") json_data = open('defaults.json') data = json.load(json_data) self.__user = data["google-music-user"] self.__password = data["google-music-password"] def setdown(self): self.__player.set_state(gst.STATE_NULL) def on_status(self, bus, message): t = message.type if(t == gst.MESSAGE_EOS): log.info("Song end") self.playCurrentSong() if(t == pygst.MESSAGE_ERROR): err, debug = message.parse_error() log.error(err) log.debug(debug) self.__player.set_state(gst.STATE_NONE) @staticmethod def getName(): return "Google Music"