def open_api(): global api log('Logging into google music...') api = Mobileclient() if not api.oauth_login(Mobileclient.FROM_MAC_ADDRESS): log('ERROR unable to login') time.sleep(3) exit() password = None log('Login Successful.') dlog(u'Available track details: '+str(get_google_track_details())) return api
from gmusicapi import Mobileclient from PlaylistADT import Playlist import parsing if __name__ == '__main__': api = Mobileclient() device_id = input("Input your Device ID: ") api.oauth_login(device_id) main_playlist = Playlist() library = api.get_all_songs() for song in library: main_playlist.append(song) playlists = api.get_all_user_playlist_contents() for playlist in playlists: for song in playlist['tracks']: main_playlist.append(song) top = main_playlist.top_n(5) artists = [] for artist_id in top: artist = api.get_artist_info(include_albums=False, artist_id=artist_id, max_rel_artist=0, max_top_tracks=0) artists.append(artist['name']) for artist in artists:
from http.server import HTTPServer, BaseHTTPRequestHandler from io import BytesIO from gmusicapi import Mobileclient api = Mobileclient() with open('key.txt', 'r') as file: key = file.read() if not api.oauth_login(key): #valide device-id api.perform_oauth() if not api.is_authenticated(): print("Authentication failed somehow") quit() with open('static/header.html', 'r') as file: header = file.read().encode("utf-8") with open('static/footer.html', 'r') as file: footer = file.read().encode("utf-8") with open('playlist.txt', 'r') as file: playlist = file.read() searchform = b'<form method="POST"><input type="text" class="search" name="search" placeholder="Liedwunsch"><button type="submit">Suchen</button></form>' class SimpleHTTPRequestHandler(BaseHTTPRequestHandler): def do_GET(self):
print( 'SPOTIFY_CLIENT_SECRET environment variable not set. Generate one at https://developer.spotify.com/dashboard/applications' ) bad = True if not SPOTIFY_OAUTH2_TOKEN: print( 'SPOTIFY_OAUTH2_TOKEN environment variable not set. Generate one at https://developer.spotify.com/console/put-following/ we require the scopes user-follow-modify and user-library-modify' ) bad = True if bad: exit(1) g_client = MobileClient() while not g_client.oauth_login(MobileClient.FROM_MAC_ADDRESS): g_client.perform_oauth() artists = defaultdict(set) for song in g_client.get_all_songs(): artist = song['artist'].strip() album = song['album'].strip() albumArtist = song['albumArtist'].strip() if albumArtist: artist = albumArtist artists[artist].add(album) # because the spotify library doesn't have follow yet... def follow(artist):
def importToGPlay(input = None, songsFromSpotify = []): """Searches Google Play Music using the song data previously generated.""" deviceID = '' if deviceID == '': dIDs = mc.get_registered_devices() dIDsdict = [] for ids in dIDs: dIDsdict.append({'Device name' = ids['friendlyName']}) diDsdict.append({'Device ID' = ids['id']}) print('Please input your 16 digit Android device ID or “ios:<uuid>” for iOS from the list below or enter your own.") print(dIDsdict) deviceID = input('Enter device ID: ') # Authenticates devide using device id. # Device ID os a string of 16 hex digits for Android or “ios:<uuid>” for iOS. if mc.oauth_login(deviceID) is False: mc.perform_oauth() else: print("You have logged in") #checks to see if the function was passed a song dictionary. if not gets spotify library data from file if songsFromSpotify = []: with open("trackFile.json", "r") as songFile: songsFromSpotify = json.load(songFile) #gets track info and searches google servers then compares to initial query. if it doesn't match the track is added to a fails file query = "" songIDs = [] fails = [] counter = 0 total = 0
def get_mobileclient(debug=True, deviceID=Mobileclient.FROM_MAC_ADDRESS): mc = Mobileclient(debug_logging=debug) if not mc.oauth_login(device_id=deviceID): mc.perform_oauth() return mc
#TODO: uncomment this line------------------ #api.rate_songs(thumbsDownSongs, '1') print "found " + str(len(thumbsDownSongs)) + " dupe songs" ''' #tracks = playlist['tracks'] #find_and_remove_dups(api, tracks) # Setup the gmusicapi mc = Mobileclient() mc.__init__() # Check to see if OAuth credentials available, ask user to setup if not try: mc.oauth_login(Mobileclient.FROM_MAC_ADDRESS) #api.perform_oauth() except: print "No OAuth credentials found! Please setup in the following screen!" mc.perform_oauth() mc.oauth_login(Mobileclient.FROM_MAC_ADDRESS ) # If it fails here, it wasn't meant to be # Then, move on to doing all the work if mc.is_authenticated(): main() mc.logout() else: print "Not logged in! Exiting..." exit(1)
class Gmusic(object): def __init__(self, playlists_to_sync, credentials_storage_location, debug): self.playlists_to_sync = playlists_to_sync self.credentials_storage_location = credentials_storage_location self._client = Mobileclient(debug_logging=debug) self._manager = Musicmanager(debug_logging=debug) def client_login(self): credentials = self.credentials_storage_location if not os.path.isfile(credentials): credentials = self._client.perform_oauth( storage_filepath=self.credentials_storage_location, open_browser=True) if not self._client.oauth_login( device_id=Mobileclient.FROM_MAC_ADDRESS, oauth_credentials=credentials, ): logger.error("Gmusic mobile client authentication failed") return False logger.info("Gmusic mobile client authentication succeeded.") return True def manager_login(self): credentials = self.credentials_storage_location if not os.path.isfile(credentials): credentials = self._manager.perform_oauth( storage_filepath=self.credentials_storage_location, open_browser=True) if not self._manager.login(oauth_credentials=credentials, ): logger.error("Gmusic music manager authentication failed") return False logger.info("Gmusic music manager authentication succeeded.") return True @property def client(self): if not self._client.is_authenticated(): self.client_login() return self._client @property def manager(self): if not self._manager.is_authenticated(): self.manager_login() return self._manager @cached_property def uploaded_songs(self): return {song['id']: song for song in self.manager.get_uploaded_songs()} @property def _playlists(self): playlists = self.client.get_all_user_playlist_contents() logger.debug("Loaded {} playlists".format(len(playlists))) return playlists @cached_property def playlists(self): playlists_to_sync = [] for playlist in self._playlists: if playlist['name'] in self.playlists_to_sync: playlists_to_sync.append(playlist) return playlists_to_sync def get_latest_addition_date(self, playlist): lastModified = playlist.get('lastModifiedTimestamp') if lastModified: return datetime.fromtimestamp(int(lastModified) / 10**6).replace(tzinfo=pytz.utc) return None
class GmusicComponent(MediaPlayerDevice): def __init__(self, hass, config): from gmusicapi import Mobileclient # https://github.com/simon-weber/gmusicapi/issues/424 class GMusic(Mobileclient): def login(self, username, password, device_id, authtoken=None): if authtoken: self.session._authtoken = authtoken self.session.is_authenticated = True try: # Send a test request to ensure our authtoken is still valide and working self.get_registered_devices() return True except: # Faild with the test-request so we set "is_authenticated=False" # and go through the login-process again to get a new "authtoken" self.session.is_authenticated = False if device_id: if super(GMusic, self).login(username, password, device_id): return True # Prevent further execution in case we failed with the login-process raise Exception( "Legacy login failed! Please check logs for any gmusicapi related WARNING" ) self.hass = hass self._api = Mobileclient() _username = config.get(CONF_USERNAME) _password = config.get(CONF_PASSWORD) _device_id = config.get(CONF_DEVICE_ID, '00') if _username == 'oauth': if os.path.isfile(_password): try: logged_in = self._api.oauth_login(_device_id, _password) if not logged_in: raise Exception( "Login failed! Please check logs for any gmusicapi related WARNING" ) except: raise Exception( "Failed oauth login, check https://unofficial-google-music-api.readthedocs.io/en/latest/reference/mobileclient.html#gmusicapi.clients.Mobileclient.perform_oauth" ) else: raise Exception("Invalid - Not a file! oauth_cred: ", _password) else: _authtoken = config.get(CONF_TOKEN_PATH, DEFAULT_TOKEN_PATH) + "gmusic_authtoken" _LOGGER.debug("TOKEN: (%s)", _authtoken) if os.path.isfile(_authtoken): with open(_authtoken, 'rb') as handle: authtoken = pickle.load(handle) else: authtoken = None logged_in = self._api.login(_username, _password, _device_id, authtoken) if not logged_in: _LOGGER.error( "Failed legacy log in, check http://unofficial-google-music-api.readthedocs.io/en/latest/reference/mobileclient.html#gmusicapi.clients.Mobileclient.login" ) return False with open(_authtoken, 'wb') as f: pickle.dump(self._api.session._authtoken, f) self._name = DOMAIN self._playlist = "input_select." + config.get(CONF_SELECT_PLAYLIST, DEFAULT_SELECT_PLAYLIST) self._media_player = "input_select." + config.get( CONF_SELECT_SPEAKERS, DEFAULT_SELECT_SPEAKERS) self._station = "input_select." + config.get(CONF_SELECT_STATION, DEFAULT_SELECT_STATION) self._source = "input_select." + config.get(CONF_SELECT_SOURCE, DEFAULT_SELECT_SOURCE) self._gmusicproxy = config.get(CONF_GMPROXY) self._speakersList = config.get(CONF_RECEIVERS) self._entity_ids = [] ## media_players - aka speakers self._playlists = [] self._playlist_to_index = {} self._stations = [] self._station_to_index = {} self._tracks = [] self._track = [] self._attributes = {} self._next_track_no = 0 hass.bus.listen_once(EVENT_HOMEASSISTANT_START, self._update_sources) hass.bus.listen_once(EVENT_HOMEASSISTANT_START, self._get_speakers) hass.bus.listen('gmusic_player.sync_media', self._update_sources) hass.bus.listen('gmusic_player.play_media', self._gmusic_play_media) self._shuffle = config.get(CONF_SHUFFLE, DEFAULT_SHUFFLE) self._shuffle_mode = config.get(CONF_SHUFFLE_MODE, DEFAULT_SHUFFLE_MODE) self._unsub_tracker = None self._playing = False self._state = STATE_OFF self._volume = 0.0 self._is_mute = False self._track_name = None self._track_artist = None self._track_album_name = None self._track_album_cover = None self._track_artist_cover = None self._attributes['_player_state'] = STATE_OFF @property def name(self): """ Return the name of the player. """ return self._name @property def icon(self): return 'mdi:music-circle' @property def supported_features(self): """ Flag media player features that are supported. """ return SUPPORT_GMUSIC_PLAYER @property def should_poll(self): """ No polling needed. """ return False @property def state(self): """ Return the state of the device. """ return self._state @property def device_state_attributes(self): """ Return the device state attributes. """ return self._attributes @property def is_volume_muted(self): """ Return True if device is muted """ return self._is_mute @property def is_on(self): """ Return True if device is on. """ return self._playing @property def media_content_type(self): """ Content type of current playing media. """ return MEDIA_TYPE_MUSIC @property def media_title(self): """ Title of current playing media. """ return self._track_name @property def media_artist(self): """ Artist of current playing media """ return self._track_artist @property def media_album_name(self): """ Album name of current playing media """ return self._track_album_name @property def media_image_url(self): """ Image url of current playing media. """ return self._track_album_cover @property def media_image_remotely_accessible(self): # True returns: entity_picture: http://lh3.googleusercontent.com/Ndilu... # False returns: entity_picture: /api/media_player_proxy/media_player.gmusic_player?token=4454... return True @property def shuffle(self): """ Boolean if shuffling is enabled. """ return self._shuffle @property def volume_level(self): """ Volume level of the media player (0..1). """ return self._volume def turn_on(self, *args, **kwargs): """ Turn on the selected media_player from input_select """ self._playing = False if not self._update_entity_ids(): return _player = self.hass.states.get(self._entity_ids) data = {ATTR_ENTITY_ID: _player.entity_id} if _player.state == STATE_OFF: self._unsub_tracker = track_state_change(self.hass, _player.entity_id, self._sync_player) self._turn_on_media_player(data) elif _player.state != STATE_OFF: self._turn_off_media_player(data) call_later(self.hass, 1, self.turn_on) def _turn_on_media_player(self, data=None): """Fire the on action.""" if data is None: data = {ATTR_ENTITY_ID: self._entity_ids} self._state = STATE_IDLE self.schedule_update_ha_state() self.hass.services.call(DOMAIN_MP, 'turn_on', data) def turn_off(self, entity_id=None, old_state=None, new_state=None, **kwargs): """ Turn off the selected media_player """ self._playing = False self._track_name = None self._track_artist = None self._track_album_name = None self._track_album_cover = None _player = self.hass.states.get(self._entity_ids) data = {ATTR_ENTITY_ID: _player.entity_id} self._turn_off_media_player(data) def _turn_off_media_player(self, data=None): """Fire the off action.""" self._playing = False self._state = STATE_OFF self._attributes['_player_state'] = STATE_OFF self.schedule_update_ha_state() if data is None: data = {ATTR_ENTITY_ID: self._entity_ids} self.hass.services.call(DOMAIN_MP, 'turn_off', data) def _update_entity_ids(self): """ sets the current media_player from input_select """ media_player = self.hass.states.get( self._media_player ) # Example: self.hass.states.get(input_select.gmusic_player_speakers) if media_player is None: _LOGGER.error("(%s) is not a valid input_select entity.", self._media_player) return False _entity_ids = "media_player." + media_player.state if self.hass.states.get(_entity_ids) is None: _LOGGER.error("(%s) is not a valid media player.", media_player.state) return False # Example: self._entity_ids = media_player.bedroom_stereo self._entity_ids = _entity_ids return True def _sync_player(self, entity_id=None, old_state=None, new_state=None): """ Perform actions based on the state of the selected (Speakers) media_player """ if not self._playing: return """ _player = The selected speakers """ _player = self.hass.states.get(self._entity_ids) """ Entire state of the _player, include attributes. """ # self._attributes['_player'] = _player """ entity_id of selected speakers. """ self._attributes['_player_id'] = _player.entity_id """ _player state - Example [playing -or- idle]. """ self._attributes['_player_state'] = _player.state if _player.state == 'off': self._state = STATE_OFF self.turn_off() """ Set new volume if it has been changed on the _player """ if 'volume_level' in _player.attributes: self._volume = round(_player.attributes['volume_level'], 2) self.schedule_update_ha_state() def _gmusic_play_media(self, event): _speak = event.data.get('speakers') _source = event.data.get('source') _media = event.data.get('name') if event.data['shuffle_mode']: self._shuffle_mode = event.data.get('shuffle_mode') _LOGGER.info("SHUFFLE_MODE: %s", self._shuffle_mode) if event.data['shuffle']: self.set_shuffle(event.data.get('shuffle')) _LOGGER.info("SHUFFLE: %s", self._shuffle) _LOGGER.debug("GMUSIC PLAY MEDIA") _LOGGER.debug("Speakers: (%s) | Source: (%s) | Name: (%s)", _speak, _source, _media) self.play_media(_source, _media, _speak) def _update_sources(self, now=None): _LOGGER.debug("Load source lists") self._update_playlists() self._update_stations() #self._update_library() #self._update_songs() def _get_speakers(self, now=None): data = { "options": list(self._speakersList), "entity_id": self._media_player } self.hass.services.call(input_select.DOMAIN, input_select.SERVICE_SET_OPTIONS, data) def _update_playlists(self, now=None): """ Sync playlists from Google Music library """ self._playlist_to_index = {} self._playlists = self._api.get_all_user_playlist_contents() idx = -1 for playlist in self._playlists: idx = idx + 1 name = playlist.get('name', '') if len(name) < 1: continue self._playlist_to_index[name] = idx playlists = list(self._playlist_to_index.keys()) self._attributes['playlists'] = playlists data = {"options": list(playlists), "entity_id": self._playlist} self.hass.services.call(input_select.DOMAIN, input_select.SERVICE_SET_OPTIONS, data) def _update_stations(self, now=None): """ Sync stations from Google Music library """ self._station_to_index = {} self._stations = self._api.get_all_stations() idx = -1 for station in self._stations: idx = idx + 1 name = station.get('name', '') library = station.get('inLibrary') if len(name) < 1: continue if library == True: self._station_to_index[name] = idx stations = list(self._station_to_index.keys()) stations.insert(0, "I'm Feeling Lucky") self._attributes['stations'] = stations data = {"options": list(stations), "entity_id": self._station} self.hass.services.call(input_select.DOMAIN, input_select.SERVICE_SET_OPTIONS, data) def _load_playlist(self, playlist=None): """ Load selected playlist to the track_queue """ if not self._update_entity_ids(): return """ if source == Playlist """ _playlist_id = self.hass.states.get(self._playlist) if _playlist_id is None: _LOGGER.error("(%s) is not a valid input_select entity.", self._playlist) return if playlist is None: playlist = _playlist_id.state idx = self._playlist_to_index.get(playlist) if idx is None: _LOGGER.error("playlist to index is none!") self._turn_off_media_player() return self._tracks = None self._tracks = self._playlists[idx]['tracks'] self._total_tracks = len(self._tracks) #self.log("Loading [{}] Tracks From: {}".format(len(self._tracks), _playlist_id)) if self._shuffle and self._shuffle_mode != 2: random.shuffle(self._tracks) self._play() def _load_station(self, station=None): """ Load selected station to the track_queue """ self._total_tracks = 100 if not self._update_entity_ids(): return """ if source == station """ self._tracks = None _station_id = self.hass.states.get(self._station) if _station_id is None: _LOGGER.error("(%s) is not a valid input_select entity.", self._station) return if station is None: station = _station_id.state if station == "I'm Feeling Lucky": self._tracks = self._api.get_station_tracks( 'IFL', num_tracks=self._total_tracks) else: idx = None idx = self._station_to_index.get(station) if idx is None: self._turn_off_media_player() return _id = self._stations[idx]['id'] self._tracks = self._api.get_station_tracks( _id, num_tracks=self._total_tracks) # self.log("Loading [{}] Tracks From: {}".format(len(self._tracks), _station_id)) self._play() def _play(self): self._playing = True self._next_track_no = -1 self._get_track() def _get_track(self, entity_id=None, old_state=None, new_state=None, retry=3): """ Get a track and play it from the track_queue. """ _track = None if self._shuffle and self._shuffle_mode != 1: self._next_track_no = random.randrange(self._total_tracks) - 1 else: self._next_track_no = self._next_track_no + 1 if self._next_track_no >= self._total_tracks: self._next_track_no = 0 ## Restart curent playlist (Loop) #random.shuffle(self._tracks) ## (re)Shuffle on Loop try: _track = self._tracks[self._next_track_no] except IndexError: _LOGGER.error( "Out of range! Number of tracks in track_queue == (%s)", self._total_tracks) self._turn_off_media_player() return if _track is None: _LOGGER.error("_track is None!") self._turn_off_media_player() return """ If source is a playlist, track is inside of track """ if 'track' in _track: _track = _track['track'] """ Find the unique track id. """ uid = '' if 'trackId' in _track: uid = _track['trackId'] elif 'storeId' in _track: uid = _track['storeId'] elif 'id' in _track: uid = _track['id'] else: _LOGGER.error("Failed to get ID for track: (%s)", _track) if retry < 1: self._turn_off_media_player() return return self._get_track(retry=retry - 1) """ If available, get track information. """ if 'title' in _track: self._track_name = _track['title'] else: self._track_name = None if 'artist' in _track: self._track_artist = _track['artist'] else: self._track_artist = None if 'album' in _track: self._track_album_name = _track['album'] else: self._track_album_name = None if 'albumArtRef' in _track: _album_art_ref = _track['albumArtRef'] ## returns a list self._track_album_cover = _album_art_ref[0]['url'] ## of dic else: self._track_album_cover = None if 'artistArtRef' in _track: _artist_art_ref = _track['artistArtRef'] self._track_artist_cover = _artist_art_ref[0]['url'] else: self._track_artist_cover = None """ Get the stream URL and play on media_player """ try: if not self._gmusicproxy: #_url = self._api.get_stream_url(uid) _url = self._api.get_stream_url("{}".format(uid)) else: _url = self._gmusicproxy + "/get_song?id=" + uid except Exception as err: _LOGGER.error("Failed to get URL for track: (%s)", uid) if retry < 1: self._turn_off_media_player() return return self._get_track(retry=retry - 1) self._state = STATE_PLAYING self.schedule_update_ha_state() data = { ATTR_MEDIA_CONTENT_ID: _url, ATTR_MEDIA_CONTENT_TYPE: "audio/mp3", ATTR_ENTITY_ID: self._entity_ids } self.hass.services.call(DOMAIN_MP, SERVICE_PLAY_MEDIA, data) def play_media(self, media_type, media_id, _player=None, **kwargs): if not self._update_entity_ids(): return # Should skip this if input_select does not exist if _player is not None: _option = {"option": _player, "entity_id": self._media_player} self.hass.services.call(input_select.DOMAIN, input_select.SERVICE_SELECT_OPTION, _option) if media_type == "station": _source = {"option": "Station", "entity_id": self._source} _option = {"option": media_id, "entity_id": self._station} self.hass.services.call(input_select.DOMAIN, input_select.SERVICE_SELECT_OPTION, _source) self.hass.services.call(input_select.DOMAIN, input_select.SERVICE_SELECT_OPTION, _option) elif media_type == "playlist": _source = {"option": "Playlist", "entity_id": self._source} _option = {"option": media_id, "entity_id": self._playlist} self.hass.services.call(input_select.DOMAIN, input_select.SERVICE_SELECT_OPTION, _source) self.hass.services.call(input_select.DOMAIN, input_select.SERVICE_SELECT_OPTION, _option) else: _LOGGER.error( "Invalid: (%s) --> media_types are 'station' or 'playlist'.", media_type) return _player = self.hass.states.get(self._entity_ids) if self._playing == True: self.media_stop() self.media_play() elif self._playing == False and self._state == STATE_OFF: if _player.state == STATE_OFF: self.turn_on() else: data = {ATTR_ENTITY_ID: _player.entity_id} self._turn_off_media_player(data) call_later(self.hass, 1, self.turn_on) else: _LOGGER.error("self._state is: (%s).", self._state) def media_play(self, entity_id=None, old_state=None, new_state=None, **kwargs): """Send play command.""" if self._state == STATE_PAUSED: self._state = STATE_PLAYING self.schedule_update_ha_state() data = {ATTR_ENTITY_ID: self._entity_ids} self.hass.services.call(DOMAIN_MP, 'media_play', data) else: _source = self.hass.states.get(self._source) source = _source.state if source == 'Playlist': self._load_playlist() elif source == 'Station': self._load_station() else: _LOGGER.error("Invalid source: (%s)", source) self.turn_off() return def media_pause(self, **kwargs): """ Send media pause command to media player """ self._state = STATE_PAUSED self.schedule_update_ha_state() data = {ATTR_ENTITY_ID: self._entity_ids} self.hass.services.call(DOMAIN_MP, 'media_pause', data) def media_play_pause(self, **kwargs): """Simulate play pause media player.""" if self._state == STATE_PLAYING: self.media_pause() else: self.media_play() def media_previous_track(self, **kwargs): """Send the previous track command.""" if self._playing: self._next_track_no = max(self._next_track_no - 2, -1) self._get_track() def media_next_track(self, **kwargs): """Send next track command.""" if self._playing: self._get_track() def media_stop(self, **kwargs): """Send stop command.""" self._state = STATE_IDLE self._playing = False self._track_artist = None self._track_album_name = None self._track_name = None self._track_album_cover = None self.schedule_update_ha_state() data = {ATTR_ENTITY_ID: self._entity_ids} self.hass.services.call(DOMAIN_MP, 'media_stop', data) def set_shuffle(self, shuffle): self._shuffle = shuffle if self._shuffle_mode == 1: self._attributes['shuffle_mode'] = 'Shuffle' elif self._shuffle_mode == 2: self._attributes['shuffle_mode'] = 'Random' elif self._shuffle_mode == 3: self._attributes['shuffle_mode'] = 'Shuffle Random' else: self._attributes['shuffle_mode'] = self._shuffle_mode return self.schedule_update_ha_state() def set_volume_level(self, volume): """Set volume level.""" self._volume = round(volume, 2) data = {ATTR_ENTITY_ID: self._entity_ids, 'volume_level': self._volume} self.hass.services.call(DOMAIN_MP, 'volume_set', data) self.schedule_update_ha_state() def volume_up(self, **kwargs): """Volume up the media player.""" newvolume = min(self._volume + 0.05, 1) self.set_volume_level(newvolume) def volume_down(self, **kwargs): """Volume down media player.""" newvolume = max(self._volume - 0.05, 0.01) self.set_volume_level(newvolume) def mute_volume(self, mute): """Send mute command.""" if self._is_mute == False: self._is_mute = True else: self._is_mute = False self.schedule_update_ha_state() data = { ATTR_ENTITY_ID: self._entity_ids, "is_volume_muted": self._is_mute } self.hass.services.call(DOMAIN_MP, 'volume_mute', data)
class GoogleMusic: def __init__(self): self.api = Mobileclient(debug_logging=False) with open(path + "oauth.cred", 'w+') as tmp: tmp.write(settings['google']['mobileclient']) tmp.close() self.api.oauth_login(Mobileclient.FROM_MAC_ADDRESS, tmp.name) os.remove(tmp.name) def createPlaylist(self, name, songs, public): playlistId = self.api.create_playlist(name=name, description=None, public=public) self.addSongs(playlistId, songs) print("Success: created playlist \"" + name + "\"") def addSongs(self, playlistId, songs): songIds = [] songlist = list(songs) notFound = list() for i, song in enumerate(songlist): song = song.replace(" &", "") result = self.api.search(query=song, max_results=2) if len(result['song_hits']) == 0: notFound.append(song) else: songIds.append(self.get_best_fit_song_id(result['song_hits'], song)) if i % 20 == 0: print(str(i) + ' searched') self.api.add_songs_to_playlist(playlistId, songIds) with open(path + 'noresults.txt', 'w', encoding="utf-8") as f: f.write("\n".join(notFound)) f.close() def removeSongs(self, playlistId): pl = self.api.get_all_user_playlist_contents() tracks = next(x for x in pl if x['id'] == playlistId)['tracks'] self.api.remove_entries_from_playlist([x['id'] for x in tracks]) def getPlaylistId(self, name): pl = self.api.get_all_playlists() return next(x for x in pl if x['name'].find(name) != -1)['id'] def get_best_fit_song_id(self, results, song): match_score = {} for res in results: compare = res['track']['artist'] + ' ' + res['track']['title'] match_score[res['track']['storeId']] = difflib.SequenceMatcher(a=song.lower(), b=compare.lower()).ratio() return max(match_score, key=match_score.get) def remove_playlists(self, pattern): pl = self.api.get_all_playlists() p = re.compile("{0}".format(pattern)) matches = [song for song in pl if p.match(song['name'])] print("The following playlists will be removed:") print("\n".join([song['name'] for song in matches])) print("Please confirm (y/n):") choice = input().lower() if choice[:1] == 'y': [self.api.delete_playlist(song['id']) for song in matches] print(str(len(matches)) + " playlists deleted.") else: print("Aborted. No playlists were deleted.")
class GoogleMusicController(object): def __init__(self): self.device_id = os.environ['GOOGLE_MUSIC_DEVICE_ID'] self.client = Mobileclient(debug_logging=False) # TODO: change this to relative path from run location self.client.oauth_login(Mobileclient.FROM_MAC_ADDRESS, 'iota/auth.json') self.player_data = Manager().dict() self.player = None self.player_pid = None self.playlist = Playlist('Now Playing') def _get_entity(self, name: str, type: str, extra_filter=lambda _: True): results = self.search(name).__dict__[type] if len(results) == 0: return None results = list(filter(extra_filter, results)) if len(results) == 0: return None # We will trust Google's ability to filter search results... :P return results[0] def _get_song(self, name: str, artist: str = '', album: str = '') -> Song: if artist != '' and album != '': return self._get_entity( name, 'songs', lambda x: x.artist.lower() == artist and x.album .lower() == album) if artist != '': return self._get_entity(name, 'songs', lambda x: x.artist.lower() == artist) if album != '': return self._get_entity(name, 'songs', lambda x: x.album.lower() == album) return self._get_entity(name, 'songs') def _get_album(self, name: str, artist: str = '') -> Album: if artist != '': return self._get_entity(name, 'albums', lambda x: x.artist == artist) return self._get_entity(name, 'albums') def _get_artist(self, name: str) -> Artist: return self._get_entity(name, 'artists') def _get_playlist(self, name: str) -> Playlist: playlists = self.client.get_all_user_playlist_contents() matched_playlists = [] for p in playlists: p_name = p['name'].lower() if p_name == name or p_name == name.replace(' ', ''): matched_playlists.append(p) if len(matched_playlists) > 0: found = matched_playlists[0] self.playlist = Playlist(found['name']) [ self.playlist.add_song(track['track']) for track in found['tracks'] ] return self.playlist return None def play_song(self, name: str, callback_at_end, artist: str = '', album: str = ''): song = self._get_song(name, artist, album) if song is None: return f'I couldn\'t find a song called {name} by {artist}' return self.play_playlist('Now Playing', callback_at_end, song_list=[song]) def play_playlist( self, name: str, callback_at_end, song_list=[], start=0, shuffle=False, ) -> str: if song_list == []: self.playlist = self._get_playlist(name) if self.playlist is None: return f'I couldn\'t find a playlist called {name}' else: self.playlist = Playlist(name) self.playlist.set_list(song_list) if shuffle: self.playlist.shuffle() # Embed this so we don't have to pass a bunch of context out def get_url(id): # we need to logout and log back in to allow rapid requesting # of stream_urls -- they expire after a minute, and can't be # re-requested before then without an SSLError...thanks Google. self.client.logout() self.client.oauth_login(Mobileclient.FROM_MAC_ADDRESS, 'auth.json') return self.client.get_stream_url(id, device_id=self.device_id) # Spawn a subprocess for the player self.player = Process(target=spawn_player, args=(get_url, self.playlist, self.player_data, callback_at_end, start)) self.player.start() self.player_pid = self.player.pid return None def pause_song(self): if 'pid' in self.player_data.keys(): psutil.Process(self.player_data['pid']).send_signal(signal.SIGSTOP) def resume_song(self): if 'pid' in self.player_data.keys(): psutil.Process(self.player_data['pid']).send_signal(signal.SIGCONT) def stop_player(self): if 'pid' in self.player_data.keys(): psutil.Process(self.player_data['pid']).send_signal(signal.SIGSTOP) # self.player.terminate() def next_song(self) -> str: if 'pid' in self.player_data.keys(): psutil.Process(self.player_data['pid']).send_signal(signal.SIGTERM) def previous_song(self) -> str: if 'index' not in self.player_data.keys(): return 'Could not start the playlist, missing index' idx = self.player_data['index'] idx = idx - 1 if idx > 0 else 0 if not self.player_data['done']: self.stop_player() self.play_playlist(self.playlist.name.lower(), self.playlist.songs, start=idx) return '' def start_over(self): return '' def search(self, query: str, max_results: int = 100) -> SearchResults: results = self.client.search(query, max_results) return SearchResults(results)
# Initialize api and login with oauth_login from gmusicapi import Mobileclient, CallFailure from gmusicapi.exceptions import InvalidDeviceId from urllib.request import urlretrieve, urlopen from urllib.error import HTTPError, URLError from mutagen import id3, mp3, File import os import sys api = Mobileclient() if not os.path.exists(api.OAUTH_FILEPATH): api.perform_oauth() if not os.path.exists(api.OAUTH_FILEPATH[:-17] + 'deviceID.txt'): try: api.oauth_login('') except InvalidDeviceId as error: deviceID = error.valid_device_ids[0] output = open(api.OAUTH_FILEPATH[:-17] + 'deviceID.txt', 'w') output.write(deviceID) output.close() else: deviceID = open(api.OAUTH_FILEPATH[:-17] + 'deviceID.txt').read().rstrip() api.oauth_login(deviceID) def clean(string): # Replace chars with alternatives - "<>:\"/|?*" string = string.replace('<', '‹') string = string.replace('>', '›') string = string.replace(':', '꞉') string = string.replace('"', '\'')
def authenticate(): api = Mobileclient() api.perform_oauth(open_browser=True) api.oauth_login(Mobileclient.FROM_MAC_ADDRESS) return api
class Gpm: def __init__(self): self.client = Mobileclient() # self.client.perform_oauth() self.client.oauth_login(Mobileclient.FROM_MAC_ADDRESS) def fetchCollection(self): songs = self.__makeSongSet(self.client.get_all_songs()) playlists = list() for playlistData in self.client.get_all_user_playlist_contents(): playlist = self.__makePlaylist(playlistData) if playlist is not None: playlists.append(playlist) return Collection(songs, playlists, self) def __makePlaylist(self, playlistData): if playlistData["deleted"] == "True": return None title = playlistData["name"] description = playlistData[ "description"] if "description" in playlistData else None serviceId = playlistData["id"] songs = self.__makeSongSet(playlistData["tracks"]) return Playlist(title, description, songs, serviceId) def __makeSongSet(self, songSetData): songs = list() for songData in songSetData: song = self.__makeSong(songData) if song is not None: songs.append(song) return SongSet(songs) def __makeSong(self, songData): if songData["kind"] == "sj#playlistEntry": if songData["deleted"] == "True" or not "track" in songData: return None songData = songData["track"] isDeleted = songData["deleted"] if "deleted" in songData else False if isDeleted: return None title = songData["title"] artist = songData["artist"] album = songData["album"] rating = int(songData["rating"]) if "rating" in songData else 0 serviceId = songData["id"] if "id" in songData else songData["storeId"] return Song(title, artist, album, rating, serviceId) @staticmethod def loadTakeoutExport(exportPath): songsPath = os.path.join(exportPath, "Tracks") songs = Gpm.loadTakeoutSongSet(songsPath) playlists = list() playlistsPath = os.path.join(exportPath, "Playlists") for playlistFileName in sorted(os.listdir(playlistsPath)): if playlistFileName != "Thumbs Up": playlist = Gpm.loadTakeoutPlaylist( os.path.join(playlistsPath, playlistFileName)) if playlist is not None: playlists.append(playlist) return Collection(songs, playlists, NullService()) @staticmethod def loadTakeoutPlaylist(exportPath): title = os.path.basename(exportPath) description = "" isDeleted = False metadataPath = os.path.join(exportPath, "Metadata.csv") with open(metadataPath) as metadataFile: metadata = next(csv.DictReader(metadataFile)) title = metadata["Title"] description = metadata["Description"] isDeleted = (metadata["Deleted"] == "Yes") if isDeleted: return None songs = Gpm.loadTakeoutSongSet(os.path.join(exportPath, "Tracks")) return Playlist(title, description, songs, None) @staticmethod def loadTakeoutSongSet(exportPath): songs = list() for songFileName in sorted(os.listdir(exportPath)): song = Gpm.loadTakeoutSong(os.path.join(exportPath, songFileName)) if song is not None: songs.append(song) return SongSet(songs) @staticmethod def loadTakeoutSong(exportPath): with open(exportPath) as songFile: metadata = next(csv.DictReader(songFile)) title = html.unescape(metadata["Title"].strip(" ")) artist = html.unescape(metadata["Artist"].strip(" ")) album = html.unescape(metadata["Album"].strip(" ")) rating = int(metadata["Rating"]) isDeleted = (metadata["Removed"] == "Yes") if isDeleted or (title == "" and artist == "" and album == ""): return None return Song(title, artist, album, rating, None) def addPlaylist(self, title, description): playlistId = self.client.create_playlist(title, description) return Playlist(title, description, list(), playlistId) def addSongFromSearchResults(self, song): trackId = self.client.add_store_tracks([song.serviceId]) return Song(song.title, song.artist, song.album, song.rating, trackId) def addSongToPlaylist(self, song, playlist): self.client.add_songs_to_playlist(playlist.serviceId, song.serviceId) def likeSong(self, song): self.client.rate_songs({"id": song.serviceId}, "5") def search(self, query): matches = list() searchResults = self.client.search(query) for songHit in searchResults["song_hits"]: song = self.__makeSong(songHit["track"]) matches.append(song) return matches
import numpy as np from gmusicapi import Mobileclient import json client = Mobileclient() # client.perform_oauth() client.oauth_login(Mobileclient.FROM_MAC_ADDRESS) songs = client.get_all_songs() with open('dataset.json', 'w') as f: json.dump(songs, f, indent=4) print("Serialized song data")
track_info = list( filter(lambda s: s['id'] == track['trackId'], songs))[0] info_file.write("\t{0} - {1}\n".format(track_info["artist"], track_info["title"])) backup_file.write("\n") info_file.write("\n") backup_file.close() info_file.close() def load_from_backup(): print("not implemented yet :c") def migrate(): print("not implemented yet :c") def print_help(): print("not implemented yet :c") if __name__ == '__main__': print("Hello!") api = Mobileclient() isLoggedIn = api.oauth_login(Mobileclient.FROM_MAC_ADDRESS) if not isLoggedIn: isLoggedIn = log_in(api) if isLoggedIn: run_menu(api)
class GoogleMusicDownloader: LONG_FILE_DUR = 600000 FILE_NAME_RE = re.compile(r'[\\/:"*?<>|]+') def __init__(self): self.client = Mobileclient() logged_in = self.client.oauth_login(Mobileclient.FROM_MAC_ADDRESS) if path.exists(Mobileclient.OAUTH_FILEPATH) else False if not logged_in: print('No oauth credentials found, please authenticate your account') self.client.perform_oauth(open_browser=True) self.client.oauth_login(Mobileclient.FROM_MAC_ADDRESS) else: print('Logged in!') def __ask(self, text): inpt = input(text + ' (y/n): ').lower() return inpt.startswith('y') def __update_metadata(self, path = str(), info = dict()): with open(path, 'r+b') as mp3f: mp3 = MP3(mp3f) id3 = ID3() track_num = info.get('trackNumber', 1) id3.add(TRCK(encoding=3, text=[track_num if track_num > 0 else 1])) id3.add(TIT2(encoding=3, text=info['title'])) id3.add(TPE1(encoding=3, text=[info.get('artist', None)])) id3.add(TCOM(encoding=3, text=[info.get('composer', None)])) id3.add(TCON(encoding=3, text=[info.get('genre', None)])) id3.add(TAL(encoding=3, text=[info.get('album', None)])) year = info.get('year', 0) if year > 0: id3.add(TYER(encoding=3, text=[year])) if 'albumArtRef' in info and len(info['albumArtRef']) > 0: img_url = info['albumArtRef'][0]['url'] if img_url: req = requests.get(img_url, allow_redirects=True) id3.add(APIC(encoding=3, mime='image/jpeg', type=3, data=req.content)) mp3.tags = id3 mp3.save(mp3f) def __kill(self): self.client.logout() exit() def download_all_songs(self): print('Loading music library...') library = self.client.get_all_songs() print(len(library), 'tracks detected.') if len(library) == 0: self.__kill() current_path = path.dirname(path.realpath(__file__)) include_long_files = self.__ask('Also download long files? (10+ min)') if not self.__ask('Begin downloading?'): self.__kill() long_skipped_count = 0 errors_count = 0 successful_count = 0 song_num = 0 folder_path = path.join(current_path, 'downloads') if not path.exists(folder_path): mkdir(folder_path) for song in library: song_num += 1 song_id = song['id'] if song['id'] else song['storeId'] song_name = song['artist'] + ' - ' + song['title'] mp3_path = path.join(folder_path, self.FILE_NAME_RE.sub(' ', song_name) + '.mp3') song_name = '%d. %s' % (song_num, song_name) # song name with index number only for display if path.exists(mp3_path): print('Track', song_name, 'already exists! Updating metadata...') self.__update_metadata(mp3_path, song) continue if not include_long_files and int(song.get('durationMillis', 0)) >= self.LONG_FILE_DUR: long_skipped_count += 1 continue song_url = self.client.get_stream_url(song_id) if not song_url: print('Warning:', song_name, 'url is empty! Skip...') errors_count += 1 continue req = requests.get(song_url, allow_redirects=True, stream=True) if not req.ok: print(song_name, 'download error!') errors_count += 1 req.raise_for_status() continue total_size = int(req.headers.get('content-length')) with open(mp3_path, 'wb') as mp3f: with tqdm(total=total_size, unit='B', unit_scale=True, desc=song_name + '.mp3') as pbar: for chunk in req.iter_content(1024): if chunk: mp3f.write(chunk) mp3f.flush() pbar.update(len(chunk)) successful_count += 1 print('Filling metadata for', song_name) self.__update_metadata(mp3_path, song) status_text = 'Process complete! Downloaded: {downloaded}; ' if not include_long_files: status_text += 'Long files skipped: {long_skipped}; ' status_text += 'Errors count: {errors}' print(status_text.format(downloaded=successful_count, long_skipped=long_skipped_count, errors=errors_count)) self.client.logout()
#This script is meant to populate the playlist table with a user's playlist from google play music. from gmusicapi import Mobileclient import sqlite3 import sys reload(sys) sys.setdefaultencoding('utf-8') api = Mobileclient() #Now using the newer oauth login! api.oauth_login(device_id=Mobileclient.FROM_MAC_ADDRESS, oauth_credentials="oauth.txt") if Mobileclient.is_authenticated(api) == True: print("Logged into GPM successfully") else: print "Please log into Google Play Music" api.perform_oauth(storage_filepath="oauth.txt") api.oauth_login(device_id=Mobileclient.FROM_MAC_ADDRESS, oauth_credentials="oauth.txt") def fillPlaylist(): print "These playlists were detected on your Google Play Music account:" print ">>-------------------------------------<<" dplaylists = api.get_all_user_playlist_contents() index = 1 for item in dplaylists: print(str(index) + ". " + item['name']) index += 1 index -= 1
import os import json from gmusicapi import Mobileclient import os.path from youtube_search_engine import youtube_search from youtube_search_engine import youtube_stream_link import yaml ROOT_PATH = os.path.realpath(os.path.join(__file__, '..', '..')) USER_PATH = os.path.realpath(os.path.join(__file__, '..', '..', '..')) with open('{}/src/config.yaml'.format(ROOT_PATH), 'r') as conf: configuration = yaml.load(conf) api = Mobileclient() logged_in = api.oauth_login(Mobileclient.FROM_MAC_ADDRESS) if logged_in: for device in api.get_registered_devices(): if device['type'] == 'ANDROID': deviceid = device['id'][2:] print(deviceid) break api.logout() logged_in = api.oauth_login(deviceid) class vlcplayer(): def __init__(self): self.libvlc_Instance = vlc.Instance('--verbose 0') self.libvlc_player = self.libvlc_Instance.media_player_new() # self.libvlc_list_player = self.libvlc_Instance.media_list_player_new()
def main(): #### Requests user specifies update library and/or playlists if len(sys.argv) != 3: print('Specify T/F arguments for uploading and updating playlists') print('e.g. python ' + sys.argv[0] + ' 1 0') print('which would:\n--> upload new songs\n--> NOT update playlists') sys.exit(0) #### Parameters music_dir = '/home/conor/Music/' print('Local music directory set to:', music_dir) accepted = input('Type "y" if this is correct directory: ') if accepted.lower() != 'y': print('Edit music_dir variable in source to run script...') print('Ending music management.') sys.exit(0) #### Some general information needed for both tasks is collected here # Get mp3 file names from music folder local_song_paths = glob.glob(music_dir + '*.mp3') # Get individual song names local_song_names = set() for p in local_song_paths: _, song_name = os.path.split(p) local_song_names.add(song_name) # Authenticate mc = Mobileclient() mc.oauth_login('38e42c4b00ca0a10') # Authenticates using on-disk token print('Mobile client authentication complete...') # Create dict of gpm 'song'': 'id' pairs song_ids = {} gpm_songs = mc.get_all_songs() for song in gpm_songs: song_ids[song['title']] = song['id'] #### Manage upload/deletion of songs uploading = sys.argv[1] if uploading == '1': mm = Musicmanager() mm.login(uploader_id='EE:20:80:B4:17:A9' ) # Authenticates using on-disk token print('Music manager authentication complete...') # Delete songs that no longer exist locally to_delete = set() for song in song_ids: if song not in local_song_names: to_delete.add(song) if len(to_delete) == 0: print('No songs to delete.') else: print('{} songs to delete:'.format(len(to_delete))) print([s for s in to_delete]) # delete_songs() method requires a list as input to_delete_ids = [] for s in to_delete: song_id = song_ids[s] to_delete_ids.append(song_id) mc.delete_songs(to_delete_ids) print('Deleted songs.') #### Uploading to_upload = [] for s in local_song_names: if s not in song_ids: to_upload.append(music_dir + s) print('{} songs to upload.'.format(len(to_upload))) if len(to_upload) != 0: accepted = input('Type "y" to commence upload now: ') if accepted.lower() != 'y': print('Ending music management.') sys.exit(0) mm.upload(to_upload) #### Create and edit playlists as required # Works by deleting all playlists and then re-creating from scratch playlisting = sys.argv[2] if playlisting == '1': # Refresh song list # (since we have uploaded new songs since original list generated) song_ids = {} gpm_songs = mc.get_all_songs() for song in gpm_songs: song_ids[song['title']] = song['id'] # Flush old playlists print('Deleting old playlists...') gpm_playlists = mc.get_all_playlists() for pl in gpm_playlists: mc.delete_playlist(pl['id']) print('Playlists deleted.') # Keep a dictionary of created playlists to prevent duplication playlist_ids = {} total = len(song_ids) completed = 0 # Create and update playlists print('Organising songs:') for s in song_ids: sid = song_ids[s] req_pls = required_playlists(s) for pl in req_pls: if pl in playlist_ids: pid = playlist_ids[pl] else: pid = mc.create_playlist(name=pl) playlist_ids[pl] = pid mc.add_songs_to_playlist(pid, sid) completed += 1 # Console output for number of songs sorted sys.stdout.write("\r{}/{} processed".format(completed, total)) sys.stdout.flush() print()
print "USAGE:" print "./add_last_songs_to_top_of_playlist.py 'PLAYLIST NAME' NUMBER_SONGS" print print "example: ./add_last_songs_to_top_of_playlist.py 'Ultimate Everything' 5" print " will move the last 5 songs in 'Ultimate Everything' to the top of the playlist." exit(0) else: playlist_name = sys.argv[1] num_songs = sys.argv[2] # Setup the gmusicapi api = Mobileclient() api.__init__() # Check to see if OAuth credentials available, ask user to setup if not try: api.oauth_login(Mobileclient.FROM_MAC_ADDRESS) except: print "No OAuth credentials found! Please setup in the following screen!" api.perform_oauth() api.oauth_login(Mobileclient.FROM_MAC_ADDRESS) # If it fails here, it wasn't meant to be # Then, move on to doing all the work if api.is_authenticated(): print "Successfully logged in. Moving " + num_songs + " tracks to top of playlist" playlists = api.get_all_user_playlist_contents() tracks = get_playlist_tracks(playlist_name, playlists) move_songs_to_top(api, tracks, int(num_songs)) print "Script completed successfully!"
int(_) for _ in self.parent.geometry().split('+', 1)[1].split('+')) parent_w, parent_h = ( int(_) for _ in self.parent.geometry().split('+', 1)[0].split('x')) w, h = (int(_) for _ in self.geometry().split('+')[0].split('x')) x = parent_x + parent_w / 2 - w / 2 y = parent_y + parent_h / 2 - h / 2 self.geometry("+%d+%d" % (x, y)) def steps_complete(self, number_of_steps): self.bar['value'] += number_of_steps self.parent.update_idletasks() self.update_idletasks() #print(self.bar['value']) def set_message(self, message_text): self.message.config(text=message_text) self.update_idletasks() if __name__ == "__main__": #mobile_client = Mobileclient(debug_logging=True) mobile_client = Mobileclient(debug_logging=False) if not mobile_client.oauth_login(Mobileclient.FROM_MAC_ADDRESS): mobile_client.perform_oauth(open_browser=True) mobile_client.oauth_login(Mobileclient.FROM_MAC_ADDRESS) splash = shared.Splash('GMusicDownloader\nis loading...') app = MainWindow() app.title('GMusic Downloader') app.mainloop()