Example #1
0
class GoogleMusic(Source):
    def __init__(self, library, username, password):
        Source.__init__(self, library, SourceType.GOOGLE)
        self.GOOGLE_DEVICE_ID = None

        print username
        print password

        self.client = Mobileclient()
        logged_in = self.client.login(username, password, Mobileclient.FROM_MAC_ADDRESS)
        print "Google logged in:", logged_in

        DList = self.client.get_registered_devices()
        self.GOOGLE_DEVICE_ID = DList[0]["id"]
        if self.GOOGLE_DEVICE_ID[:2] == '0x':
            self.GOOGLE_DEVICE_ID = self.GOOGLE_DEVICE_ID[2:]

        print self.GOOGLE_DEVICE_ID

        #>testing
        # self.get_stream_URL("47b9d52c-9d66-3ff2-94d4-3ae55c0d2acc")

    def get_stream_URL(self, song_id):
        return self.client.get_stream_url(song_id, self.GOOGLE_DEVICE_ID)

    def sync(self):
        gmusic_tracks = self.client.get_all_songs()
        for track in gmusic_tracks:
            art = ''
            try:
                art = track['albumArtRef'][0]['url']
            except KeyError:
                art = ''
            self.library.insert_track(track['title'], track['album'], track['artist'], self._source, str(track['id']), track['trackNumber'], art)
Example #2
0
 def search(self, lib, opts, args):
     password = config['gmusic']['password']
     email = config['gmusic']['email']
     password.redact = True
     email.redact = True
     # Since Musicmanager doesn't support library management
     # we need to use mobileclient interface
     mobile = Mobileclient()
     try:
         mobile.login(email.as_str(), password.as_str(),
                      Mobileclient.FROM_MAC_ADDRESS)
         files = mobile.get_all_songs()
     except NotLoggedIn:
         ui.print_(
             u'Authentication error. Please check your email and password.'
         )
         return
     if not args:
         for i, file in enumerate(files, start=1):
             print(i, ui.colorize('blue', file['artist']),
                   file['title'], ui.colorize('red', file['album']))
     else:
         if opts.track:
             self.match(files, args, 'title')
         else:
             self.match(files, args, 'artist')
Example #3
0
 def search(self, lib, opts, args):
     password = config['gmusic']['password']
     email = config['gmusic']['email']
     password.redact = True
     email.redact = True
     # Since Musicmanager doesn't support library management
     # we need to use mobileclient interface
     mobile = Mobileclient()
     try:
         mobile.login(email.as_str(), password.as_str(),
                      Mobileclient.FROM_MAC_ADDRESS)
         files = mobile.get_all_songs()
     except NotLoggedIn:
         ui.print_(
             u'Authentication error. Please check your email and password.')
         return
     if not args:
         for i, file in enumerate(files, start=1):
             print(i, ui.colorize('blue', file['artist']), file['title'],
                   ui.colorize('red', file['album']))
     else:
         if opts.track:
             self.match(files, args, 'title')
         else:
             self.match(files, args, 'artist')
	def get_data(self):
		mobileapi = Mobileclient()
		mobileapi.login(setting.GUSER, setting.GPASS)
		library = mobileapi.get_all_songs()
		mobileapi.logout()
		
		return library
def gm_get_current_pl_member(client: Mobileclient, playlist: str) -> (str, list):
    playlist = list(filter(
        lambda x: x['deleted'] == False and x['name'] == playlist,
        client.get_all_user_playlist_contents()
    ))[0]
    member_track_ids = set([item['trackId'] for item in playlist['tracks']])
    return playlist['id'], [item for item in client.get_all_songs() if item['id'] in member_track_ids]
Example #6
0
def google_music(gmail, psswd,last_sync = 0):

    from gmusicapi import Mobileclient
    api = Mobileclient()
    songs =[]

    if api.login(gmail, psswd, ):
        library = api.get_all_songs()

        for track in  library:
            song = {}
            song['name'] = track.get('title','')
            song['artist'] = track.get('artist','')
            song['year'] = track.get('year',0)
            song['genre'] = track.get('genre','')
            song['plays'] = track.get('playCount',0)
            tup = youtubeVidSearch(song['name'],song['artist'])
            song['url'] = tup[0]
            song['art'] = tup[1]
            stamp = int(track.get('creationTimestamp',0))/1000.0
            if stamp > last_sync and song.get('url') :
                songs.append(song)
                print track

    return songs
Example #7
0
def update_stats(user_id):
    gm = Mobileclient()
    user = UserSettings.objects.get(pk=user_id)
    try:
        user_credential_base64 = user.credential
        user_credential = codecs.decode(user_credential_base64.encode(),
                                        "base64")
        credential = pickle.loads(user_credential)

        # TODO think about google apis problem
        gm.oauth_login(user.current_device, credential)

        try:
            library = gm.get_all_songs()
            gm.logout()
        except Exception as e:
            print("Exception: " + str(e))
            return

        new_library = prepare_library(library)

        new_stats = PlayMusicStats()
        new_stats.user = user.user
        new_stats.stats = new_library
        new_stats.total_time = get_total_time_in_sec(new_library)
        new_stats.save()

        print('Stats for ' + str(user.user) + ' saved')
    except Exception as e:
        user.credential_is_valid = False
        user.save()
        print('Credential for ' + str(user.user) + ' is invalid: ' + str(e))
Example #8
0
def get_songs(sync=False):
    if os.path.isfile('songs.json') and not sync:
        f = open('songs.json', 'r')
        songs = f.read()
        songs = json.loads(songs)
    else:
        api = Mobileclient()
        api.login(GOOGLE_EMAIL, GOOGLE_MUSIC_PASS,
                  Mobileclient.FROM_MAC_ADDRESS)

        songs_gen = api.get_all_songs(True)

        print("Loading library songs:")

        songs = []
        for part in songs_gen:
            songs = songs + part
            print("%s songs loaded" % len(songs))

            str(len(songs)) + " songs loaded."

        songs = list(reversed(resort_by_added(songs)))

        f = open('songs.json', 'w')
        f.write(json.dumps(songs, indent=4, separators=(',', ': ')))
        f.close()

    return songs
Example #9
0
class GMusicClient:
    def __init__(self):
        """
        This connects to the google music server by requesting credentials.
        """
        self.api = Mobileclient()

        # username = input('Type your Google Play Music email below.\n--> ')
        self.username = os.getenv('GOOGLE_USERNAME')
        dir_path = os.path.dirname(os.path.realpath(__file__)) + '/.cache-gmusic-' + ''.join(filter(str.isalpha, self.username))
        # Check if already authenticated
        if(not os.path.isfile(dir_path)):
            self.api.perform_oauth(open_browser=True, storage_filepath=dir_path)

        # Attempt to log in; if fail, get new token.
        try:
            self.api.oauth_login(Mobileclient.FROM_MAC_ADDRESS, oauth_credentials=dir_path)
        except:
            self.api.perform_oauth(open_browser=True, storage_filepath=dir_path)
            self.api.oauth_login(Mobileclient.FROM_MAC_ADDRESS, oauth_credentials=dir_path)

        print('Connected to GMusic')

    def get_playlists(self):
        """
        Gets all the playlists in Google Play Music. Some may not actually
        have any music, but they will be processed anyways.
        """
        playlists_cache_path = os.path.dirname(os.path.realpath(__file__)) + '/.cache-playlists_cache-' + ''.join(filter(str.isalpha, self.username))
        if (os.path.isfile(playlists_cache_path)):
            with open(playlists_cache_path, 'rb') as playlists_cache_file:
                playlists = pickle.load(playlists_cache_file)
        else:
            print('Requesting Google playlists')
            playlistsG = self.api.get_all_user_playlist_contents()
            print('Received Google playlists, we have', len(playlistsG), 'playlists')
            playlists = Playlists(playlistsG)
            with open(playlists_cache_path, 'wb') as playlists_cache_file:
                pickle.dump(playlists, playlists_cache_file)

        return playlists

    def get_all_songs(self):
        """
        Gets the entire Google library for adding to the
        """
        lib_cache_path = os.path.dirname(os.path.realpath(__file__)) + '/.cache-lib_cache-' + ''.join(filter(str.isalpha, self.username))
        if (os.path.isfile(lib_cache_path)):
            with open(lib_cache_path, 'rb') as lib_cache_file:
                library = pickle.load(lib_cache_file)
        else:
            print('Requesting Google library')
            librarySongs = self.api.get_all_songs()
            print('Received Google library, we have', len(librarySongs), 'songs')
            library = MusicLibrary(librarySongs)
            with open(lib_cache_path, 'wb') as lib_cache_file:
                pickle.dump(library, lib_cache_file)

        return library
Example #10
0
def get_google_songs(mc: Mobileclient, mintimestamp: int = 0):
    arr = mc.get_all_songs()
    filterd = []
    mintimestamp *= 1000
    for elem in arr:
        if int(elem["creationTimestamp"]) > mintimestamp:
            filterd.append(elem["id"])
    return filterd
class GoogleMusicHelper(object):
    def __init__(self, email=None, password=None):
        self.google_music_client = Mobileclient()
        if email and password:
            self.login(email, password)

    def login(self, email, password):
        if self.google_music_client.login(email, password,
                                          Mobileclient.FROM_MAC_ADDRESS):
            return "Logged in to Google"
        return "Error logging in"

    def add_song_by_name_to_google_library(self, song="", artist=""):
        results = self.google_music_client.search(query=song + " " + artist,
                                                  max_results=1)
        if results:
            track = results["song_hits"][0]["track"]
            return self.google_music_client.add_store_tracks(
                track.get("storeId") or track.get("nid"))

    def list_playlists(self):
        return self.google_music_client.get_all_user_playlist_contents()

    def sync_playlists_with_library(self, password=None, username=None):
        if self.google_music_client.login(username, password,
                                          Mobileclient.FROM_MAC_ADDRESS):
            all_tracks = []
            for playlist in self.google_music_client.get_all_user_playlist_contents(
            ):
                for track in playlist["tracks"]:
                    all_tracks.append(track["track"])

            playlist_store_ids = [track["storeId"] for track in all_tracks]
            all_songs = self.google_music_client.get_all_songs(
                incremental=False)

            print all_songs[0]

            added_store_ids = []
            for song in all_songs:
                store_id = None
                if song.get("nid"):
                    store_id = song["nid"]
                elif song.get("storeId"):
                    store_id = song["storeId"]
                added_store_ids.append(store_id)

            new_store_ids = set(playlist_store_ids) - set(added_store_ids)
            new_tracks = [
                track for track in all_tracks
                if track["storeId"] not in added_store_ids
            ]
            for storeId in new_store_ids:
                for track in new_tracks:
                    if track["storeId"] == storeId:
                        break
                print track['title'] + " by " + track["artist"]
                print self.google_music_client.add_store_tracks(storeId)
Example #12
0
class Plugin:
    name = 'gmusic'

    def __init__(self, username, password):
        self.client = Mobileclient()
        self.client.login(username, password, Mobileclient.FROM_MAC_ADDRESS)
        # self.webclient = Webclient()
        # self.webclient.login(username, password)

    def get_tracks(self, artist=None, album=None):
        """
        Fetches tracks from api.

        If no filter is defined, it will get user tracks
        """
        return TrackList(self.client.get_all_songs())

    def get_playlists(self):
        """
        Get playlists and radios
        """
        playlists = []
        for playlist in self.client.get_all_user_playlist_contents():
            tracks = TrackList([
                self.client.get_track_info(x['trackId'])
                for x in playlist['tracks']
            ])
            playlists.append(PlayList(playlist['name'], tracks))
        return playlists

    def stream(self, track):
        def _stream(url):
            inp = requests.get(url, stream=True)
            chunk_size = 1024
            for chunk in inp.iter_content(chunk_size):
                if not chunk:
                    continue
                yield chunk

        song_id = track.uri.split(':')[-1]
        return _stream(self.client.get_stream_url(song_id))

    def search(self, keywords, matches):
        results = self.client.search(keywords)
        if matches == 'artist':
            return {'artists': results.get('artist_hits', [])}
        elif matches == 'album':
            return {'albums': results.get('album_hits', [])}
        elif matches == 'tracks':
            return {'tracks': results.get('song_hits', [])}
        elif matches == 'all':
            return {
                'artists': results.get('artist_hits', []),
                'albums': results.get('album_hits', []),
                'tracks': results.get('song_hits', [])
            }
def download_album(username, password, artist_name, album_name):
    api = Mobileclient()
    api.login(username, password, Mobileclient.FROM_MAC_ADDRESS)

    library = api.get_all_songs()
    songs = [s for s in library if s['albumArtist'] == artist_name and s['album'] == album_name]

    if len(songs) == 0:
        print('Error: Album not found', file=sys.stderr)
        return

    device_id = api.get_registered_devices()[0]['id'].replace('0x', '')
    dname = slugify(unicode(album_name))
    os.mkdir(dname)
    
    # download songs
    for song in tqdm(songs, desc='Downloading'):
        fname = slugify(song['title'])
        mpg_name = os.path.join(dname, fname + '.mpg')
        mp3_name = os.path.join(dname, fname + '.mp3')

        url = api.get_stream_url(song['id'], device_id=device_id)
        response = requests.get(url)

        # first save as MPEG video
        with open(mpg_name, 'wb') as fout:
            for chunk in response.iter_content(chunk_size=128):
                fout.write(chunk)

        # call FFMPEG to convert to MP3
        os.system(' '.join([FFMPEG_CMD] + FFMPEG_ARGS).format(
            input=mpg_name,
            output=mp3_name,
            title=song['title'],
            artist=song['albumArtist'],
            album=song['album'],
            track=song['trackNumber']))

        os.remove(mpg_name)

    # download album art
    art_name = os.path.join(dname, dname + '.png')
    album_info = api.get_album_info(songs[0]['albumId'], include_tracks=False)
    response = requests.get(album_info['albumArtRef'])
    t = magic.from_buffer(response.content, mime=True)

    if t == 'image/jpeg':
        ext = '.jpg'
    elif t == 'image/png':
        ext = '.png'
    else:
        print('Unknown MIME type: {}'.format(t), file=sys.stderr)
        ext = '.wat'

    with open(os.path.join(dname, dname + ext), 'wb') as fout:
        fout.write(response.content)
Example #14
0
def _GetLibrary():
    print("Retrieving library..")
    api = Mobileclient()
    if not api.login(config["DEFAULT"]["sGMusicUsername"],
                     config["DEFAULT"]["sGMusicPassword"],
                     Mobileclient.FROM_MAC_ADDRESS):
        raise Exception("Google Music login attempt failed under username:"******"DEFAULT"]["sGMusicUsername"])
    library = api.get_all_songs()
    GMRLog.debug("library:" + TM.Narrate(library))
    return library
Example #15
0
def main(path):
    api = Mobileclient()
    logged_in = api.login(EMAIL, PASSWORD)

    if logged_in:
        print("Succesfully logged in, retrieving all songs and running check...")
        all_songs = api.get_all_songs()
        tracks = remove_dups(all_songs)
        results = find_in_lib(path, tracks)
        print("saving file to %s" % os.path.join(os.getcwd(), "output.json"))
        with open("output.json", "w+") as f:
            f.write(json.dumps(results))
            f.close()
def get_online_library():
    api = Mobileclient()
    logged_in = api.login("*****@*****.**", "yesilly12twat",
                          Mobileclient.FROM_MAC_ADDRESS)
    if logged_in == False:
        sys.exit("Couldn't log in.")
    if not api.is_authenticated:
        sys.exit("Couldn't log in. Wrong credentials")

    library = {
        "tracks": api.get_all_songs(),
        "playlists": api.get_all_user_playlist_contents(),
    }
    return library
def get_lib_from_googlemusic():
	# global USER_NAME
	# global APP_PASSWORD
	api = Mobileclient(debug_logging=False)
	logged_in = api.login(email=USER_NAME, password=APP_PASSWORD, locale='en_US', android_id=Mobileclient.FROM_MAC_ADDRESS)
	lib = api.get_all_songs()
	lib_list = []
	for song in lib:
	    song_dict={}
	    song_dict['artist'] = song['artist']
	    # song_dict['album'] = song['album']
	    song_dict['title'] = song['title']
	    lib_list.append(song_dict)
	return pd.DataFrame(lib_list)
Example #18
0
class Plugin:
    name = 'gmusic'

    def __init__(self, username, password):
        self.client = Mobileclient()
        self.client.login(username, password, Mobileclient.FROM_MAC_ADDRESS)
        # self.webclient = Webclient()
        # self.webclient.login(username, password)

    def get_tracks(self, artist=None, album=None):
        """
        Fetches tracks from api.

        If no filter is defined, it will get user tracks
        """
        return TrackList(self.client.get_all_songs())

    def get_playlists(self):
        """
        Get playlists and radios
        """
        playlists = []
        for playlist in self.client.get_all_user_playlist_contents():
            tracks = TrackList([self.client.get_track_info(x['trackId']) for x in playlist['tracks']])
            playlists.append(PlayList(playlist['name'], tracks))
        return playlists

    def stream(self, track):
        def _stream(url):
            inp = requests.get(url, stream=True)
            chunk_size = 1024
            for chunk in inp.iter_content(chunk_size):
                if not chunk:
                    continue
                yield chunk
        song_id = track.uri.split(':')[-1]
        return _stream(self.client.get_stream_url(song_id))

    def search(self, keywords, matches):
        results = self.client.search(keywords)
        if matches == 'artist':
            return {'artists': results.get('artist_hits', [])}
        elif matches == 'album':
            return {'albums': results.get('album_hits', [])}
        elif matches == 'tracks':
            return {'tracks': results.get('song_hits', [])}
        elif matches == 'all':
            return {'artists': results.get('artist_hits', []),
                    'albums': results.get('album_hits', []),
                    'tracks': results.get('song_hits', [])}
Example #19
0
def play_song():
    """
    Need OAuth creds first:
    from gmusicapi import Mobileclient
    api = Mobileclient()
    api.perform_oauth()
    # do instructions, it will save creds to storage.
    """
    api = Mobileclient()
    api.oauth_login(Mobileclient.FROM_MAC_ADDRESS)
    library = api.get_all_songs()
    track_id = library[0]['id']
    url = api.get_stream_url(track_id)
    p = vlc.MediaPlayer(url)
    p.play()
Example #20
0
def getTracksGPM(api):

    #Get unformatted tracks list
    tracksDictionary = Mobileclient.get_all_songs(api, False, None)

    tracksList = []

    for i in range(len(tracksDictionary)):

        trackName = tracksDictionary[i]['title'].upper()
        artistName = tracksDictionary[i]['artist'].upper()

        tracksList.append(trackFormat(trackName, artistName))

    return tracksList
def lastfm_to_google_music(lastfm_user, lastfm_apikey, gmusic_email, gmusic_password):
    lastfm_client = LastFMClient()
    gmusic_client = Mobileclient()
    gmusic_client.login(gmusic_email, gmusic_password)
   

    tracks= defaultdict(list)

    # get gmusic all songs
    gmusic_load =  gmusic_client.get_all_songs()
    for element in gmusic_load :
        rp_artist = element["artist"].encode('utf8').lower()
        rp_title = element["title"].encode('utf8').lower()
        tracks["gmusic"].append((rp_artist,rp_title))


    # get lastfm loves
    lastfm_likes = lastfm_client.liked_tracks(lastfm_user, lastfm_apikey)
    json_string = json.loads(lastfm_likes)
    for element in json_string["lovedtracks"]["track"]:
        rp_artist = element["artist"]["name"].encode('utf8').lower()
        rp_title = element["name"].encode('utf8').lower()
        tracks["lastfm"].append((rp_artist,rp_title))


    match = set(tracks["lastfm"]) & set(tracks["gmusic"])

    print "gmusic total"
    print sum(len(x) for x in tracks["gmusic"])

    print "Lastfm likes total"
    lastfm_like_count = sum(len(x) for x in tracks["lastfm"])
    print lastfm_like_count

    print "matched with gmusic"
    print sum(len(x) for x in match)

    print "not matched"
    print list(set(tracks["lastfm"]) - set(match))

    for element in gmusic_load:
        rp_artist = element["artist"].encode('utf8').lower()
        rp_title = element["title"].encode('utf8').lower()

        for element2 in match:
            if element2 == (rp_artist,rp_title):
                element['rating'] = '5'
                gmusic_client.change_song_metadata(element)
Example #22
0
def main():
    api = Mobileclient()
    print('login as {} to Google Music...'.format(CONFIG['login']))
    if api.login(CONFIG['login'], CONFIG['password'], CONFIG['device_id']):
        try:
            if not api.is_subscribed:
                raise AssertionError(
                    'You has not Google Music subscription :(')

            print('Reading all songs...')
            lib = api.get_all_songs()
            albums = CONFIG['albums']
            for artist in albums:
                print('Artist: {}'.format(artist))
                for album in albums[artist]:
                    print('Album: {}'.format(album))
                    tracks = sorted([
                        t for t in lib
                        if t['album'] == album and t['artist'] == artist
                    ],
                                    key=lambda t: t['trackNumber'])
                    if tracks:
                        dir_name = os.path.join(
                            CONFIG['root_dir'], fix_file_name(artist),
                            "{} {}".format(tracks[0]['year'],
                                           fix_file_name(album)))
                        if not os.path.exists(dir_name):
                            os.makedirs(dir_name)
                        for tr in tracks:
                            if 'albumArtRef' in tr:
                                i = 0
                                for artRef in tr['albumArtRef']:
                                    img_file_name = 'cover.{}.jpg' if i else 'cover.jpg'
                                    full_path = os.path.join(
                                        dir_name, img_file_name)
                                    full_path = fix_path_name(full_path)
                                    if not os.path.exists(full_path):
                                        wget.download(artRef['url'], full_path)
                            file_name = '{:02d} {}.mp3'.format(
                                tr['trackNumber'], tr['title'])
                            file_name = fix_file_name(file_name)
                            full_path = os.path.join(dir_name, file_name)
                            if not os.path.exists(full_path):
                                url = api.get_stream_url(tr['id'])
                                wget.download(url, full_path)
                                update_tags(tr, full_path)
        finally:
            api.logout()
Example #23
0
class GoogleMusicClient(object):

    def __init__(self, email, password, device_id):
        self.api = Mobileclient()
        self.api.login(email, password)
        self.device_id = device_id

        self.playlists = []
        self.songs = {}

        self.player = Player()

    def update_library(self):
        self.songs = {song.get('nid'): song for song in self.api.get_all_songs()}

        self.playlists = [
            Playlist(name=playlist['name'].encode('utf-8'),
                     tracks=[track['trackId'] for track in playlist['tracks']])
            for playlist in self.api.get_all_user_playlist_contents()
        ]

    def play(self, item_type, item_index):
        if item_type == 'playlist':
            click.echo('playing {} {}'.format(item_type, self.playlists[int(item_index)].name))

    def queue(self, item_type, item_index):
        if item_type == 'playlist':
            for song in self.playlists[int(item_index)]:
                self.player.enqueue(song)

    def show(self, item_type, item_index):
        if item_type == 'playlist':
            playlist = self.playlists[int(item_index)]
            click.echo('showing {} {}'.format(item_type, playlist.name))
            for song in playlist.tracks:
                click.echo(self.songs[song])
        elif item_type == 'queue':
            for song in self.player.queue:
                click.echo(song)

    def list(self, item_type):
        if item_type == 'playlist':
            for i, playlist in enumerate(self.playlists):
                click.echo("[{}]\t{} ({})".format(i, playlist.name, len(playlist.tracks)))
        elif item_type == 'songs':
            click.echo(self.songs)
Example #24
0
def main():
    global waiting
    waiting = False
    mc = Mobileclient()
    mc.perform_oauth(storage_filepath='./oauth.cred')
    mc.oauth_login(device_id=mc.FROM_MAC_ADDRESS,
                   oauth_credentials='./oauth.cred')
    waiting = True
    thread = Thread(target=threaded_cursor, args=('Gathering Metadata', ))
    thread.start()
    library = mc.get_all_songs()
    years = {}

    for song in library:
        if 'year' in song:
            try:
                if not str(song['year']) in years:
                    years[str(song['year'])] = []

                if any(song['album'] in keys['album']
                       for keys in years[str(song['year'])]):
                    continue
                else:
                    if 'albumArtRef' in song:
                        d = {
                            'album': song['album'],
                            'artwork': song['albumArtRef'][0]['url']
                        }
                        years[str(song['year'])].append(d)
                    else:
                        if verbose:
                            print("No album art for {}".format(song))
            except KeyError:
                if verbose:
                    print("Key error {}".format(song))
        else:
            if verbose:
                print("No year for {}".format(song))

    # clean up songs with unknown year
    if '0' in years:
        del years['0']
    waiting = False
    thread.join()
    make_plot(years)
Example #25
0
    def analyse(self, device_id, artists_number):
        """The main method that analysis Google Play Music account,
        and returns results of parsing concert.ua

        :param device_id: str
        :param artists_number: int
        :return: results: list
        """

        api = Mobileclient()
        try:
            artists_number = int(artists_number)
            device_id = str(device_id)
        except ValueError:
            return -1
        api.oauth_login(str(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(artists_number)
        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'])

        results = []
        for artist in artists:
            parse_result = Parser().parse(artist)
            if parse_result:
                results.append(parse_result)

        return results
Example #26
0
def download_all(outdir: str = DEF_OUT_DR,
                 device_id: str = DEF_DEV_ID,
                 mac_addr: str = DEF_MAC_AD):

    mc = Mobileclient()
    mm = Musicmanager()

    mc.oauth_login(DEF_DEV_ID)
    mm.login(uploader_id=DEF_MAC_AD)

    songs = mc.get_all_songs()
    print(f'Downloading {len(songs)}')
    for song in songs:
        filename, audio = mm.download_song(song['id'])
        print(f'Downloading {song["id"]} : {filename}', flush=True)
        with open(f'{outdir}/{filename}', 'wb') as fh:
            fh.write(audio)
        with open(f'{outdir}/{filename}.meta', 'w') as fh:
            json.dump(song, fh, indent=2, sort_keys=True)
Example #27
0
    def get_library(mobile_client: Mobileclient) -> List[GpmTrack]:
        """
        Given an authenticated mobile client, return a list of GPM Tracks representing the users library

        Args:
            mobile_client (Mobileclient): Must be authenticated. Client is used to retrieve the library for the GPM
                user.

        Returns:
            List[GpmTrack]: A list of ``GpmTrack`` objects representing the user's library.

        """
        # Check if client isn't authenticated
        if not mobile_client.is_authenticated():
            raise UnauthenticatedClientException("Trying to get library with an unauthenticated mobile client")

        # Get the library as a list of dicts
        raw_tracks: List[dict] = mobile_client.get_all_songs()

        return [ApiWrapper.__map_dict_to_gpm_track(track) for track in raw_tracks]
Example #28
0
class GMusicClient:
    def __init__(self):
        """
        This connects to the google music server by requesting credentials.
        """
        self.api = Mobileclient()

        username = input('Type your Google Play Music email below.\n--> ')
        dir_path = os.path.dirname(
            os.path.realpath(__file__)) + '/.cache-gmusic-' + ''.join(
                filter(str.isalpha, username))
        # Check if already authenticated
        if (not os.path.isfile(dir_path)):
            self.api.perform_oauth(open_browser=True,
                                   storage_filepath=dir_path)

        # Attempt to log in; if fail, get new token.
        try:
            self.api.oauth_login(Mobileclient.FROM_MAC_ADDRESS)
        except:
            self.api.perform_oauth(open_browser=True,
                                   storage_filepath=dir_path)
            self.api.oauth_login(Mobileclient.FROM_MAC_ADDRESS)

        print('Connected to GMusic')

    def get_playlists(self):
        """
        Gets all the playlists in Google Play Music. Some may not actually
        have any music, but they will be processed anyways.
        """
        return Playlists(self.api.get_all_user_playlist_contents())

    def get_all(self):
        """
        Gets the entire Google library for adding to the
        """
        print('Requesting Google library')
        library = self.api.get_all_songs()
        print('Received Google library, we have', len(library), 'songs')
        return MusicLibrary(library)
def bestof(username, password):
    pass
    api = Mobileclient()
    api.login(username, password, Mobileclient.FROM_MAC_ADDRESS)

    library = api.get_all_songs()

    for year in range(2018, 2010, -1):
        songs = [s for s in library if 'year' in s and s['year'] == year]
        albums = set([(s['artist'], s['album']) for s in songs])

        plays = []
        for artist, album in albums:
            plays.append((sum([s['playCount'] if 'playCount' in s else 0 for s in songs if s['album'] == album]), artist, album)) 

        plays = sorted(plays, reverse=True)
        print('===== {} ====='.format(year))

        for play_count, artist, album in plays:
            print('{} - {} ({})'.format(artist, album, play_count))
        print()
Example #30
0
class Kotone:

    def __init__(self, device_id: str, cred_mc: oauth2client.client.OAuth2Credentials, cred_mm: oauth2client.client.OAuth2Credentials):
        self._mc = Mobileclient()
        if not self._mc.oauth_login(device_id, cred_mc):
            raise RuntimeError('Mobileclient login failed')
        self._mm = Musicmanager()
        if not self._mm.login(cred_mm, _UPLOADER_ID, _UPLOADER_NAME):
            raise RuntimeError('Musicmanager login failed')

    def get_songs(self):
        return self._mc.get_all_songs()

    def download_song(self, song_id: str) -> Tuple[str, bytes]:
        return self._mm.download_song(song_id)

    def stream_url(self, song_id: str) -> str:
        return self._mc.get_stream_url(song_id)

    def upload(self, paths):
        return self._mm.upload(paths)
Example #31
0
def home(request):

    sync = request.params.get('sync', None)
    api = Mobileclient()

    api.login(GOOGLE_EMAIL, GOOGLE_MUSIC_PASS, Mobileclient.FROM_MAC_ADDRESS)

    if os.path.isfile('songs.json') and not sync:
        f = open('songs.json', 'r')
        songs = f.read()
        songs = json.loads(songs)
    else:
        songs = api.get_all_songs()
        songs = list(reversed(resort_by_added(songs)))

        f = open('songs.json', 'w')
        f.write(json.dumps(songs, indent=4, separators=(',', ': ')))
        f.close()

    result = []
    back = timedelta(days=10)
    now = datetime.now()

    for track in songs:
        d = get_datetime(track['creationTimestamp'])
        if (now - d) < back:
            result.append({
                'name':
                track['title'],
                'url':
                api.get_stream_url(track['id'], GOOGLE_DEVICE_ID),
                'date':
                d.strftime("%a %d-%m-%Y %H:%M")
            })

    master = get_renderer('templates/master.pt').implementation()

    return {'song_list': result, 'title': "Song list", 'main': master}
Example #32
0
class GoogleMusic(Source):
    def __init__(self, library, username, password):
        Source.__init__(self, library, SourceType.GOOGLE)
        self.GOOGLE_DEVICE_ID = None

        print username
        print password

        self.client = Mobileclient()
        logged_in = self.client.login(username, password,
                                      Mobileclient.FROM_MAC_ADDRESS)
        print "Google logged in:", logged_in

        DList = self.client.get_registered_devices()
        self.GOOGLE_DEVICE_ID = DList[0]["id"]
        if self.GOOGLE_DEVICE_ID[:2] == '0x':
            self.GOOGLE_DEVICE_ID = self.GOOGLE_DEVICE_ID[2:]

        print self.GOOGLE_DEVICE_ID

        #>testing
        # self.get_stream_URL("47b9d52c-9d66-3ff2-94d4-3ae55c0d2acc")

    def get_stream_URL(self, song_id):
        return self.client.get_stream_url(song_id, self.GOOGLE_DEVICE_ID)

    def sync(self):
        gmusic_tracks = self.client.get_all_songs()
        for track in gmusic_tracks:
            art = ''
            try:
                art = track['albumArtRef'][0]['url']
            except KeyError:
                art = ''
            self.library.insert_track(track['title'], track['album'],
                                      track['artist'], self._source,
                                      str(track['id']), track['trackNumber'],
                                      art)
Example #33
0
def main():
    api = Mobileclient()
    print('login as {} to Google Music...'.format(CONFIG['login']))
    if api.login(CONFIG['login'], CONFIG['password'], CONFIG['device_id']):
        if not api.is_subscribed:
            raise AssertionError('You has not Google Music subscription :(')

        lib = api.get_all_songs()
        print('Reading all songs...')
        artist_album = {}
        for tr in lib:
            artist = tr['artist']
            album = tr['album']
            if artist not in artist_album:
                artist_album[artist] = [
                    album,
                ]
            if album not in artist_album[artist]:
                artist_album[artist] += [
                    album,
                ]

        print(json.dumps(artist_album, indent=2, ensure_ascii=False))
        api.logout()
Example #34
0
from gmusicapi import Mobileclient
import codecs

api = Mobileclient()

trackEntryStart = "sj#track"
trackPrefix = "'title'"
artistPrefix = "'artist'"
delim = ","

if not api.oauth_login(api.FROM_MAC_ADDRESS):
    api.perform_oauth()

response = str(api.get_all_songs())
index = 0

f = codecs.open("GPMLibraryParsed.txt", mode="w", encoding="utf-8")
result = ""

while index < len(response):
    if response.find(trackEntryStart, index) != -1:

        index = response.index(trackEntryStart, index)

        titleIndex = response.index(trackPrefix, index) + 10
        titleDelimIndex = response.index(delim, titleIndex) - 1

        artistIndex = response.index(artistPrefix, index) + 11
        artistDelimIndex = response.index(delim, artistIndex) - 1

        result = result + response[
Example #35
0
api = Mobileclient()
api.login(args.account, password, Mobileclient.FROM_MAC_ADDRESS)

print("Login successful")

print("Fetching all playlists")
googlePlayPlaylists = api.get_all_user_playlist_contents()

print("Fetching list of tracks for the playlist")
googlePlayPlaylistTrackList = [playlist['tracks'] for playlist in googlePlayPlaylists
                               if playlist['name'] == args.playlist][0]

googlePlayTrackIds = list(map(lambda x: x['trackId'], googlePlayPlaylistTrackList))

print("Fetching list of files in Google Play library")
allTracksInGooglePlayLibrary = api.get_all_songs()

print("Fetching track info for tracks in playlist")
tracksInGooglePlayPlaylist = [track for track in allTracksInGooglePlayLibrary
                              if track['id'] in googlePlayTrackIds]

googlePlayTrackInfos = \
    list(map(lambda x: {'artist': x['artist'], 'title': x['title'], 'comment': x['comment'], 'album': x['album']},
             tracksInGooglePlayPlaylist))

def googlePlayPlaylistContainsTrack(tags):
    for info in googlePlayTrackInfos:
        if 'ARTIST' in tags and 'TITLE' in tags and info['artist'] == tags['ARTIST'][0] and info['title'] == tags['TITLE'][0]:
                # TODO: remove track from infos
                googlePlayTrackInfos.remove(info)
                print("Found a match for: {} - {}".format(tags['ARTIST'][0], tags['TITLE'][0]))
Example #36
0
class GMusicSession(object):

    def __init__(self):
        super(GMusicSession, self).__init__()
        logger.info('Mopidy uses Google Music')
        self.api = Mobileclient()

    def login(self, username, password, deviceid):
        if self.api.is_authenticated():
            self.api.logout()
        try:
            self.api.login(username, password)
        except CallFailure as error:
            logger.error(u'Failed to login as "%s": %s', username, error)
        if self.api.is_authenticated():
            if deviceid is None:
                self.deviceid = self.get_deviceid(username, password)
            else:
                self.deviceid = deviceid
        else:
            return False

    def logout(self):
        if self.api.is_authenticated():
            return self.api.logout()
        else:
            return True

    def get_all_songs(self):
        if self.api.is_authenticated():
            return self.api.get_all_songs()
        else:
            return {}

    def get_stream_url(self, song_id):
        if self.api.is_authenticated():
            try:
                return self.api.get_stream_url(song_id, self.deviceid)
            except CallFailure as error:
                logger.error(u'Failed to lookup "%s": %s', song_id, error)

    def get_all_playlist_contents(self):
        if self.api.is_authenticated():
            return self.api.get_all_user_playlist_contents()
        else:
            return {}

    def get_shared_playlist_contents(self, shareToken):
        if self.api.is_authenticated():
            return self.api.get_shared_playlist_contents(shareToken)
        else:
            return {}

    def get_all_playlists(self):
        if self.api.is_authenticated():
            return self.api.get_all_playlists()
        else:
            return {}

    def get_deviceid(self, username, password):
        logger.warning(u'No mobile device ID configured. '
                       u'Trying to detect one.')
        webapi = Webclient(validate=False)
        webapi.login(username, password)
        devices = webapi.get_registered_devices()
        deviceid = None
        for device in devices:
            if device['type'] == 'PHONE' and device['id'][0:2] == u'0x':
                # Omit the '0x' prefix
                deviceid = device['id'][2:]
                break
        webapi.logout()
        if deviceid is None:
            logger.error(u'No valid mobile device ID found. '
                         u'Playing songs will not work.')
        else:
            logger.info(u'Using mobile device ID %s', deviceid)
        return deviceid

    def get_track_info(self, store_track_id):
        if self.api.is_authenticated():
            try:
                return self.api.get_track_info(store_track_id)
            except CallFailure as error:
                logger.error(u'Failed to get All Access track info: %s', error)

    def get_album_info(self, albumid, include_tracks=True):
        if self.api.is_authenticated():
            try:
                return self.api.get_album_info(albumid, include_tracks)
            except CallFailure as error:
                logger.error(u'Failed to get All Access album info: %s', error)
Example #37
0
def main():
    log.setLevel(logging.INFO)
    logging.getLogger('gmusicapi').setLevel(logging.INFO)
    
    cred_path = os.path.join(os.path.expanduser('~'), '.gmusic-sync')

    if not os.path.isfile(cred_path):
        raise NoCredentialException(
                    'No username/password was specified. No config file could '
                    'be found either. Try creating %s and specifying your '
                    'username/password there. Make sure to chmod 600.'
                    % cred_path)
    if not oct(os.stat(cred_path)[os.path.stat.ST_MODE]).endswith('00'):
        raise NoCredentialException(
                    'Config file is not protected. Please run: '
                    'chmod 600 %s' % cred_path)
    
    config = ConfigParser.ConfigParser()
    config.read(cred_path)

    src_user = config.get('src','username')
    src_pass = config.get('src','password')
    src_device = config.get('src','deviceid')

    dst_user = config.get('dst','username')
    dst_pass = config.get('dst','password')
    dst_device = config.get('dst','deviceid')

    if not src_user or not src_pass or not dst_user or not dst_pass:
        raise NoCredentialException(
                    'No username/password could be read from config file'
                    ': %s' % cred_path)
    if not src_device or not dst_device:
         raise NoCredentialException(
                    'No deviceId could be read from config file'
                    ': %s' % cred_path)

    parser = argparse.ArgumentParser(description='gmusic-sync', add_help=False)

    parser.add_argument('-a', '--add-songs', help='Add songs from the src account to the dst account', action='store_true', dest='add')
    parser.add_argument('-h', '--heuristics', help='Use heuristics to try and find missing songs. Songs must match artist and title to be considered a match.', action='store_true', dest='heuristics')
    parser.add_argument('-hs', '--strict-heuristics', help='Songs must match artist, album, and title to be considered a match.', action='store_true', dest='strict_heuristics')
    args = parser.parse_args()

    api = Mobileclient()
    api.login(src_user, src_pass, src_device)
    library = api.get_all_songs()

    api2 = Mobileclient()
    api2.login(dst_user, dst_pass, dst_device)
    library2 = api2.get_all_songs()

    aa_songs2 = []
    aa_diff = []
    
    for track in library2:
        try:
            if track['storeId'].startswith('T'):
                aa_songs2.append(track['storeId'])
        except KeyError:
            continue

    for track in library:
        try:
            if track['storeId'].startswith('T') :
                if track['storeId'] not in aa_songs2:
                    #aa_diff.append(track)
                    if args.add:
                        api2.add_aa_track(track['storeId'])
                        time.sleep(1) # sleep so Google doesn't banhammer you for spamming their servers
        except KeyError:
            continue
        except:
            #Track wasn't found in the dst database. See if we can match to an existing song or something
            #else from the store
            if args.heuristics:
                if heuristic_search(library2, track, args.strict_heuristics) is not None:
                    continue
                                    
            print 'ERROR ADDING: ' + track['title'] + ' - ' + track['artist'] + ' (' + track['album'] + ')' + ' (' + track['storeId'] + ')'
            aa_diff.append(track)
            continue

    print '----------------- TRACKS NOT IN DST --------------------'
    for track in aa_diff:
        print track['title'] + ' - ' + track['artist'] + ' (' + track['album'] + ')'
import sys
import getpass
from gmusicapi import Mobileclient


email = raw_input("User (gmail): ")
pswd = getpass.getpass("Password:"******"Authentification error"
    sys.exit()

songs = api.get_all_songs()

for song in songs:
    song["genre"] = song["genre"].replace(" ", "").lower()
    if ";" in song["genre"]:
        song["genre"] = song["genre"].split(";")
    elif "," in song["genre"]:
        song["genre"] = song["genre"].split(",")
    elif "/" in song["genre"]:
        song["genre"] = song["genre"].split("/")
    else:
        song["genre"] = [song["genre"]]

genres_map = {}
for s in songs:
    for g in s["genre"]:
        genres_map.setdefault(g, [])
Example #39
0
class GMusicClient(ContentConsumer):
    """Element in charge of interfacing with GMusicApi Client"""

    def __init__(self, data_cache):
        self.client = Mobileclient()
        self.data_cache = data_cache

    def login(self):
        """Use data/unlocked/credentials.json to log in"""
        mac = Mobileclient.FROM_MAC_ADDRESS
        try:
            credentials = json.load(open("data/unlocked/credentials.json", "r"))
            result = self.client.login(credentials["username"], credentials["password"], mac)
            if result == False:
                print("\n\033[93mLogin failed.")
                print("Please double check that data/unlocked/credentials.json has correct information.\033[m\n")
                os._exit(1)
        except:
            print("\n\033[93mdata/unlocked/credentials.json is not valid.")
            print("You may need to delete and regnerate the credentials file.\033[m\n")
            exit(1)

    def load_my_library(self):
        """Load user's songs, playlists, and stations"""
        track_load = threading.Thread(target=self.load_tracks)
        radio_load = threading.Thread(target=self.load_radios)
        playlist_load = threading.Thread(target=self.load_playlists)

        track_load.start()
        radio_load.start()
        playlist_load.start()

        track_load.join()
        radio_load.join()
        playlist_load.join()

    def load_playlists(self):
        playlists = self.client.get_all_user_playlist_contents()
        playlists.reverse()
        self.data_cache.playlists = playlists

    def load_tracks(self):
        self.data_cache.tracks = [t for t in self.client.get_all_songs() if "nid" in t]

    def scrape_song(self, track):
        return track

    def load_radios(self):
        radios = self.client.get_all_stations()
        radios.reverse()
        self.data_cache.radios = radios

    def get_radio_contents(self, radio_id):
        tracks = self.client.get_station_tracks(radio_id)
        return tracks

    def get_radio_list(self, name):
        return [r for r in self.data_cache.radios if name in r["name"]]

    def filter(self, element, field, filter_by):
        return [e for e in element if filter_by in e[field]]

    def get_playlist_list(self, name):
        return self.filter(self.data_cache.playlists, "name", name)

    def search_all_access(self, query):
        return self.client.search_all_access(query)

    def create_radio(self, seed_type, id, name):
        """Create a radio"""
        # This is a weird way to do this, but there's no other choice
        ids = {"track": None, "album": None, "artist": None}
        seed_id_name = self.get_type_name(seed_type)
        ids[seed_id_name] = id
        return self.client.create_station(
            name=name, track_id=ids["track"], album_id=ids["album"], artist_id=ids["artist"]
        )

    def search_items_all_access(self, type, query):
        """Searches Albums, Artists, and Songs; uses metaprogramming"""
        index_arguments = self.get_index_arguments(type)

        items = self.search_all_access(query)["{0}_hits".format(type[:-1])]
        return [self.format_item(item, type, index_arguments) for item in items]

    def get_sub_items(self, type_from, search_type, from_id):
        """Here type_from refers to artist or album we're indexing against"""
        args = self.get_index_arguments(search_type)

        if type_from == "playlist":
            return self.get_playlist_contents(from_id)

        else:
            # Get the appropriate search method and execute it
            search_method_name = "get_{0}_info".format(type_from)
            search_method = getattr(self.client, search_method_name)
            try:
                items = search_method(from_id, True)[args["type"] + "s"]  # True here includes subelements
            except:
                # User passed in a bad id or something
                return

        # Now return appropriately
        return [self.format_subitems(t, args) for t in items if args["id"] in t]

    def get_playlist_contents(self, from_id):
        """Playlist exclusive stuff"""
        shareToken = [t for t in self.data_cache.playlists if t["id"] == from_id][0]["shareToken"]

        contents = self.client.get_shared_playlist_contents(shareToken)
        return [self.format_playlist_contents(t) for t in contents if "track" in t]

    def get_suggested(self):
        """Returns a list of tracks that the user might be interested in"""
        items = sorted(self.client.get_promoted_songs(), key=lambda y: y["title"])
        return [self.format_suggested(t) for t in items if "storeId" in t]

    def get_information_about(self, from_type, from_id):
        """Gets specific information about an id (depending on the type)"""
        if "artist" in from_type.lower():
            return self.client.get_artist_info(from_id, include_albums=False)
        if "album" in from_type.lower():
            return self.client.get_album_info(from_id, include_tracks=False)
        return self.client.get_track_info(from_id)

    def get_stream_url(self, nid):
        return self.client.get_stream_url(nid)

    def lookup(self, nid):
        return self.client.get_track_info(nid)

    def add_track_to_library(self, nid):
        self.client.add_aa_track(nid)

    def add_to_playlist(self, playlist_id, nid):
        self.client.add_songs_to_playlist(playlist_id, nid)

        playlist_load = threading.Thread(target=self.load_playlists)
        playlist_load.daemon = True
        playlist_load.start()

    def format_suggested(self, t):
        return (t["title"], t["storeId"], "Play", t["album"])

    def format_playlist_contents(self, t):
        return (t["track"]["title"], t["trackId"], "Play", t["track"]["album"])

    def format_subitems(self, t, args):
        return (t[args["name"]], t[args["id"]], args["command"], t[args["alt"]])
Example #40
0
class tizgmusicproxy(object):
    """A class for logging into a Google Play Music account and retrieving song
    URLs.

    """

    all_songs_album_title = "All Songs"
    thumbs_up_playlist_name = "Thumbs Up"

    def __init__(self, email, password, device_id):
        self.__gmusic = Mobileclient()
        self.__email = email
        self.__device_id = device_id
        self.logged_in = False
        self.queue = list()
        self.queue_index = -1
        self.play_queue_order = list()
        self.play_modes = TizEnumeration(["NORMAL", "SHUFFLE"])
        self.current_play_mode = self.play_modes.NORMAL
        self.now_playing_song = None

        userdir = os.path.expanduser('~')
        tizconfig = os.path.join(userdir, ".config/tizonia/." + email + ".auth_token")
        auth_token = ""
        if os.path.isfile(tizconfig):
            with open(tizconfig, "r") as f:
                auth_token = pickle.load(f)
                if auth_token:
                    # 'Keep track of the auth token' workaround. See:
                    # https://github.com/diraimondo/gmusicproxy/issues/34#issuecomment-147359198
                    print_msg("[Google Play Music] [Authenticating] : " \
                              "'with cached auth token'")
                    self.__gmusic.android_id = device_id
                    self.__gmusic.session._authtoken = auth_token
                    self.__gmusic.session.is_authenticated = True
                    try:
                        self.__gmusic.get_registered_devices()
                    except CallFailure:
                        # The token has expired. Reset the client object
                        print_wrn("[Google Play Music] [Authenticating] : " \
                                  "'auth token expired'")
                        self.__gmusic = Mobileclient()
                        auth_token = ""

        if not auth_token:
            attempts = 0
            print_nfo("[Google Play Music] [Authenticating] : " \
                      "'with user credentials'")
            while not self.logged_in and attempts < 3:
                self.logged_in = self.__gmusic.login(email, password, device_id)
                attempts += 1

            with open(tizconfig, "a+") as f:
                f.truncate()
                pickle.dump(self.__gmusic.session._authtoken, f)

        self.library = CaseInsensitiveDict()
        self.song_map = CaseInsensitiveDict()
        self.playlists = CaseInsensitiveDict()
        self.stations = CaseInsensitiveDict()

    def logout(self):
        """ Reset the session to an unauthenticated, default state.

        """
        self.__gmusic.logout()

    def set_play_mode(self, mode):
        """ Set the playback mode.

        :param mode: curren tvalid values are "NORMAL" and "SHUFFLE"

        """
        self.current_play_mode = getattr(self.play_modes, mode)
        self.__update_play_queue_order()

    def current_song_title_and_artist(self):
        """ Retrieve the current track's title and artist name.

        """
        logging.info("current_song_title_and_artist")
        song = self.now_playing_song
        if song:
            title = to_ascii(self.now_playing_song.get('title'))
            artist = to_ascii(self.now_playing_song.get('artist'))
            logging.info("Now playing %s by %s", title, artist)
            return artist, title
        else:
            return '', ''

    def current_song_album_and_duration(self):
        """ Retrieve the current track's album and duration.

        """
        logging.info("current_song_album_and_duration")
        song = self.now_playing_song
        if song:
            album = to_ascii(self.now_playing_song.get('album'))
            duration = to_ascii \
                       (self.now_playing_song.get('durationMillis'))
            logging.info("album %s duration %s", album, duration)
            return album, int(duration)
        else:
            return '', 0

    def current_track_and_album_total(self):
        """Return the current track number and the total number of tracks in the
        album, if known.

        """
        logging.info("current_track_and_album_total")
        song = self.now_playing_song
        track = 0
        total = 0
        if song:
            try:
                track = self.now_playing_song['trackNumber']
                total = self.now_playing_song['totalTrackCount']
                logging.info("track number %s total tracks %s", track, total)
            except KeyError:
                logging.info("trackNumber or totalTrackCount : not found")
        else:
            logging.info("current_song_track_number_"
                         "and_total_tracks : not found")
        return track, total

    def current_song_year(self):
        """ Return the current track's year of publication.

        """
        logging.info("current_song_year")
        song = self.now_playing_song
        year = 0
        if song:
            try:
                year = song['year']
                logging.info("track year %s", year)
            except KeyError:
                logging.info("year : not found")
        else:
            logging.info("current_song_year : not found")
        return year

    def clear_queue(self):
        """ Clears the playback queue.

        """
        self.queue = list()
        self.queue_index = -1

    def enqueue_artist(self, arg):
        """ Search the user's library for tracks from the given artist and adds
        them to the playback queue.

        :param arg: an artist
        """
        try:
            self.__update_local_library()
            artist = None
            if arg not in self.library.keys():
                for name, art in self.library.iteritems():
                    if arg.lower() in name.lower():
                        artist = art
                        print_wrn("[Google Play Music] '{0}' not found. " \
                                  "Playing '{1}' instead." \
                                  .format(arg.encode('utf-8'), \
                                          name.encode('utf-8')))
                        break
                if not artist:
                    # Play some random artist from the library
                    random.seed()
                    artist = random.choice(self.library.keys())
                    artist = self.library[artist]
                    print_wrn("[Google Play Music] '{0}' not found. "\
                              "Feeling lucky?." \
                              .format(arg.encode('utf-8')))
            else:
                artist = self.library[arg]
            tracks_added = 0
            for album in artist:
                tracks_added += self.__enqueue_tracks(artist[album])
            print_wrn("[Google Play Music] Playing '{0}'." \
                      .format(to_ascii(artist)))
            self.__update_play_queue_order()
        except KeyError:
            raise KeyError("Artist not found : {0}".format(arg))

    def enqueue_album(self, arg):
        """ Search the user's library for albums with a given name and adds
        them to the playback queue.

        """
        try:
            self.__update_local_library()
            album = None
            artist = None
            tentative_album = None
            tentative_artist = None
            for library_artist in self.library:
                for artist_album in self.library[library_artist]:
                    print_nfo("[Google Play Music] [Album] '{0}'." \
                              .format(to_ascii(artist_album)))
                    if not album:
                        if arg.lower() == artist_album.lower():
                            album = artist_album
                            artist = library_artist
                            break
                    if not tentative_album:
                        if arg.lower() in artist_album.lower():
                            tentative_album = artist_album
                            tentative_artist = library_artist
                if album:
                    break

            if not album and tentative_album:
                album = tentative_album
                artist = tentative_artist
                print_wrn("[Google Play Music] '{0}' not found. " \
                          "Playing '{1}' instead." \
                          .format(arg.encode('utf-8'), \
                          album.encode('utf-8')))
            if not album:
                # Play some random album from the library
                random.seed()
                artist = random.choice(self.library.keys())
                album = random.choice(self.library[artist].keys())
                print_wrn("[Google Play Music] '{0}' not found. "\
                          "Feeling lucky?." \
                          .format(arg.encode('utf-8')))

            if not album:
                raise KeyError("Album not found : {0}".format(arg))

            self.__enqueue_tracks(self.library[artist][album])
            print_wrn("[Google Play Music] Playing '{0}'." \
                      .format(to_ascii(album)))
            self.__update_play_queue_order()
        except KeyError:
            raise KeyError("Album not found : {0}".format(arg))

    def enqueue_playlist(self, arg):
        """Search the user's library for playlists with a given name
        and adds the tracks of the first match to the playback queue.

        Requires Unlimited subscription.

        """
        try:
            self.__update_local_library()
            self.__update_playlists()
            self.__update_playlists_unlimited()
            playlist = None
            playlist_name = None
            for name, plist in self.playlists.items():
                print_nfo("[Google Play Music] [Playlist] '{0}'." \
                          .format(to_ascii(name)))
            if arg not in self.playlists.keys():
                for name, plist in self.playlists.iteritems():
                    if arg.lower() in name.lower():
                        playlist = plist
                        playlist_name = name
                        print_wrn("[Google Play Music] '{0}' not found. " \
                                  "Playing '{1}' instead." \
                                  .format(arg.encode('utf-8'), \
                                          to_ascii(name)))
                        break
                if not playlist:
                    # Play some random playlist from the library
                    random.seed()
                    playlist_name = random.choice(self.playlists.keys())
                    playlist = self.playlists[playlist_name]
                    print_wrn("[Google Play Music] '{0}' not found. "\
                              "Feeling lucky?." \
                              .format(arg.encode('utf-8')))
            else:
                playlist_name = arg
                playlist = self.playlists[arg]

            self.__enqueue_tracks(playlist)
            print_wrn("[Google Play Music] Playing '{0}'." \
                      .format(to_ascii(playlist_name)))
            self.__update_play_queue_order()
        except KeyError:
            raise KeyError("Playlist not found : {0}".format(arg))

    def enqueue_station_unlimited(self, arg):
        """Search the user's library for a station with a given name
        and add its tracks to the playback queue.

        Requires Unlimited subscription.

        """
        try:
            # First try to find a suitable station in the user's library
            self.__enqueue_user_station_unlimited(arg)

            if not len(self.queue):
                # If no suitable station is found in the user's library, then
                # search google play unlimited for a potential match.
                self.__enqueue_station_unlimited(arg)

            if not len(self.queue):
                raise KeyError

        except KeyError:
            raise KeyError("Station not found : {0}".format(arg))

    def enqueue_genre_unlimited(self, arg):
        """Search Unlimited for a genre with a given name and add its
        tracks to the playback queue.

        Requires Unlimited subscription.

        """
        print_msg("[Google Play Music] [Retrieving genres] : '{0}'. " \
                  .format(self.__email))

        try:
            all_genres = list()
            root_genres = self.__gmusic.get_genres()
            second_tier_genres = list()
            for root_genre in root_genres:
                second_tier_genres += self.__gmusic.get_genres(root_genre['id'])
            all_genres += root_genres
            all_genres += second_tier_genres
            for genre in all_genres:
                print_nfo("[Google Play Music] [Genre] '{0}'." \
                          .format(to_ascii(genre['name'])))
            genre = dict()
            if arg not in all_genres:
                genre = next((g for g in all_genres \
                              if arg.lower() in to_ascii(g['name']).lower()), \
                             None)

            tracks_added = 0
            while not tracks_added:
                if not genre and len(all_genres):
                    # Play some random genre from the search results
                    random.seed()
                    genre = random.choice(all_genres)
                    print_wrn("[Google Play Music] '{0}' not found. "\
                              "Feeling lucky?." \
                              .format(arg.encode('utf-8')))

                genre_name = genre['name']
                genre_id = genre['id']
                station_id = self.__gmusic.create_station(genre_name, \
                                                          None, None, None, genre_id)
                num_tracks = 200
                tracks = self.__gmusic.get_station_tracks(station_id, num_tracks)
                tracks_added = self.__enqueue_tracks(tracks)
                logging.info("Added %d tracks from %s to queue", tracks_added, genre_name)
                if not tracks_added:
                    # This will produce another iteration in the loop
                    genre = None

            print_wrn("[Google Play Music] Playing '{0}'." \
                      .format(to_ascii(genre['name'])))
            self.__update_play_queue_order()
        except KeyError:
            raise KeyError("Genre not found : {0}".format(arg))
        except CallFailure:
            raise RuntimeError("Operation requires an Unlimited subscription.")

    def enqueue_situation_unlimited(self, arg):
        """Search Unlimited for a situation with a given name and add its
        tracks to the playback queue.

        Requires Unlimited subscription.

        """
        print_msg("[Google Play Music] [Retrieving situations] : '{0}'. " \
                  .format(self.__email))

        try:

            self.__enqueue_situation_unlimited(arg)

            if not len(self.queue):
                raise KeyError

            logging.info("Added %d tracks from %s to queue", \
                         len(self.queue), arg)

        except KeyError:
            raise KeyError("Situation not found : {0}".format(arg))
        except CallFailure:
            raise RuntimeError("Operation requires an Unlimited subscription.")

    def enqueue_artist_unlimited(self, arg):
        """Search Unlimited for an artist and adds the artist's 200 top tracks to the
        playback queue.

        Requires Unlimited subscription.

        """
        try:
            artist = self.__gmusic_search(arg, 'artist')

            include_albums = False
            max_top_tracks = 200
            max_rel_artist = 0
            artist_tracks = dict()
            if artist:
                artist_tracks = self.__gmusic.get_artist_info \
                                (artist['artist']['artistId'],
                                 include_albums, max_top_tracks,
                                 max_rel_artist)['topTracks']
            if not artist_tracks:
                raise KeyError

            tracks_added = self.__enqueue_tracks(artist_tracks)
            logging.info("Added %d tracks from %s to queue", \
                         tracks_added, arg)
            self.__update_play_queue_order()
        except KeyError:
            raise KeyError("Artist not found : {0}".format(arg))
        except CallFailure:
            raise RuntimeError("Operation requires an Unlimited subscription.")

    def enqueue_album_unlimited(self, arg):
        """Search Unlimited for an album and add its tracks to the
        playback queue.

        Requires Unlimited subscription.

        """
        try:
            album = self.__gmusic_search(arg, 'album')
            album_tracks = dict()
            if album:
                album_tracks = self.__gmusic.get_album_info \
                               (album['album']['albumId'])['tracks']
            if not album_tracks:
                raise KeyError

            print_wrn("[Google Play Music] Playing '{0}'." \
                      .format((album['album']['name']).encode('utf-8')))

            tracks_added = self.__enqueue_tracks(album_tracks)
            logging.info("Added %d tracks from %s to queue", \
                         tracks_added, arg)
            self.__update_play_queue_order()
        except KeyError:
            raise KeyError("Album not found : {0}".format(arg))
        except CallFailure:
            raise RuntimeError("Operation requires an Unlimited subscription.")

    def enqueue_tracks_unlimited(self, arg):
        """ Search Unlimited for a track name and adds all the matching tracks
        to the playback queue.

        Requires Unlimited subscription.

        """
        print_msg("[Google Play Music] [Retrieving library] : '{0}'. " \
                  .format(self.__email))

        try:
            max_results = 200
            track_hits = self.__gmusic.search(arg, max_results)['song_hits']
            if not len(track_hits):
                # Do another search with an empty string
                track_hits = self.__gmusic.search("", max_results)['song_hits']
                print_wrn("[Google Play Music] '{0}' not found. "\
                          "Feeling lucky?." \
                          .format(arg.encode('utf-8')))

            tracks = list()
            for hit in track_hits:
                tracks.append(hit['track'])
            tracks_added = self.__enqueue_tracks(tracks)
            logging.info("Added %d tracks from %s to queue", \
                         tracks_added, arg)
            self.__update_play_queue_order()
        except KeyError:
            raise KeyError("Playlist not found : {0}".format(arg))
        except CallFailure:
            raise RuntimeError("Operation requires an Unlimited subscription.")

    def enqueue_promoted_tracks_unlimited(self):
        """ Retrieve the url of the next track in the playback queue.

        """
        try:
            tracks = self.__gmusic.get_promoted_songs()
            count = 0
            for track in tracks:
                store_track = self.__gmusic.get_track_info(track['storeId'])
                if u'id' not in store_track.keys():
                    store_track[u'id'] = store_track['nid']
                self.queue.append(store_track)
                count += 1
            if count == 0:
                print_wrn("[Google Play Music] Operation requires " \
                          "an Unlimited subscription.")
            logging.info("Added %d Unlimited promoted tracks to queue", \
                         count)
            self.__update_play_queue_order()
        except CallFailure:
            raise RuntimeError("Operation requires an Unlimited subscription.")

    def next_url(self):
        """ Retrieve the url of the next track in the playback queue.

        """
        if len(self.queue):
            self.queue_index += 1
            if (self.queue_index < len(self.queue)) \
               and (self.queue_index >= 0):
                next_song = self.queue[self.play_queue_order[self.queue_index]]
                return self.__retrieve_track_url(next_song)
            else:
                self.queue_index = -1
                return self.next_url()
        else:
            return ''

    def prev_url(self):
        """ Retrieve the url of the previous track in the playback queue.

        """
        if len(self.queue):
            self.queue_index -= 1
            if (self.queue_index < len(self.queue)) \
               and (self.queue_index >= 0):
                prev_song = self.queue[self.play_queue_order[self.queue_index]]
                return self.__retrieve_track_url(prev_song)
            else:
                self.queue_index = len(self.queue)
                return self.prev_url()
        else:
            return ''

    def __update_play_queue_order(self):
        """ Update the queue playback order.

        A sequential order is applied if the current play mode is "NORMAL" or a
        random order if current play mode is "SHUFFLE"

        """
        total_tracks = len(self.queue)
        if total_tracks:
            if not len(self.play_queue_order):
                # Create a sequential play order, if empty
                self.play_queue_order = range(total_tracks)
            if self.current_play_mode == self.play_modes.SHUFFLE:
                random.shuffle(self.play_queue_order)
            print_nfo("[Google Play Music] [Tracks in queue] '{0}'." \
                      .format(total_tracks))

    def __retrieve_track_url(self, song):
        """ Retrieve a song url

        """
        song_url = self.__gmusic.get_stream_url(song['id'], self.__device_id)
        try:
            self.now_playing_song = song
            return song_url
        except AttributeError:
            logging.info("Could not retrieve the song url!")
            raise

    def __update_local_library(self):
        """ Retrieve the songs and albums from the user's library

        """
        print_msg("[Google Play Music] [Retrieving library] : '{0}'. " \
                  .format(self.__email))

        songs = self.__gmusic.get_all_songs()
        self.playlists[self.thumbs_up_playlist_name] = list()

        # Retrieve the user's song library
        for song in songs:
            if "rating" in song and song['rating'] == "5":
                self.playlists[self.thumbs_up_playlist_name].append(song)

            song_id = song['id']
            song_artist = song['artist']
            song_album = song['album']

            self.song_map[song_id] = song

            if song_artist == "":
                song_artist = "Unknown Artist"

            if song_album == "":
                song_album = "Unknown Album"

            if song_artist not in self.library:
                self.library[song_artist] = CaseInsensitiveDict()
                self.library[song_artist][self.all_songs_album_title] = list()

            if song_album not in self.library[song_artist]:
                self.library[song_artist][song_album] = list()

            self.library[song_artist][song_album].append(song)
            self.library[song_artist][self.all_songs_album_title].append(song)

        # Sort albums by track number
        for artist in self.library.keys():
            logging.info("Artist : %s", to_ascii(artist))
            for album in self.library[artist].keys():
                logging.info("   Album : %s", to_ascii(album))
                if album == self.all_songs_album_title:
                    sorted_album = sorted(self.library[artist][album],
                                          key=lambda k: k['title'])
                else:
                    sorted_album = sorted(self.library[artist][album],
                                          key=lambda k: k.get('trackNumber',
                                                              0))
                self.library[artist][album] = sorted_album

    def __update_stations_unlimited(self):
        """ Retrieve stations (Unlimited)

        """
        self.stations.clear()
        stations = self.__gmusic.get_all_stations()
        self.stations[u"I'm Feeling Lucky"] = 'IFL'
        for station in stations:
            station_name = station['name']
            logging.info("station name : %s", to_ascii(station_name))
            self.stations[station_name] = station['id']

    def __enqueue_user_station_unlimited(self, arg):
        """ Enqueue a user station (Unlimited)

        """
        print_msg("[Google Play Music] [Station search "\
                  "in user's library] : '{0}'. " \
                  .format(self.__email))
        self.__update_stations_unlimited()
        station_name = arg
        station_id = None
        for name, st_id in self.stations.iteritems():
            print_nfo("[Google Play Music] [Station] '{0}'." \
                      .format(to_ascii(name)))
        if arg not in self.stations.keys():
            for name, st_id in self.stations.iteritems():
                if arg.lower() in name.lower():
                    station_id = st_id
                    station_name = name
                    break
        else:
            station_id = self.stations[arg]

        num_tracks = 200
        tracks = list()
        if station_id:
            try:
                tracks = self.__gmusic.get_station_tracks(station_id, \
                                                          num_tracks)
            except KeyError:
                raise RuntimeError("Operation requires an "
                                   "Unlimited subscription.")
            tracks_added = self.__enqueue_tracks(tracks)
            if tracks_added:
                if arg != station_name:
                    print_wrn("[Google Play Music] '{0}' not found. " \
                              "Playing '{1}' instead." \
                              .format(arg.encode('utf-8'), name.encode('utf-8')))
                logging.info("Added %d tracks from %s to queue", tracks_added, arg)
                self.__update_play_queue_order()
            else:
                print_wrn("[Google Play Music] '{0}' has no tracks. " \
                          .format(station_name))

        if not len(self.queue):
            print_wrn("[Google Play Music] '{0}' " \
                      "not found in the user's library. " \
                      .format(arg.encode('utf-8')))

    def __enqueue_station_unlimited(self, arg, max_results=200, quiet=False):
        """Search for a station and enqueue all of its tracks (Unlimited)

        """
        if not quiet:
            print_msg("[Google Play Music] [Station search in "\
                      "Google Play Music] : '{0}'. " \
                      .format(arg.encode('utf-8')))
        try:
            station_name = arg
            station_id = None
            station = self.__gmusic_search(arg, 'station', max_results, quiet)

            if station:
                station = station['station']
                station_name = station['name']
                seed = station['seed']
                seed_type = seed['seedType']
                track_id = seed['trackId'] if seed_type == u'2' else None
                artist_id = seed['artistId'] if seed_type == u'3' else None
                album_id = seed['albumId'] if seed_type == u'4' else None
                genre_id = seed['genreId'] if seed_type == u'5' else None
                playlist_token = seed['playlistShareToken'] if seed_type == u'8' else None
                curated_station_id = seed['curatedStationId'] if seed_type == u'9' else None
                num_tracks = max_results
                tracks = list()
                try:
                    station_id \
                        = self.__gmusic.create_station(station_name, \
                                                       track_id, \
                                                       artist_id, \
                                                       album_id, \
                                                       genre_id, \
                                                       playlist_token, \
                                                       curated_station_id)
                    tracks \
                        = self.__gmusic.get_station_tracks(station_id, \
                                                           num_tracks)
                except KeyError:
                    raise RuntimeError("Operation requires an "
                                       "Unlimited subscription.")
                tracks_added = self.__enqueue_tracks(tracks)
                if tracks_added:
                    if not quiet:
                        print_wrn("[Google Play Music] [Station] : '{0}'." \
                                  .format(station_name.encode('utf-8')))
                    logging.info("Added %d tracks from %s to queue", \
                                 tracks_added, arg.encode('utf-8'))
                    self.__update_play_queue_order()

        except KeyError:
            raise KeyError("Station not found : {0}".format(arg))

    def __enqueue_situation_unlimited(self, arg):
        """Search for a situation and enqueue all of its tracks (Unlimited)

        """
        print_msg("[Google Play Music] [Situation search in "\
                  "Google Play Music] : '{0}'. " \
                  .format(arg.encode('utf-8')))
        try:
            situation_hits = self.__gmusic.search(arg)['situation_hits']

            if not len(situation_hits):
                # Do another search with an empty string
                situation_hits = self.__gmusic.search("")['situation_hits']
                print_wrn("[Google Play Music] '{0}' not found. "\
                          "Feeling lucky?." \
                          .format(arg.encode('utf-8')))

            situation = next((hit for hit in situation_hits \
                              if 'best_result' in hit.keys()), None)

            num_tracks = 200
            if not situation and len(situation_hits):
                max_results = num_tracks / len(situation_hits)
                for hit in situation_hits:
                    situation = hit['situation']
                    print_nfo("[Google Play Music] [Situation] '{0} : {1}'." \
                              .format((hit['situation']['title']).encode('utf-8'),
                                      (hit['situation']['description']).encode('utf-8')))

                    self.__enqueue_station_unlimited(situation['title'], max_results, True)

            if not situation:
                raise KeyError

        except KeyError:
            raise KeyError("Situation not found : {0}".format(arg))

    def __enqueue_tracks(self, tracks):
        """ Add tracks to the playback queue

        """
        count = 0
        for track in tracks:
            if u'id' not in track.keys():
                track[u'id'] = track['nid']
            self.queue.append(track)
            count += 1
        return count

    def __update_playlists(self):
        """ Retrieve the user's playlists

        """
        plists = self.__gmusic.get_all_user_playlist_contents()
        for plist in plists:
            plist_name = plist['name']
            logging.info("playlist name : %s", to_ascii(plist_name))
            tracks = plist['tracks']
            tracks.sort(key=itemgetter('creationTimestamp'))
            self.playlists[plist_name] = list()
            for track in tracks:
                try:
                    song = self.song_map[track['trackId']]
                    self.playlists[plist_name].append(song)
                except IndexError:
                    pass

    def __update_playlists_unlimited(self):
        """ Retrieve shared playlists (Unlimited)

        """
        plists_subscribed_to = [p for p in self.__gmusic.get_all_playlists() \
                                if p.get('type') == 'SHARED']
        for plist in plists_subscribed_to:
            share_tok = plist['shareToken']
            playlist_items \
                = self.__gmusic.get_shared_playlist_contents(share_tok)
            plist_name = plist['name']
            logging.info("shared playlist name : %s", to_ascii(plist_name))
            self.playlists[plist_name] = list()
            for item in playlist_items:
                try:
                    song = item['track']
                    song['id'] = item['trackId']
                    self.playlists[plist_name].append(song)
                except IndexError:
                    pass

    def __gmusic_search(self, query, query_type, max_results=200, quiet=False):
        """ Search Google Play (Unlimited)

        """

        search_results = self.__gmusic.search(query, max_results)[query_type + '_hits']
        result = next((hit for hit in search_results \
                            if 'best_result' in hit.keys()), None)

        if not result and len(search_results):
            secondary_hit = None
            for hit in search_results:
                if not quiet:
                    print_nfo("[Google Play Music] [{0}] '{1}'." \
                              .format(query_type.capitalize(),
                                      (hit[query_type]['name']).encode('utf-8')))
                if query.lower() == \
                   to_ascii(hit[query_type]['name']).lower():
                    result = hit
                    break
                if query.lower() in \
                   to_ascii(hit[query_type]['name']).lower():
                    secondary_hit = hit
            if not result and secondary_hit:
                result = secondary_hit

        if not result and not len(search_results):
            # Do another search with an empty string
            search_results = self.__gmusic.search("")[query_type + '_hits']

        if not result and len(search_results):
            # Play some random result from the search results
            random.seed()
            result = random.choice(search_results)
            if not quiet:
                print_wrn("[Google Play Music] '{0}' not found. "\
                          "Feeling lucky?." \
                          .format(query.encode('utf-8')))

        return result
from gmusicapi import Mobileclient

client = Mobileclient()
assert client.login('*****@*****.**', PASSWORD, Mobileclient.FROM_MAC_ADDRESS)
tracks = client.get_all_songs()
genres_to_merge = {'Alternative Rock', 'Alt. Rock'}
playlist_track_ids = [t['id'] for t in tracks if t['genre'] in genres_to_merge]
print "Creating playlist with %d tracks" % len(playlist_track_ids)
playlist_id = client.create_playlist('Alt Rock')
client.add_songs_to_playlist(playlist_id, playlist_track_ids)
Example #42
0
class MusicLibrary(object):
    'Read information about your Google Music library'

    def __init__(self, username=None, password=None,
                 true_file_size=False, scan=True, verbose=0):
        self.verbose = False
        if verbose > 1:
            self.verbose = True

        self.__login_and_setup(username, password)

        self.__artists = {} # 'artist name' -> {'album name' : Album(), ...}
        self.__albums = [] # [Album(), ...]
        if scan:
            self.rescan()
        self.true_file_size = true_file_size

    def rescan(self):
        self.__artists = {} # 'artist name' -> {'album name' : Album(), ...}
        self.__albums = [] # [Album(), ...]
        self.__aggregate_albums()

    def __login_and_setup(self, username=None, password=None):
        # If credentials are not specified, get them from $HOME/.gmusicfs
        if not username or not password:
            cred_path = os.path.join(os.path.expanduser('~'), '.gmusicfs')
            if not os.path.isfile(cred_path):
                raise NoCredentialException(
                    'No username/password was specified. No config file could '
                    'be found either. Try creating %s and specifying your '
                    'username/password there. Make sure to chmod 600.'
                    % cred_path)
            if not oct(os.stat(cred_path)[os.path.stat.ST_MODE]).endswith('00'):
                raise NoCredentialException(
                    'Config file is not protected. Please run: '
                    'chmod 600 %s' % cred_path)
            self.config = ConfigParser.ConfigParser()
            self.config.read(cred_path)
            username = self.config.get('credentials','username')
            password = self.config.get('credentials','password')
            global deviceId
            deviceId = self.config.get('credentials','deviceId')
            if not username or not password:
                raise NoCredentialException(
                    'No username/password could be read from config file'
                    ': %s' % cred_path)
            if not deviceId:
                raise NoCredentialException(
                    'No deviceId could be read from config file'
                    ': %s' % cred_path)

        self.api = GoogleMusicAPI(debug_logging=self.verbose)
        log.info('Logging in...')
        self.api.login(username, password)
        log.info('Login successful.')

    def __aggregate_albums(self):
        'Get all the tracks in the library, parse into artist and album dicts'
        all_artist_albums = {} # 'Artist|||Album' -> Album()
        log.info('Gathering track information...')
        tracks = self.api.get_all_songs()
        for track in tracks:
            # Prefer the album artist over the track artist if there is one:
            artist = formatNames(track['albumArtist'].lower())
            if artist.strip() == '':
                artist = formatNames(track['artist'].lower())
            # Get the Album object if it already exists:
            key = '%s|||%s' % (formatNames(artist), formatNames(track['album'].lower()))
            album = all_artist_albums.get(key, None)
            if not album:
                # New Album
                if artist == '':
                    artist = 'unknown'
                album = all_artist_albums[key] = Album(
                    self, formatNames(track['album'].lower()))
                self.__albums.append(album)
                artist_albums = self.__artists.get(artist, None)
                if artist_albums:
                    artist_albums[formatNames(album.normtitle)] = album
                else:
                    self.__artists[artist] = {album.normtitle: album}
                    artist_albums = self.__artists[artist]
            album.add_track(track)
        log.debug('%d tracks loaded.' % len(tracks))
        log.debug('%d artists loaded.' % len(self.__artists))
        log.debug('%d albums loaded.' % len(self.__albums))

    def get_artists(self):
        return self.__artists

    def get_albums(self):
        return self.__albums

    def get_artist_albums(self, artist):
        log.debug(artist)
        return self.__artists[artist]

    def cleanup(self):
        pass
Example #43
0
    def handle(self, *args, **options):
        if GPLAY_PASS == "" or GPLAY_USER == "":
            self.stdout.write('Credentials not set up. Please edit settings.py')
            return

        api = Mobileclient()
        if not api.login(GPLAY_USER,GPLAY_PASS):
            self.stdout.write('Incorrect credentials, login failed')
            return

        self.stdout.write('Connected to Google Music, downloading data...')
        #library = []
        library = api.get_all_songs()
        self.stdout.write('Data downloaded!')
        self.stdout.write('Clearing DB...')
        cursor = connection.cursor()
        # This can take a long time using ORM commands on the Pi, so lets Truncate
        cursor.execute('DELETE FROM ' + Track._meta.db_table)
        cursor.execute('DELETE FROM ' + Album._meta.db_table)
        cursor.execute('DELETE FROM ' + Artist._meta.db_table)
        cursor.execute('DELETE FROM ' + Playlist._meta.db_table)
        cursor.execute('DELETE FROM ' + PlaylistConnection._meta.db_table)
        self.stdout.write('Parsing new data...')

        # Easier to keep track of who we've seen like this...
        artists = []
        albums = []
        count = len(library)
        self.stdout.write(str(count) + ' tracks found')
        i = 0
        for song in library:
            i = i + 1
            track = Track()

            if song['albumArtist'] == "":
                if song['artist'] == "":
                    a = "Unknown Artist"
                else:
                    a = song['artist']
            else:
                a = song['albumArtist']

            if a not in artists:
                artist = Artist()
                artist.name = a

                try:
                    artist.art_url = song['artistArtRef'][0]['url']
                except:
                    print "No Art found."
                artist.save()
                artists.append(a)
                self.stdout.write('Added artist: ' + a)
                self.stdout.write(str(i) + '/' + str(count) + ' tracks completed')
            else:
                artist = Artist.objects.get(name=a)
            track.artist = artist

            if song['album'] + a not in albums:
                album = Album()
                album.name = song['album']
                album.artist = artist
                try:
                    album.year = song['year']
                except:
                    pass

                try:
                    album.art_url = song['albumArtRef'][0]['url']
                except:
                    print "No Art found."
                album.save()
                albums.append(song['album'] + a)
            else:
                album = Album.objects.get(name=song['album'], artist=artist)
            track.album = album

            track.name = song['title']
            track.stream_id = song['id']
            try:
                track.track_no = song['trackNumber']
            except:
                track.track_no = 0
            track.save()

        self.stdout.write('All tracks saved!')
        self.stdout.write('Getting Playlists...')
        
        self.stdout.write('Saving playlists...')

        self.stdout.write('Getting playlist contents.')
        playlists = api.get_all_user_playlist_contents()
        for playlist in playlists:
            p = Playlist()
            p.pid = playlist['id']
            p.name = playlist['name']
            p.save()
            for entry in playlist['tracks']:
                try:
                    track = Track.objects.get(stream_id=entry['trackId'])
                    pc = PlaylistConnection()
                    pc.playlist = p
                    pc.track = track
                    pc.save()
                except Exception:
                    print "Not found."

        self.stdout.write('Library saved!')
Example #44
0
 def fetch(self):
     client = Mobileclient()
     assert client.login(USER, PASSWORD, Mobileclient.FROM_MAC_ADDRESS)
     self.data = client.get_all_songs()
Example #45
0
class GPMClient(object):
    """
    Google Play Music client.
    """

    all_songs_album_title = "All Songs"
    thumbs_up_playlist_name = "Thumbs Up"

#------------------------------------------------------------------------------

    def __init__(self, email, password, device_id):
        self.__api = Mobileclient()
        self.logged_in = False
        self.__device_id = device_id

        attempts = 0
        while not self.logged_in and attempts < 3:
            self.logged_in = self.__api.login(email, password, device_id)
            attempts += 1

        self.all_tracks = dict()
        self.playlists = dict()
        self.library = dict()

#------------------------------------------------------------------------------

    def logout(self):
        self.__api.logout()

#------------------------------------------------------------------------------

    def update_local_lib(self):
        songs = self.__api.get_all_songs()
        self.playlists[self.thumbs_up_playlist_name] = list()

        # Get main library
        song_map = dict()
        for song in songs:
            if "rating" in song and song["rating"] == "5":
                self.playlists[self.thumbs_up_playlist_name].append(song)

            song_id = song["id"]
            song_artist = song["artist"]
            song_album = song["album"]

            song_map[song_id] = song

            if song_artist == "":
                song_artist = "Unknown Artist"

            if song_album == "":
                song_album = "Unknown Album"

            if song_artist not in self.library:
                self.library[song_artist] = dict()
                self.library[song_artist][self.all_songs_album_title] = list()

            if song_album not in self.library[song_artist]:
                self.library[song_artist][song_album] = list()

            self.library[song_artist][song_album].append(song)
            self.library[song_artist][self.all_songs_album_title].append(song)

        # Sort albums by track number
        for artist in self.library.keys():
            for album in self.library[artist].keys():
                if album == self.all_songs_album_title:
                    sorted_album = sorted(self.library[artist][album],
                                          key=lambda k: k['title'])
                else:
                    sorted_album = sorted(self.library[artist][album],
                                          key=lambda k: k.get('trackNumber', 0))
                self.library[artist][album] = sorted_album

        # Get all playlists
        plists = self.__api.get_all_user_playlist_contents()
        for plist in plists:
            plist_name = plist["name"]
            self.playlists[plist_name] = list()
            for track in plist["tracks"]:
                if track["trackId"] not in song_map:
                    song = song_map[track["trackId"]] = track["track"]
                    song["id"] = track["trackId"]
                else:
                    song = song_map[track["trackId"]]
                self.playlists[plist_name].append(song)

#------------------------------------------------------------------------------

    def get_stream_url(self, song):
        return self.__api.get_stream_url(song["id"], self.__device_id)

#------------------------------------------------------------------------------

    def rate_song(self, song, rating):
        try:
            song["rating"] = rating
            song_list = [song]
            self.__api.change_song_metadata(song_list)
            print "Gave a Thumbs Up to {0} by {1} on Google Play.".format(
                   song["title"].encode("utf-8"),
                   song["artist"].encode("utf-8"))
        except RuntimeError:
            print "Error giving a Thumbs Up on Google Play."
Example #46
0
    if len(pl) == 1:
        playlist = pl[0]

    print 'Analysing playlist: %s' % playlist['name']

if not playlist:
    print 'Playlist ID or name are required.'
    for p in pl:
        print '%20s - %s' % (p['id'], p['name'])
    sys.exit(1)

if 'tracks' not in playlist:
    print 'No tracks found!'
    sys.exit(1)

songs = mc.get_all_songs()
titles = {x['id']: x for x in songs}

for t in playlist['tracks']:
    if 'track' not in t:
      info = titles[t['trackId']]
      print ">>> %31.29s / %.20s / \"%.30s\"" % (info['album'], info['artist'], info['title'])
    else:
      info = t['track']
      print "%35.33s / %.20s / \"%.30s\"" % (info['album'], info['artist'], info['title'])

missing = []
for t in playlist['tracks']:
    if 'track' not in t:
      info = titles[t['trackId']]
    if 'nid' not in t or t['nid'][0] != 'T':
#Create the mobile client
#No debug logging, validate, and verify SSL
api = Mobileclient(False,True,True)

#Login
#api.perform_oauth('C:\\Users\\Joshv\\Josh\\Programming\\Python\\googleMusic\\gMusicDeviceID.txt')
api.oauth_login('b83fce595c6fd82bcfcfdd8e2e542d79f3c176bb0974c4bb34da2df10d95cec1')

#Retrieve all playlists
playlists = api.get_all_playlists(False, False)

#Retrive the contents of all playlists
playlistContents = api.get_all_user_playlist_contents()

#Get the entire song library
library = api.get_all_songs(False, False)

#Loop through all of the local playlists
for playlistFilePath in playlistFilePaths:
	#Create the array for the paths artists, tracks in the local playlist
	paths = []
	lArtists = []
	lTracks = []

	#Create arrays for the artists and tracks in the gmusic playlist
	gArtists = []
	gTracks = []

	#Get the playlist file name
	playlistFileName = os.path.basename(playlistFilePath)
	playlistName = os.path.splitext(playlistFileName)[0]
Example #48
0
class MusicLibrary(object):
    """This class reads information about your Google Play Music library"""

    def __init__(self, username=None, password=None,
                 true_file_size=False, scan=True, verbose=0):
        self.verbose = False
        if verbose > 1:
            self.verbose = True

        self.__login_and_setup(username, password)

        self.__artists = {}  # 'artist name' -> {'album name' : Album(), ...}
        self.__gartists = {}
        self.__albums = []  # [Album(), ...]
        self.__galbums = {}
        self.__tracks = {}
        self.__playlists = {}
        if scan:
            self.rescan()
        self.true_file_size = true_file_size

    def rescan(self):
        """Scan the Google Play Music library"""
        self.__artists = {}  # 'artist name' -> {'album name' : Album(), ...}
        self.__gartists = {}
        self.__albums = []  # [Album(), ...]
        self.__galbums = {}
        self.__tracks = {}
        self.__playlists = {}
        self.__aggregate_albums()

    def __login_and_setup(self, username=None, password=None):
        # If credentials are not specified, get them from $HOME/.gmusicfs
        if not username or not password:
            cred_path = os.path.join(os.path.expanduser('~'), '.gmusicfs')
            if not os.path.isfile(cred_path):
                raise NoCredentialException(
                    'No username/password was specified. No config file could '
                    'be found either. Try creating %s and specifying your '
                    'username/password there. Make sure to chmod 600.'
                    % cred_path)
            if not oct(os.stat(cred_path)[os.path.stat.ST_MODE]).endswith('00'):
                raise NoCredentialException(
                    'Config file is not protected. Please run: '
                    'chmod 600 %s' % cred_path)
            self.config = ConfigParser.ConfigParser()
            self.config.read(cred_path)
            username = self.config.get('credentials', 'username')
            password = self.config.get('credentials', 'password')
            global deviceId
            deviceId = self.config.get('credentials', 'deviceId')
            if not username or not password:
                raise NoCredentialException(
                    'No username/password could be read from config file'
                    ': %s' % cred_path)
            if not deviceId:
                raise NoCredentialException(
                    'No deviceId could be read from config file'
                    ': %s' % cred_path)
            if deviceId.startswith("0x"):
                deviceId = deviceId[2:]

        self.api = GoogleMusicAPI(debug_logging=self.verbose)
        log.info('Logging in...')
        self.api.login(username, password, deviceId)
        log.info('Login successful.')

    def __set_key_from_ginfo(self, track, ginfo, key, to_key=None):
        """Set track key from either album_info or artist_info"""
        if to_key is None:
            to_key = key

        try:
            int_key = int(key)
        except ValueError:
            int_key = None

        if (not track.has_key(key) or track[key] == "" or int_key == 0) and ginfo.has_key(to_key):
            track[key] = ginfo[to_key]

        return track

    def __aggregate_albums(self):
        """Get all the tracks and playlists in the library, parse into relevant dicts"""
        log.info('Gathering track information...')
        tracks = self.api.get_all_songs()
        for track in tracks:
            log.debug('track = %s' % pp.pformat(track))

            # Get album and artist information from Google
            if track.has_key('albumId'):
                if self.__galbums.has_key(track['albumId']):
                    album_info = self.__galbums[track['albumId']]
                else:
                    log.info("Downloading album info for %s '%s'", track['albumId'], track['album'])
                    try:
                        album_info = self.__galbums[track['albumId']] = self.api.get_album_info(track['albumId'], include_tracks=False)
                    except gmusicapi.exceptions.CallFailure:
                        log.exception("Failed to download album info for %s '%s'", track['albumId'], track['album'])
                        #album_info = {}
                if album_info.has_key('artistId') and len(album_info['artistId']) > 0 and album_info['artistId'][0] != "":
                    artist_id = album_info['artistId'][0]
                    if self.__gartists.has_key(artist_id):
                        artist_info = self.__gartists[artist_id]
                    else:
                        log.info("Downloading artist info for %s '%s'", artist_id, album_info['albumArtist'])
                        #if album_info['albumArtist'] == "Various":
                        #    print album_info
                        artist_info = self.__gartists[artist_id] = self.api.get_artist_info(artist_id, include_albums=False, max_top_tracks=0, max_rel_artist=0)
                else:
                    artist_info = {}
            else:
                album_info = {}
                artist_info = {}

            track = self.__set_key_from_ginfo(track, album_info, 'album', 'name')
            track = self.__set_key_from_ginfo(track, album_info, 'year')
            track = self.__set_key_from_ginfo(track, artist_info, 'albumArtist', 'name')

            # Prefer the album artist over the track artist if there is one
            artist_name = formatNames(track['albumArtist'])
            if artist_name.strip() == '':
                artist_name = formatNames(track['artist'])
            if artist_name.strip() == '':
                artist_name = 'Unknown'

            # Get the Artist object, or create one if it doesn't exist
            artist = self.__artists.get(artist_name.lower(), None)
            if not artist:
                artist = Artist(self, artist_name)
                self.__artists[artist_name.lower()] = artist

            # Get the Album object, or create one if it doesn't exist
            album = artist.get_album(formatNames(track['album']))
            if not album:
                album = Album(self, track['album'])
                self.__albums.append(album)  # NOTE: Current no purpose other than to count
                artist.add_album(album)

            # Add track to album
            album.add_track(track)

            # Add track to list of all tracks, indexable by track ID
            if 'id' in track:
                self.__tracks[track['id']] = track

        log.info('%d tracks loaded.' % len(tracks))
        log.info('%d artists loaded.' % len(self.__artists))
        log.info('%d albums loaded.' % len(self.__albums))

        # Add all playlists
        playlists = self.api.get_all_user_playlist_contents()
        for pldata in playlists:
            playlist = Playlist(self, pldata)
            self.__playlists[playlist.dirname.lower()] = playlist
        log.debug('%d playlists loaded.' % len(self.__playlists))

    def get_artists(self):
        """Return all artists in the library"""
        return self.__artists

    def get_artist(self, name):
        """Return the artist from the library with the specified name"""
        return self.__artists.get(name.lower(), None)

    def get_playlists(self):
        """Return list of all playlists in the library"""
        return self.__playlists.values()

    def get_playlist(self, name):
        """Return the playlist from the library with the specified name"""
        return self.__playlists.get(name.lower(), None)

    def get_track(self, trackid):
        """Return the track from the library with the specified track ID"""
        return self.__tracks.get(trackid, None)

    def cleanup(self):
        pass
Example #49
0
def main():
    log.setLevel(logging.INFO)
    logging.getLogger('gmusicapi').setLevel(logging.INFO)
    
    cred_path = os.path.join(os.path.expanduser('~'), '.gmusic-sync')

    if not os.path.isfile(cred_path):
        raise NoCredentialException(
                    'No username/password was specified. No config file could '
                    'be found either. Try creating %s and specifying your '
                    'username/password there. Make sure to chmod 600.'
                    % cred_path)
    if not oct(os.stat(cred_path)[os.path.stat.ST_MODE]).endswith('00'):
        raise NoCredentialException(
                    'Config file is not protected. Please run: '
                    'chmod 600 %s' % cred_path)
    
    config = ConfigParser.ConfigParser()
    config.read(cred_path)

    src_user = config.get('src','username')
    src_pass = config.get('src','password')
    src_device = config.get('src','deviceid')

    dst_user = config.get('dst','username')
    dst_pass = config.get('dst','password')
    dst_device = config.get('dst','deviceid')

    if not src_user or not src_pass or not dst_user or not dst_pass:
        raise NoCredentialException(
                    'No username/password could be read from config file'
                    ': %s' % cred_path)
    if not src_device or not dst_device:
         raise NoCredentialException(
                    'No deviceId could be read from config file'
                    ': %s' % cred_path)

    parser = argparse.ArgumentParser(description='gmusic-sync', add_help=False)

    parser.add_argument('-hs', '--strict-heuristics', help='Songs must match artist, album, and title to be considered a match.', action='store_true', dest='strict_heuristics')
    parser.add_argument('-e', '--exact', help='Copy the exact rating, instead of upgrading from 1-5 star ratings to Thumbs Up/Down', action='store_true', dest='exact')
    args = parser.parse_args()

    api = Mobileclient()
    api.login(src_user, src_pass, src_device)
    library = api.get_all_songs()

    api2 = Mobileclient()
    api2.login(dst_user, dst_pass, dst_device)
    library2 = api2.get_all_songs()

    failed_tracks = []
    rated_tracks = []

    #first, get all tracks in the library with a rating
    for track in library:
        try:
            if track['rating'] != '0' and track['lastRatingChangeTimestamp'] != '0':
                rated_tracks.append(track)
        except:
            #print 'ERROR: track did not contain rating key: ' + track_info_str(track)
            pass

    #sort the tracks by rating date
    rated_tracks.sort(key=operator.itemgetter('lastRatingChangeTimestamp'))

    for track in rated_tracks:
        print track_info_str(track)

    print 'TOTAL RATED TRACKS: ' + str(len(rated_tracks))

    for track in rated_tracks:
        try:
            if track['storeId'].startswith('T'):
                #It's a store track: does it exist in the target store?
                #Perform a store lookup: this will raise an exception if the track
                #Is not in the target store
                dst_track = api2.get_track_info(track['storeId'])
                #If we got here, the song is ready to be rated
                transfer_rating(api2, track, dst_track, args.exact)

            else:
                dst_track = heuristic_search(library2, track, args.strict_heuristics)
                if dst_track is not None:
                    transfer_rating(api2, track, dst_track, args.exact)
                else:
                    failed_tracks.append(track)
        except:
            #Not a store track: do heuristics lookup
            dst_track = heuristic_search(library2, track, args.strict_heuristics)
            if dst_track is not None:
                transfer_rating(api2, track, dst_track, args.exact)
            else:
                failed_tracks.append(track)
        #Absolutely must wait between ratings or we won't get valid timestamps
        time.sleep(2)

    print '----------------- FAILED TRACKS --------------------'
    for track in failed_tracks:
        print track_info_str(track)
Example #50
0
#!/usr/bin/env python

from gmusicapi import Mobileclient
from getpass import getpass

client = Mobileclient()
client.login( raw_input( "Username: "******"Getting all songs ..."
all_songs = client.get_all_songs()
new_songs = {}
old_songs = {}

for song in all_songs:
    song_id = song.get('id')
    timestamp = song.get('recentTimestamp')
    
    key = "%s: %d-%02d %s" % ( song.get('album'), song.get('discNumber'), song.get('trackNumber'), song.get('title') )
    
    if key in new_songs:
        if new_songs[key]['timestamp'] < timestamp:
            old_songs[key] = new_songs[key]
            new_songs[key] = { 'id': song_id, 'timestamp': timestamp }
        else:
            old_songs[key] = { 'id': song_id, 'timestamp': timestamp }
    
    new_songs[key] = { 'id': song_id, 'timestamp': timestamp }

if len( old_songs ):
    print "Duplicate songs"
    
Example #51
0
class GMusicWrapper(object):
    def __init__(self, username, password, logger=None):
        self._api = Mobileclient()
        self.logger = logger
        success = self._api.login(
            username, password,
            getenv('ANDROID_ID', Mobileclient.FROM_MAC_ADDRESS))

        if not success:
            raise Exception("Unsuccessful login. Aborting!")

        # Populate our library
        self.library = {}
        self.indexing_thread = threading.Thread(target=self.index_library)
        self.indexing_thread.start()

    def log(self, log_str):
        self.logger.debug(log_str)

    def _search(self, query_type, query):
        try:
            results = self._api.search(query)
        except CallFailure:
            return []

        hits_key = "%s_hits" % query_type

        if hits_key not in results:
            return []

        # Ugh, Google had to make this schema nonstandard...
        if query_type == 'song':
            query_type = 'track'

        return [x[query_type] for x in results[hits_key]]

    def is_indexing(self):
        return self.indexing_thread.is_alive()

    def index_library(self):
        """
        Downloads the a list of every track in a user's library and populates
        self.library with storeIds -> track definitions
        """
        self.log('Fetching library...')

        tracks = self.get_all_songs()

        for track in tracks:
            song_id = track['id']
            self.library[song_id] = track

        self.log('Fetching library...')

    def get_artist(self, name):
        """
        Fetches information about an artist given its name
        """
        search = self._search("artist", name)

        if len(search) == 0:
            return False

        return self._api.get_artist_info(search[0]['artistId'],
                                         max_top_tracks=100)

    def get_album(self, name, artist_name=None):
        if artist_name:
            name = "%s %s" % (name, artist_name)

        search = self._search("album", name)

        if len(search) == 0:
            return False

        return self._api.get_album_info(search[0]['albumId'])

    def get_latest_album(self, artist_name=None):
        search = self._search("artist", artist_name)

        if len(search) == 0:
            return False

        artist_info = self._api.get_artist_info(search[0]['artistId'],
                                                include_albums=True)
        album_info = artist_info['albums']
        sorted_list = sorted(album_info.__iter__(),
                             key=lambda s: s['year'],
                             reverse=True)

        for index, val in enumerate(sorted_list):
            album_info = self._api.get_album_info(
                album_id=sorted_list[index]['albumId'], include_tracks=True)
            if len(album_info['tracks']) >= 5:
                return album_info

        return False

    def get_album_by_artist(self, artist_name, album_id=None):
        search = self._search("artist", artist_name)
        if len(search) == 0:
            return False

        artist_info = self._api.get_artist_info(search[0]['artistId'],
                                                include_albums=True)
        album_info = artist_info['albums']
        random.shuffle(album_info)

        for index, val in enumerate(album_info):
            album = self._api.get_album_info(
                album_id=album_info[index]['albumId'], include_tracks=True)
            if album['albumId'] != album_id and len(album['tracks']) >= 5:
                return album

        return False

    def get_song(self, name, artist_name=None, album_name=None):
        if artist_name:
            name = "%s %s" % (artist_name, name)
        elif album_name:
            name = "%s %s" % (album_name, name)

        search = self._search("song", name)

        if len(search) == 0:
            return False

        if album_name:
            for i in range(0, len(search) - 1):
                if album_name in search[i]['album']:
                    return search[i]
        return search[0]

    def get_promoted_songs(self):
        return self._api.get_promoted_songs()

    def get_station(self, title, track_id=None, artist_id=None, album_id=None):
        if artist_id is not None:
            if album_id is not None:
                if track_id is not None:
                    return self._api.create_station(title, track_id=track_id)
                return self._api.create_station(title, album_id=album_id)
            return self._api.create_station(title, artist_id=artist_id)

    def get_station_tracks(self, station_id):
        return self._api.get_station_tracks(station_id)

    def get_google_stream_url(self, song_id):
        return self._api.get_stream_url(song_id)

    def get_stream_url(self, song_id):
        return "%s/alexa/stream/%s" % (getenv('APP_URL'), song_id)

    def get_thumbnail(self, artist_art):
        return artist_art.replace("http://", "https://")

    def get_all_user_playlist_contents(self):
        return self._api.get_all_user_playlist_contents()

    def get_all_songs(self):
        return self._api.get_all_songs()

    def rate_song(self, song, rating):
        return self._api.rate_songs(song, rating)

    def extract_track_info(self, track):
        # When coming from a playlist, track info is nested under the "track"
        # key
        if 'track' in track:
            track = track['track']

        if 'storeId' in track:
            return track, track['storeId']
        elif 'trackId' in track:
            return self.library[track['trackId']], track['trackId']
        else:
            return None, None

    def get_artist_album_list(self, artist_name):
        search = self._search("artist", artist_name)
        if len(search) == 0:
            return "Unable to find the artist you requested."

        artist_info = self._api.get_artist_info(search[0]['artistId'],
                                                include_albums=True)
        album_list_text = "Here's the album listing for %s: " % artist_name

        counter = 0
        for index, val in enumerate(artist_info['albums']):
            if counter > 25:  # alexa will time out after 10 seconds if the list takes too long to iterate through
                break
            album_info = self._api.get_album_info(
                album_id=artist_info['albums'][index]['albumId'],
                include_tracks=True)
            if len(album_info['tracks']) > 5:
                counter += 1
                album_list_text += (
                    artist_info['albums'][index]['name']) + ", "
        return album_list_text

    def get_latest_artist_albums(self, artist_name):
        search = self._search("artist", artist_name)

        if len(search) == 0:
            return False

        artist_info = self._api.get_artist_info(search[0]['artistId'],
                                                include_albums=True)
        album_list = artist_info['albums']

        sorted_list = sorted(album_list.__iter__(),
                             key=lambda s: s['year'],
                             reverse=True)

        speech_text = 'The latest albums by %s are ' % artist_name

        counter = 0
        for index, val in enumerate(sorted_list):
            if counter > 5:
                break
            else:
                album_info = self._api.get_album_info(
                    album_id=sorted_list[index]['albumId'],
                    include_tracks=True)
                if len(album_info['tracks']) >= 5:
                    counter += 1
                    album_name = sorted_list[index]['name']
                    album_year = sorted_list[index]['year']
                    speech_text += '%s, released in %d, ' % (album_name,
                                                             album_year)

        return speech_text

    def closest_match(self,
                      request_name,
                      all_matches,
                      artist_name='',
                      minimum_score=70):
        # Give each match a score based on its similarity to the requested
        # name
        self.log('Fetching library...')

        request_name = request_name.lower() + artist_name.lower()
        scored_matches = []
        for i, match in enumerate(all_matches):
            try:
                name = match['name'].lower()
            except (KeyError, TypeError):
                i = match
                name = all_matches[match]['title'].lower()
                if artist_name != "":
                    name += all_matches[match]['artist'].lower()

            scored_matches.append({
                'index': i,
                'name': name,
                'score': fuzz.ratio(name, request_name)
            })

        sorted_matches = sorted(scored_matches,
                                key=lambda a: a['score'],
                                reverse=True)
        top_scoring = sorted_matches[0]
        self.log('Fetching library...')

        best_match = all_matches[top_scoring['index']]

        # Make sure we have a decent match (the score is n where 0 <= n <= 100)
        if top_scoring['score'] < minimum_score:
            return None

        return best_match

    def get_genres(self, parent_genre_id=None):
        return self._api.get_genres(parent_genre_id)

    def increment_song_playcount(self, song_id, plays=1, playtime=None):
        return self._api.increment_song_playcount(song_id, plays, playtime)

    def get_song_data(self, song_id):
        return self._api.get_track_info(song_id)

    @classmethod
    def generate_api(cls, **kwargs):
        return cls(getenv('GOOGLE_EMAIL'), getenv('GOOGLE_PASSWORD'), **kwargs)
Example #52
0
f = open('foobar.csv', 'r')  
rows = []
for row in unicodecsv.DictReader(f):  
    rows.append(row)

f.close()

log("##### Login Google Music #####")

# Login into Google Music
api = Mobileclient()
api.login(gmusic_username, gmusic_password)

log("##### Fetching Library #####")

library = api.get_all_songs()

# Search all songs
songs = []
missing = []

log("##### Matching Songs #####")

for row in rows:
	found = False
	for song in library:
		if decode(row['title']) == song['title'] and \
			decode(row['artist']) == song['artist'] and \
			s_in_s(decode(row['album']), song['album']) and\
			int(row['tracknum']) == song['trackNumber']:
			log("Song " + decode(row['title']) + " Found. ID: " + song['id'])
Example #53
0
class MusicLibrary(object):
    'Read information about your Google Music library'

    def __init__(self, username=None, password=None,
                 true_file_size=False, scan=True, verbose=0):
        self.verbose = False
        if verbose > 1:
            self.verbose = True

        self.__login_and_setup(username, password)

        self.__artists = {} # 'artist name' -> {'album name' : Album(), ...}
        self.__galbums = {}
        self.__gartists = {}
        self.__albums = [] # [Album(), ...]
        if scan:
            self.rescan()
        self.true_file_size = true_file_size

    def rescan(self):
        self.__artists = {} # 'artist name' -> {'album name' : Album(), ...}
        self.__albums = [] # [Album(), ...]
        self.__galbums = {}
        self.__gartists = {}
        self.__aggregate_albums()

    def __login_and_setup(self, username=None, password=None):
        # If credentials are not specified, get them from $HOME/.gmusicfs
        if not username or not password:
            cred_path = os.path.join(os.path.expanduser('~'), '.gmusicfs')
            if not os.path.isfile(cred_path):
                raise NoCredentialException(
                    'No username/password was specified. No config file could '
                    'be found either. Try creating %s and specifying your '
                    'username/password there. Make sure to chmod 600.'
                    % cred_path)
            if not oct(os.stat(cred_path)[os.path.stat.ST_MODE]).endswith('00'):
                raise NoCredentialException(
                    'Config file is not protected. Please run: '
                    'chmod 600 %s' % cred_path)
            self.config = ConfigParser.ConfigParser()
            self.config.read(cred_path)
            username = self.config.get('credentials','username')
            password = self.config.get('credentials','password')
            global deviceId
            deviceId = self.config.get('credentials','deviceId')
            if not username or not password:
                raise NoCredentialException(
                    'No username/password could be read from config file'
                    ': %s' % cred_path)
            if not deviceId:
                raise NoCredentialException(
                    'No deviceId could be read from config file'
                    ': %s' % cred_path)

        self.api = GoogleMusicAPI(debug_logging=self.verbose)
        log.info('Logging in...')
        self.api.login(username, password)
        log.info('Login successful.')

    def __set_key_from_ginfo(self, track, ginfo, key, to_key=None):
        'Set track key from either album_info or artist_info'
        if to_key is None:
            to_key = key

        try:
            int_key = int(key)
        except ValueError:
            int_key = None

        if (not track.has_key(key) or track[key] == "" or int_key == 0) and ginfo.has_key(to_key):
            track[key] = ginfo[to_key]

        return track

    def __cleanup_artist(self, artist):
        if artist.startswith("featuring"):
            artist = artist[len("featuring"):].strip()
        if artist.startswith("feat"):
            artist = artist[len("feat"):].strip()
        return artist

    def __cleanup_name(self, name, track):
        for bracket in (('\[', '\]'), ('\{', '\}'), ('\(', '\)')):
            # Remove (xxx Album Version) from track names
            match = re.compile('^(?P<name>(.*))([ ]+[%s-]([^%s]*)[Vv]ersion[%s]?[ ]*)$' % (bracket[0], bracket[1], bracket[1])).match(name)
            if match is not None:
                name = match.groupdict()['name']
                name, track = self.__cleanup_name(name, track)

            # Pull (feat. <artist>) out of name and add to artist list
            match = re.compile('^(?P<name>(.*))([ ]+[%s][ ]*[Ff]eat[\.]?[ ]*(?P<artist>(.*))[%s]+)(?P<postfix>(.*))$' % (bracket[0], bracket[1])).match(name)
            if match is not None:
                name = match.groupdict()['name']
                artist = match.groupdict()['artist']
                if match.groupdict().has_key('postfix') and match.groupdict()['postfix'] is not None:
                    name += match.groupdict()['postfix']
                artist = artist.strip()
                if artist[-1] in ")}]": # I hate regex's.  The one above doesn't catch the last parenthesis if there's one
                    artist = artist[:-1]
                if artist.find(" and ") > -1 or artist.find(" & ") > -1:
                    artist = artist.replace(', ', ';')
                artist = artist.replace(' & ', ';')
                artist = artist.replace(' and ', ';')
                alist = artist.split(';')
                for artist in alist:
                     track['artist'].append(artist.strip())
                name, track = self.__cleanup_name(name, track)

            # Remove () or ( ) from track names
            match = re.compile('^(?P<name>(.*))([ ]*[%s][ ]?[%s][ ]*)$' % (bracket[0], bracket[1])).match(name)
            if match is not None:
                name = match.groupdict()['name']
                name, track = self.__cleanup_name(name, track)

        # Strip any extra whitespace from the name
        name = name.strip()
        return name, track

    def __cleanup_track(self, track):
        name = track['title']
        name, track = self.__cleanup_name(name, track)
        track['title'] = name
        for anum in range(0, len(track['artist'])):
            track['artist'][anum] = self.__cleanup_artist(track['artist'][anum])
        return track

    def __aggregate_albums(self):
        'Get all the tracks in the library, parse into artist and album dicts'
        all_artist_albums = {}
        log.info('Gathering track information...')
        tracks = self.api.get_all_songs()
        for track in tracks:
            if track.has_key('artist'):
                if track['artist'].find(" and ") > -1 or track['artist'].find(" & ") > -1:
                    track['artist'] = track['artist'].replace(', ', ';')
                track['artist'] = track['artist'].replace(' & ', ';')
                track['artist'] = track['artist'].replace(' and ', ';')
                track['artist'] = track['artist'].split(';')
            else:
                track['artist'] = []

            track = self.__cleanup_track(track)

            if track.has_key('albumArtist') and track['albumArtist'] != "":
                albumartist = track['albumArtist']
            elif len(track['artist']) == 1 and track['artist'][0] != "":
                albumartist = track['artist'][0]
            else:
                albumartist = "Unknown"

            # Get album and artist information from Google
            if track.has_key('albumId'):
                if self.__galbums.has_key(track['albumId']):
                    album_info = self.__galbums[track['albumId']]
                else:
                    print "Downloading album info for '%s'" % track['album']
                    album_info = self.__galbums[track['albumId']] = self.api.get_album_info(track['albumId'], include_tracks=False)
                if album_info.has_key('artistId') and len(album_info['artistId']) > 0 and album_info['artistId'][0] != "":
                    artist_id = album_info['artistId'][0]
                    if self.__gartists.has_key(artist_id):
                        artist_info = self.__gartists[artist_id]
                    else:
                        print "Downloading artist info for '%s'" % album_info['albumArtist']
                        if album_info['albumArtist'] == "Various":
                            print album_info
                        artist_info = self.__gartists[artist_id] = self.api.get_artist_info(artist_id, include_albums=False, max_top_tracks=0, max_rel_artist=0)
                else:
                    artist_info = {}
            else:
                album_info = {}
                artist_info = {}

            track = self.__set_key_from_ginfo(track, album_info, 'album', 'name')
            track = self.__set_key_from_ginfo(track, album_info, 'year')
            track = self.__set_key_from_ginfo(track, artist_info, 'albumArtist', 'name')

            # Fix for odd capitalization issues
            if artist_info.has_key('name') and track['albumArtist'].lower() == artist_info['name'].lower() and track['albumArtist'] != artist_info['name']:
                track['albumArtist'] = artist_info['name']
            for anum in range(0, len(track['artist'])):
                if artist_info.has_key('name') and track['artist'][anum].lower() == artist_info['name'].lower() and track['artist'][anum] != artist_info['name']:
                    track['artist'][anum] = artist_info['name']

            if not track.has_key('albumId'):
                track['albumKey'] = "%s|||%s" % (albumartist, track['album'])
            else:
                track['albumKey'] = track['albumId']
            album = all_artist_albums.get(track['albumKey'], None)

            if not album:
                album = all_artist_albums[track['albumKey']] = Album(
                    self, formatNames(track['album']), track['albumArtist'], track['album'], track['year'] )
                self.__albums.append(album)
                artist_albums = self.__artists.get(track['albumArtist'], None)
                if artist_albums:
                    artist_albums[formatNames(album.normtitle)] = album
                else:
                    self.__artists[track['albumArtist']] = {album.normtitle: album}
                    artist_albums = self.__artists[track['albumArtist']]
            album.add_track(track)

        # Separate multi-disc albums
        for artist in self.__artists.values():
            for key in artist.keys():
                album = artist[key]
                if album.get_disc_count() > 1:
                    for d in album.get_discs():
                        new_name = "%s - Disc %i" % (album.album, d)
                        new_album = Album(album.library, formatNames(new_name), album.artist, new_name, album.year)
                        album.copy_art_to(new_album)
                        new_album.show_discnum = True
                        new_key = None
                        for t in album.get_tracks():
                            if int(t['discNumber']) == d:
                                new_album.add_track(t)
                        artist[formatNames(new_name)] = new_album
                    del artist[key]

        log.debug('%d tracks loaded.' % len(tracks))
        log.debug('%d artists loaded.' % len(self.__artists))
        log.debug('%d albums loaded.' % len(self.__albums))

    def get_artists(self):
        return self.__artists

    def get_albums(self):
        return self.__albums

    def get_artist_albums(self, artist):
        log.debug(artist)
        return self.__artists[artist]

    def cleanup(self):
        pass
Example #54
0
class GMusic(object):
    def __init__(self):
        self.authenticated = False
        self.all_access = False
        self._device = None
        self._webclient = Webclient(debug_logging=False)
        self._mobileclient = Mobileclient(debug_logging=False)
        self._playlists = []
        self._playlist_contents = []
        self._all_songs = []
        self._all_artists = {}
        self._all_albums = {}
        self._all_genres = {}
        self._stations = []

    def _get_device_id(self):
        if self.authenticated:
            devices = self._webclient.get_registered_devices()
            for dev in devices:
                if dev['type'] == 'PHONE':
                    self._device = dev['id'][2:]
                    break

    def _set_all_access(self):
        settings = self._webclient._make_call(webclient.GetSettings, '')
        self.all_access = True if 'isSubscription' in settings['settings'] and settings['settings']['isSubscription'] == True else False

    def authenticate(self, email, password):
        try:
            mcauthenticated = self._mobileclient.login(email, password)
        except AlreadyLoggedIn:
            mcauthenticated = True

        try:
            wcauthenticated = self._webclient.login(email, password)
        except AlreadyLoggedIn:
            wcauthenticated = True

        self.authenticated = mcauthenticated and wcauthenticated
        self._get_device_id()
        self._set_all_access()
        return self.authenticated

    def get_all_songs(self, id=None):
        if len(self._all_songs) == 0:
            try:
                self._all_songs = self._mobileclient.get_all_songs()
            except NotLoggedIn:
                if self.authenticate():
                    self._all_songs = self._mobileclient.get_all_songs()
                else:
                    return []

        if id:
            return [x for x in self._all_songs if x['id'] == id][0]
        else:
            return self._all_songs

    def get_all_artists(self):
        if not self._all_artists:
            songs = self.get_all_songs()
            for song in songs:
                artist = song['artist']
                thumb = None
                if artist not in self._all_artists:
                    self._all_artists[artist] = []

                track = {'title': song['title'],
                        'album': song['album'],
                        'artist': artist,
                        'durationMillis': song['durationMillis'],
                        'trackType': song['trackNumber'],
                        'id': song['id']}

                if 'albumArtRef' in song:
                    track['albumArtRef'] = song['albumArtRef']

                if 'artistArtRef' in song:
                    thumb = song['artistArtRef'][0]['url']

                if 'storeId' in song:
                    track['storeId'] = song['storeId']

                self._all_artists[artist].append({'track': track, 'thumb': thumb, 'id': song['id']})

        return self._all_artists

    def get_all_albums(self):
        if not self._all_albums:
            songs = self.get_all_songs()
            for song in songs:
                album = song['album']
                thumb = None
                if album not in self._all_albums:
                    self._all_albums[album] = []

                track = {'title': song['title'],
                        'album': album,
                        'artist': song['artist'],
                        'durationMillis': song['durationMillis'],
                        'trackType': song['trackNumber'],
                        'id': song['id']}

                if 'albumArtRef' in song:
                    track['albumArtRef'] = song['albumArtRef']
                    thumb = song['albumArtRef'][0]['url']

                if 'storeId' in song:
                    track['storeId'] = song['storeId']

                self._all_albums[album].append({'track': track, 'thumb': thumb, 'id': song['id']})

        return self._all_albums

    def get_all_genres(self):
        if not self._all_genres:
            songs = self.get_all_songs()
            for song in songs:
                genre = song['genre']
                if genre not in self._all_genres:
                    self._all_genres[genre] = []

                track = {'title': song['title'],
                        'album': song['album'],
                        'artist': song['artist'],
                        'durationMillis': song['durationMillis'],
                        'trackType': song['trackNumber'],
                        'id': song['id']}

                if 'albumArtRef' in song:
                    track['albumArtRef'] = song['albumArtRef']

                if 'storeId' in song:
                    track['storeId'] = song['storeId']

                self._all_genres[genre].append({'track': track, 'id': song['id']})

        return self._all_genres

    def get_all_playlists(self):
        if len(self._playlists) == 0:
            try:
                self._playlists = self._mobileclient.get_all_playlists()
            except NotLoggedIn:
                if self.authenticate():
                    self._playlists = self._mobileclient.get_all_playlists()
                else:
                    return []

        return self._playlists

    def get_all_user_playlist_contents(self, id):
        tracks = []
        if len(self._playlist_contents) == 0:
            try:
                self._playlist_contents = self._mobileclient.get_all_user_playlist_contents()
            except NotLoggedIn:
                if self.authenticate():
                    self._playlist_contents = self._mobileclient.get_all_user_playlist_contents()
                else:
                    return []

        for playlist in self._playlist_contents:
            if id == playlist['id']:
                tracks = playlist['tracks']
                break

        return tracks

    def get_shared_playlist_contents(self, token):
        playlist = []
        try:
            playlist = self._mobileclient.get_shared_playlist_contents(token)
        except NotLoggedIn:
            if self.authenticate():
                playlist = self._mobileclient.get_shared_playlist_contents(token)
            else:
                return []

        return playlist

    def get_all_stations(self):
        if len(self._stations) == 0:
            try:
                self._stations = self._mobileclient.get_all_stations()
            except NotLoggedIn:
                if self.authenticate():
                    self._stations = self._mobileclient.get_all_stations()
                else:
                    return []

        return self._stations

    def get_station_tracks(self, id, num_tracks=200):
        tracks = []
        try:
            tracks = self._mobileclient.get_station_tracks(id, num_tracks)
        except NotLoggedIn:
            if self.authenticate():
                tracks = self._mobileclient.get_station_tracks(id, num_tracks)
            else:
                return []

        return tracks

    def get_genres(self):
        genres = []
        try:
            genres = self._mobileclient.get_genres()
        except NotLoggedIn:
            if self.authenticate():
                genres = self._mobileclient.get_genres()
            else:
                return []

        return genres

    def create_station(self, name, id):
        station = None
        try:
            station = self._mobileclient.create_station(name=name, genre_id=id)
        except NotLoggedIn:
            if self.authenticate():
                station = self._mobileclient.create_station(name=name, genre_id=id)
            else:
                return []

        return station

    def search_all_access(self, query, max_results=50):
        results = None
        try:
            results = self._mobileclient.search_all_access(query, max_results)
        except NotLoggedIn:
            if self.authenticate():
                results = self._mobileclient.search_all_access(query, max_results)
            else:
                return []

        return results

    def get_artist_info(self, id, include_albums=True, max_top_tracks=5, max_rel_artist=5):
        results = None
        try:
            results = self._mobileclient.get_artist_info(id, include_albums=include_albums, max_top_tracks=max_top_tracks, max_rel_artist=max_rel_artist)
        except NotLoggedIn:
            if self.authenticate():
                results = self._mobileclient.get_artist_info(id, include_albums=include_albums, max_top_tracks=max_top_tracks, max_rel_artist=max_rel_artist)
            else:
                return []

        return results

    def get_album_info(self, id, include_tracks=True):
        results = None
        try:
            results = self._mobileclient.get_album_info(id, include_tracks=include_tracks)
        except NotLoggedIn:
            if self.authenticate():
                results = self._mobileclient.get_album_info(id, include_tracks=include_tracks)
            else:
                return []

        return results

    def get_stream_url(self, id):
        try:
            stream_url = self._mobileclient.get_stream_url(id, self._device)
        except NotLoggedIn:
            if self.authenticate():
                stream_url = self._mobileclient.get_stream_url(id, self._device)
            else:
                return ''
        except CallFailure:
            raise CallFailure('Could not play song with id: ' + id, 'get_stream_url')

        return stream_url
Example #55
0
            break
        except:
            print("oops, this didn't work, trying again")
            i += 1
            i %= len(ids)
else:
    oa = api.perform_oauth()
    api.oauth_login(Mobileclient.FROM_MAC_ADDRESS, oauth_credentials=oa)
    devices = api.get_registered_devices()
    ids = []
    for i in devices:
        ids.append(i['id'][2:])
    with open('config.json', 'w') as fp:
        json.dump(ids, fp)

songs = api.get_all_songs()
for song in songs:
    dirName = normalizePath("%s - %s" % (song["artist"], song["album"]))
    dirPath = targetDir + "/" + dirName
    if not os.path.exists(dirPath):
        print("downloading to directory: " + dirPath)
        os.makedirs(dirPath)
    fileName = normalizePath(
        "%s. %s - %s.mp3" %
        (song["trackNumber"], song["artist"], song["title"]))
    filePath = dirPath + "/" + fileName
    if os.path.exists(filePath):
        print(fileName + " already exists, skipping")
        continue
    url = api.get_stream_url(song_id=song["id"], quality="hi")
    print("downloading: " + fileName)
Example #56
0
        if 'album' in track and 'title' in track:
            track_txt_key = track['album'] + '_' + track['title'];
            track_txt_key = track_txt_key.lower()
            if track_txt_key not in uniq_tracks:
                uniq_tracks.append(track_txt_key)
            else:
                duplicatesTracks.append(track)
    return duplicatesTracks


api = Mobileclient()
logged_in = api.login('login', 'password')

if logged_in:
    print "Successfully logged in. Beginning duplication removal process."
    all_tracks = api.get_all_songs()
    print "all tracks: ", len(all_tracks)
    duplicate_tracks = getDuplicatesSongInAlbums(all_tracks)
    print "duplication tracks count: %s" % len(duplicate_tracks)
    show_tracks = raw_input("Show list tracks to delete?:[y] Y/n ")
    if show_tracks.lower() == 'y' or show_tracks == '':
        for track in duplicate_tracks:
            name = u"%s - %s - %s" % (track['artist'], track['album'], track['title'])
            print name.encode('utf8')
    if len(duplicate_tracks) > 0:
        deleteConfirnation = raw_input("Are you sure you want to delete tracks (%d)? [y] Y/n" % len(duplicate_tracks))
        if deleteConfirnation.lower() == 'y' or deleteConfirnation == '':
            duplicate_track_ids = get_track_ids(duplicate_tracks)
            deleted_track_ids = api.delete_songs(duplicate_track_ids)
            print "Successfully deleted " + str(len(deleted_track_ids)) + " of " + str(len(duplicate_track_ids)) + " queued songs for removal."
    else:
Example #57
0
if __name__ == "__main__":
    manager = GPMDBManager()

    """
    Load all songs into db (Use ONLY ONCE)
    """

    ANDROID_DEVICE_MAC_ADDRESS = "00:00:00:00:00:00"

    client = Mobileclient()
    client.login("*****@*****.**", "xyz", ANDROID_DEVICE_MAC_ADDRESS)

    print("Getting songs")

    library = client.get_all_songs()
    print("Retreived all songs")

    for i, songDict in enumerate(library):
        name = songDict["title"]
        album = songDict["album"]
        artist = songDict["artist"]
        duration = songDict["durationMillis"]
        playCount = songDict["playCount"]
        songRating = songDict["rating"]
        songComposer = songDict["composer"]
        songYear = songDict["year"]

        manager.insertSong(name, album, artist, duration, playCount, songRating, songComposer, songYear)
        print("Inserted Song %d : Name = %s" % ((i+1), name))
Example #58
0
class GMusic(object):
    def __init__(self):
        self.mob_client = Mobileclient()
        self.web_client = Webclient()
        self.logfile = None
        self.logfile_open = False
        # logged_in is True if login was successful
        logged_in = self.mob_client.login(MY_GMAIL, MY_PASSWORD, Mobileclient.FROM_MAC_ADDRESS)
        if logged_in:
            print("GoogleMusic MobileClient Logged In")
        else:
            raise Exception("Couldn't log in, exiting...")
        logged_in = self.web_client.login(MY_GMAIL, MY_PASSWORD)
        if logged_in:
            print("GoogleMusic WebClient Logged In")
        else:
            raise Exception("Couldn't log in, exiting...")

    def build_play_list_dummy(self):
        library = self.mob_client.get_all_songs()
        tracks = [track for track in library if track['artist'] == 'Adhesive Wombat'
                  and "night shade" in track['title'].lower()]
        # for track in sweet_tracks:
        #     print(track)

        playlist_id = self.mob_client.create_playlist('Test playlist')
        for track in tracks:
            self.mob_client.add_songs_to_playlist(playlist_id, track['id'])

        return playlist_id

    def _setlogfile(self, logfile):
        if self.logfile_open:
            self._print_and_log("logfile {} already opened! Not opening again!")
        else:
            self.logfile = logfile
            with open(self.logfile, "w") as logfile:
                logfile.write("LOGSTART: {}, script: {}\n".format(asctime(localtime()), __file__))
            self.logfile_open = True

    def _print_and_log(self, msg):
        if self.logfile:
            with open(self.logfile, "a") as logfile:
                logfile.write(msg+"\n")
        print msg

    def find_duplicate_songs(self, outfile=None):
        duplicates = []
        if outfile:
            if path.exists(path.dirname(outfile)):
                self._setlogfile(outfile)
            else:
                raise IOError("Output filename given: {} is in an none-existing dir".format(outfile))

        library = self.mob_client.get_all_songs()
        tracks = [track for track in library]
        while tracks:
            track = tracks[0]
            dup_list = []
            dup_idx_list = []
            for idx, track_i in enumerate(tracks):
                if track['artist'].lower() == track_i['artist'].lower() and\
                   track['album'].lower() == track_i['album'].lower() and\
                    track['discNumber'] == track_i['discNumber'] and\
                    track['trackNumber'] == track_i['trackNumber'] and\
                   track['title'].lower() == track_i['title'].lower():
                    dup_idx_list.append(idx)
                    dup_list.append(track_i)
            # Remove them:
            for index in sorted(dup_idx_list, reverse=True):
                del tracks[index]
            if len(dup_list) > 1:
                duplicates.append(dup_list)
        for idx, dup_list in enumerate(duplicates):
            self._print_and_log("{}: '{}' was found {} times!".format(idx+1, dup_list[0]['title'].encode("utf-8"),
                                                                      len(dup_list)))
        self._print_and_log("Found a total of {} duplicate songs!".format(len(duplicates)))
        # Display important stuff
        for idx, track_list in enumerate(duplicates):
            self._print_and_log("{}: BAND: {}, NAME:  '{}'".format(idx+1, track_list[0]['artist'],
                                                                   track_list[0]['title'].encode("utf-8")))
            for el in track_list[0]:
                for track in track_list:
                    if el not in track:
                        track[el] = "NO VALUE"
                    if track[el] != track_list[0][el] and el not in ['id', 'url', 'recentTimestamp', 'storeId', 'nid', 'clientId']:
                        # unicode?
                        try:
                            r_val = track_list[0][el].encode("utf-8")
                        except:
                            r_val = track_list[0][el]
                        # unicode?
                        try:
                            l_val = track[el].encode("utf-8")
                        except:
                            l_val = track[el]

                        self._print_and_log("track_id {}: {}='{}'".format(track_list[0]['id'], el, r_val))
                        self._print_and_log("track_id {}: {}='{}'".format(track['id'], el, l_val))

            # raw_input("Press any key to continue...")
        return duplicates

    def delete_duplicates(self, duplicates):
        self._print_and_log("Cleaning duplicates [removing oldest of each duplicant]:")
        old_song_ids = []
        for idx, dup_list in enumerate(duplicates):
            self._print_and_log("{}: BAND: {}, NAME:  '{}'".format(idx+1, dup_list[0]['artist'],
                                                                   dup_list[0]['title'].encode("utf-8")))
            track_timstamp = None
            oldest_id = None
            for el in dup_list:
                if track_timstamp is None and oldest_id is None:
                    track_timstamp = el["timestamp"]
                    oldest_id = el["id"]
                elif el["timestamp"] < track_timstamp:
                    track_timstamp = el["timestamp"]
                    oldest_id = el["id"]
            # finished with dup_list - log oldest id:
            self._print_and_log("Will delete {}, track_id: {}".format(el["title"], el["id"]))
            old_song_ids.append(oldest_id)

        self.mob_client.delete_songs(old_song_ids)
        self._print_and_log("track_ids deleted:\n{}".format(old_song_ids))