class MyCdList: mm = None library = None def authenticatewithgoogle(self, option): self.mm = Musicmanager() self.mm.login() # currently named oauth_login for the Mobileclient if option == 0: self.library = self.mm.get_purchased_songs() elif option == 1: self.library = self.mm.get_uploaded_songs() def getallartist(self): donotaddthis = "The 100 Most Essential Pieces of Classical Music" artists = [] artistsset = set() [ artistsset.add(track['artist']) for track in self.library if track['album'] != donotaddthis ] artists = list(artistsset) artists.sort() return artists def getalbumsforartist(self, artist): albums = [] albumsset = set() [ albumsset.add(track['album']) for track in self.library if track['artist'] == artist ] albums = list(albumsset) albums.sort() return albums
def play_song_by_artist(song, artist): if Mobileclient.is_authenticated(gpm): mm = Musicmanager() mm.login('/home/pi/oauth.cred') if Musicmanager.is_authenticated(mm): song_dict = mm.get_purchased_songs() song_pattern = re.compile( r'(?:.)*\s?(' + re.escape(song) + r')\s?(?:.)*', re.IGNORECASE) artist_pattern = re.compile( r'(?:.)*\s?(' + re.escape(artist) + r')\s?(?:.)*', re.IGNORECASE) btn = OnButtonPress() btn.start() for song in song_dict: m = re.match(artist_pattern, song['artist']) print(m) if (re.match(song_pattern, song['title']) is not None and re.match(artist_pattern, song['artist']) is not None): print('Song found!') song_id = song['id'] (filename, audio) = mm.download_song(song_id) # get rid of non-ascii characters in file name filename = filename.encode('ascii', errors='ignore') # check if song is already downloaded # path will look something like: # /home/pi/Music/02 - Raindrop Prelude.mp3 # forces filename to be a string filename = filename.decode('ascii') path = song_location + filename try: if os.path.isfile(path): print('Song is already downloaded...') print(path) print('Playing song.') vlc_instance = vlc.Instance() p = vlc_instance.media_player_new() media = vlc_instance.media_new(path) p.set_media(media) events = p.event_manager() events.event_attach( vlc.EventType.MediaPlayerEndReached, SongFinished) p.play() p.audio_set_volume(58) while finish == 0: duration = p.get_time() / 1000 (m, s) = divmod(duration, 60) print('Current song is: ', path) print('Length:', '%02d:%02d' % (m, s)) time.sleep(5) p.stop() break else: with open(path, 'wb') as f: f.write(audio) print('Song has been added to: ' + path) print('Playing song.') vlc_instance = vlc.Instance() p = vlc_instance.media_player_new() media = vlc_instance.media_new(path) p.set_media(media) events = p.event_manager() events.event_attach( vlc.EventType.MediaPlayerEndReached, SongFinished) p.play() p.audio_set_volume(58) while finish == 0: duration = p.get_time() / 1000 m, s = divmod(duration, 60) print('Current song is: ', path) print('Length:', '%02d:%02d' % (m, s)) time.sleep(5) p.stop() break except (OSError, IOError): print('An error has occurred.') break else: print('Song not found yet.') else: print('Looks like you need to authenticate.') mm.perform_oauth('/home/pi/oauth.cred') print('Logging out.') Mobileclient.logout(gpm) mm.logout() else: print('Mobile client is not authenticated.') Mobileclient.logout(gpm)
#! /usr/bin/env python3 from gmusicapi import Musicmanager from os.path import expanduser, join mm = Musicmanager() if not mm.login(): print('Login failed: did you run oauth_login.py?') quit() # No point properly checking for duplicates when overwriting them # gives the same result. songs = {} for song in mm.get_purchased_songs(): songs[song['id']] = ' - '.join( [song['title'], song['artist'], song['album']] ) for song in mm.get_uploaded_songs(): songs[song['id']] = ' - '.join( [song['title'], song['artist'], song['album']] ) print('Downloading %d songs to ~/.local/share/gpymusic/songs. ' 'This might take a while...' % len(songs)) song_dir = join(expanduser('~'), '.local', 'share', 'gpymusic', 'songs') i = 1 for id in songs: print('%d/%d: %s' % (i, len(songs), songs[id])) dl_path = join(song_dir, '%s.mp3' % songs[id].replace('/', '---'))
class TheGoogs: DEFAULT_CREDS_DIR = "~/gmusic/.oauth" DEFAULT_MOBILE_DEVICE_ID = "342e914abacc484d" # Galaxy Tab DEFAULT_MANAGER_MAC_ADDRESS = "A2:C2:E2:CC:C7:37" # Made-up def __init__(self, creds_dir=DEFAULT_CREDS_DIR): self.creds_dir = os.path.expanduser(creds_dir) logger.info("Creating TheGoogs from creds at {}".format( self.creds_dir)) self.mobile_creds = os.path.join(self.creds_dir, "mobile.creds") self.manager_creds = os.path.join(self.creds_dir, "manager.creds") self.mobile = Mobileclient() self.manager = Musicmanager() logger.debug("Logging in") self.mobile.oauth_login(device_id=self.DEFAULT_MOBILE_DEVICE_ID, oauth_credentials=self.mobile_creds) self.manager.login(uploader_id=self.DEFAULT_MANAGER_MAC_ADDRESS, oauth_credentials=self.manager_creds) def get_libdata(self): logger.info("Fetching libdata ...") logger.info("... fetching registered devices") registered_devices = self.mobile.get_registered_devices() logger.info("... fetching all songs") library = self.mobile.get_all_songs() logger.info("... fetching playlist metadata") playlists = self.mobile.get_all_playlists() logger.info("... fetching playlist contents") playlist_contents = self.mobile.get_all_user_playlist_contents() logger.info("... fetching uploaded songs") uploaded_songs = self.manager.get_uploaded_songs() logger.info("... fetching purchased songs") purchased_songs = self.manager.get_purchased_songs() return Libdata(timestamp=datetime.utcnow(), registered_devices=registered_devices, all_songs=library, playlist_metadata=playlists, playlists=playlist_contents, uploaded_songs=uploaded_songs, purchased_songs=purchased_songs) def get_streamed_song(self, id): logger.info("Downloading streamed song id {}".format(id)) stream_url = self.mobile.get_stream_url(id) response = urllib.request.urlopen(stream_url) return response.read() def get_uploaded_song(self, id): logger.info("Downloading uploaded song id {}".format(id)) suggested_filename, data = self.manager.download_song(id) return data
class FreeClient(Client): """ Client for free users with limited functionality. Free users only have access to songs that they have either purchased or uploaded, and they must be downloaded before they can be played. Artists and albums cannot be generated, so the expand method has no use. """ def __init__(self): """ Log into Musicmanager and get the library, either by loading an existing library file, or by generating a new one. """ self.kind = 'free' self.mm = Musicmanager() self.mm.login() self.songs = [] self.load_library() if not self.songs: self.gen_library() def load_library(self): path = join(common.DATA_DIR, 'library.zip') common.w.outbar_msg('Loading library...') if not isfile(path): common.w.addstr(common.w.infobar, 'Could not find library file.') return try: with zipfile.ZipFile(path) as z: try: lib = json.loads(z.read('library.json').decode('utf-8')) except json.JSONDecodeError: # The .json file is invalid. common.w.addstr(common.w.infobar, 'Library file is corrupt.') return except zipfile.BadZipFile: # The .zip file is invalid. common.w.addstr(common.w.infobar, 'Library file is corrupt.') return for item in lib['songs']: try: self.songs.append( music_objects.LibrarySong(item, source='json')) except KeyError: # The file has the wrong data. common.w.addstr(common.w.infobar, 'Library file is corrupt.') return l = len(self.songs) common.w.outbar_msg('Loaded %s song%s.' % (l, '' if l is 1 else 's')) def gen_library(self): ids = [] # Avoid duplicates between purchased and uploaded songs. common.w.outbar_msg('Generating your library...') for song in self.mm.get_uploaded_songs(): if song['id'] not in ids: self.songs.append(music_objects.LibrarySong(song)) ids.append(song['id']) for song in self.mm.get_purchased_songs(): if song['id'] not in ids: self.songs.append(music_objects.LibrarySong(song)) ids.append(song['id']) # Todo: Use something other than json for library storage since it # doesn't really make logical sense (songs is a list, not a dict), # but for now it's very easy to use. with zipfile.ZipFile(join(common.DATA_DIR, 'library.zip'), 'w') as z: z.writestr('library.json', json.dumps({'songs': self.songs})) l = len(self.songs) common.w.outbar_msg('Generated %d song%s.' % (l, '' if l is 1 else 's')) common.w.now_playing() def expand(self, arg=None): """ Artists/albums cannot be generated. so free users cannot expand songs.. Keyword arguments: arg=None: Irrelevant. """ common.q.error_msg('Free users cannot use expand') def search(self, query): """ Search the library for some query. and update the view with the results. Keyword arguments: query=None: The search query. """ if query is None: common.w.error_msg('Missing search query') return # Save the current view in case there are no results. cache = common.v.copy() if common.w.curses: limit = common.w.main.getmaxyx()[0] - 4 else: limit = 50 common.w.outbar_msg('Searching for \'%s\'...' % query) common.v.clear() count, query = 0, query.lower() # Search is case-insensitive. for song in self.songs: if any(query in song[k].lower() for k in ('name', 'artist', 'album')): count += 1 common.v['songs'].append(song) if count == limit: break common.w.outbar_msg('Search returned %d results.' % len(common.v)) if common.v.is_empty(): common.v.replace(cache)
class FreeClient(Client): """ Client for free users with limited functionality. Free users only have access to songs that they have either purchased or uploaded, and they must be downloaded before they can be played. Artists and albums cannot be generated, so the expand and radio methods have no use. """ def __init__(self): """ Log into Musicmanager and get the library, either by loading an existing library file, or by generating a new one. """ self.kind = 'free' self.mm = Musicmanager() self.mm.login() self.songs = [] self.load_library() if not self.songs: self.gen_library() def load_library(self): path = join(common.DATA_DIR, 'library.zip') common.w.outbar_msg('Loading library...') if not isfile(path): common.w.addstr(common.w.infobar, 'Could not find library file.') return try: with zipfile.ZipFile(path) as z: try: lib = json.loads(z.read('library.json').decode('utf-8')) except json.JSONDecodeError: # The .json file is invalid. common.w.addstr( common.w.infobar, 'Library file is corrupt.' ) return except zipfile.BadZipFile: # The .zip file is invalid. common.w.addstr(common.w.infobar, 'Library file is corrupt.') return for item in lib['songs']: try: self.songs.append( music_objects.LibrarySong(item, source='json')) except KeyError: # The file has the wrong data. common.w.addstr(common.w.infobar, 'Library file is corrupt.') return l = len(self.songs) common.w.outbar_msg('Loaded %s song%s.' % (l, '' if l is 1 else 's')) def gen_library(self): ids = [] # Avoid duplicates between purchased and uploaded songs. common.w.outbar_msg('Generating your library...') for song in self.mm.get_uploaded_songs(): if song['id'] not in ids: self.songs.append(music_objects.LibrarySong(song)) ids.append(song['id']) for song in self.mm.get_purchased_songs(): if song['id'] not in ids: self.songs.append(music_objects.LibrarySong(song)) ids.append(song['id']) # Todo: Use something other than json for library storage since it # doesn't really make logical sense (songs is a list, not a dict), # but for now it's very easy to use. with zipfile.ZipFile(join(common.DATA_DIR, 'library.zip'), 'w') as z: z.writestr('library.json', json.dumps({'songs': self.songs})) l = len(self.songs) common.w.outbar_msg( 'Generated %d song%s.' % (l, '' if l is 1 else 's') ) common.w.now_playing() def expand(self, arg=None): """ Artists/albums cannot be generated. so free users cannot expand songs.. Keyword arguments: arg=None: Irrelevant. """ common.q.error_msg('Free users cannot use expand') def radio(self, arg=None): """ Artists/albums cannot be generated. so free users cannot create radio stations. Keyword arguments: arg=None: Irrelevant. """ common.q.error_msg('Free users cannot use radio') def search(self, query): """ Search the library for some query. and update the view with the results. Keyword arguments: query=None: The search query. """ if query is None: common.w.error_msg('Missing search query') return # Save the current view in case there are no results. cache = common.v.copy() if common.w.curses: limit = common.w.ylimit - 4 else: limit = 10 common.w.outbar_msg('Searching for \'%s\'...' % query) common.v.clear() count, query = 0, query.lower() # Search is case-insensitive. for song in self.songs: if any(query in song[k].lower() for k in ('name', 'artist', 'album')): count += 1 common.v['songs'].append(song) if count == limit: break common.w.outbar_msg('Search returned %d results.' % len(common.v)) if common.v.is_empty(): common.v.replace(cache)