Example #1
0
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
Example #2
0
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:
Example #3
0
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):
Example #4
0
    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):
Example #5
0
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
Example #6
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
Example #7
0
	#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)
Example #8
0
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)
Example #10
0
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.")
Example #11
0
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)
Example #12
0
# 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('"', '\'')
Example #13
0
def authenticate():
    api = Mobileclient()
    api.perform_oauth(open_browser=True)
    api.oauth_login(Mobileclient.FROM_MAC_ADDRESS)
    return api
Example #14
0
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
Example #15
0
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")
Example #16
0
                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()
Example #18
0
#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
Example #19
0
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()
Example #20
0
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!"
Example #22
0
            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()