Example #1
0
class GMusicWS:
    def __init__(self, user, password, playlistName):
        self.playlistName = playlistName
        self.api = Mobileclient()
        print("Logging into MobileClient API")
        self.api.login(user, password,
                       "android_id")  #insert unique android_id here

    def mapUnknownTracks(self, db):
        playlist = db.unmappedTracks()

        for track in playlist:
            searchstr = track.artist + " " + track.song
            print("Searching for %s" % (searchstr))
            try:
                result = self.api.search_all_access(searchstr, max_results=1)
                print("Found " + result['song_hits'][0]['track']['artist'] +
                      " - " + result['song_hits'][0]['track']['title'])
                nid = result['song_hits'][0]['track']['nid']
                db.storemapping(track.song, track.artist, nid)
            except:
                print("Error parsing result: " + str(result))

            time.sleep(1)

    def maintain(self, tracks):
        print("Searching for playlist %s" % (self.playlistName))

        found = False
        searchres = self.api.get_all_playlists()
        for list in searchres:
            if list['name'] == self.playlistName:
                found = True
                pid = list['id']

        if not found:
            print("Not found - creating")
            pid = self.api.create_playlist(self.playlistName)

        print("Playlist id is %s" % (pid))

        print("Getting current contents")
        playlists = self.api.get_all_user_playlist_contents()
        currentEntries = []
        for playlist in playlists:
            if playlist['name'] == self.playlistName:
                for entry in playlist['tracks']:
                    currentEntries.append(entry['id'])

        print("Removing songs")
        self.api.remove_entries_from_playlist(currentEntries)

        print("Adding songs")
        self.api.add_songs_to_playlist(pid, tracks)
Example #2
0
class GMusicWS:
	def __init__(self, user, password, playlistName):
		self.playlistName = playlistName
		self.api = Mobileclient()
		print ("Logging into MobileClient API")
		self.api.login(user, password,"android_id") #insert unique android_id here

	def mapUnknownTracks(self, db):
		playlist = db.unmappedTracks()
		
		for track in playlist:
			searchstr = track.artist + " " + track.song
			print ("Searching for %s" % (searchstr))
			try:
				result = self.api.search_all_access(searchstr, max_results=1)
				print ("Found " + result['song_hits'][0]['track']['artist'] + " - " + result['song_hits'][0]['track']['title'])
				nid = result['song_hits'][0]['track']['nid']
				db.storemapping(track.song, track.artist, nid)
			except:
				print ("Error parsing result: " + str(result))
				
			time.sleep(1)
	
	def maintain(self, tracks):
		print ("Searching for playlist %s" % (self.playlistName))
				
		found = False
		searchres = self.api.get_all_playlists()
		for list in searchres:
			if list['name'] == self.playlistName:
				found = True
				pid = list['id']
				
		if not found:
			print ("Not found - creating")
			pid = self.api.create_playlist(self.playlistName)
		
		print ("Playlist id is %s" % (pid))
		
		print ("Getting current contents")
		playlists = self.api.get_all_user_playlist_contents()
		currentEntries = []
		for playlist in playlists:
			if playlist['name'] == self.playlistName:
				for entry in playlist['tracks']:
					currentEntries.append(entry['id'])

		print ("Removing songs")		
		self.api.remove_entries_from_playlist(currentEntries)
		
		print ("Adding songs")
		self.api.add_songs_to_playlist(pid, tracks)
Example #3
0
class GMusicAPI():
    def __init__(self, username=None, encrypted_pass=None):
        self._api = Mobileclient()
        self.logged_in = False
        if username and encrypted_pass:
            self.login(username, encrypted_pass)

    def login(self, username, encrypted_pass):
        self.logged_in = self._api.login(username, decrypt(encrypted_pass), Mobileclient.FROM_MAC_ADDRESS)

    def logout(self):
        self._api.logout()
        self.logged_in = False

    def clear_playlist(self, playlist_name):
        playlists = self._api.get_all_user_playlist_contents()
        playlist = [playlist for playlist in playlists if playlist['name'] == playlist_name][0]
        entry_ids = [entry['id'] for entry in playlist['tracks']]
        removed = self._api.remove_entries_from_playlist(entry_ids)
        return len(removed)

    def search(self, *args):
        """
        Returns the best-fitting track dict for the given information.
        :param args: Strings which can be artist, song title, album etc.
        :return:
        """
        query = sanitise_query(' '.join(args))

        result = self._api.search(query)

        song_results = result['song_hits']
        if not song_results:
            warnings.warn('Warning: query {} returned no song hits.'.format(query))
            return None

        tracks = [song_result['track'] for song_result in song_results[:5]]

        for track in tracks:
            if not is_tribute(track, query):
                return track

        warnings.warn('Warning: query {} returned no non-tribute song hits.'.format(query))
        return None

    def get_playlist_id(self, playlist_name):
        for playlist in self._api.get_all_playlists():
            if playlist['name'] == playlist_name:
                return playlist['id']
        raise ValueError("Playlist '{}' not found".format(playlist_name))

    def add_songs(self, playlist_name, tracks):
        playlist_id = self.get_playlist_id(playlist_name)
        track_ids = [track['nid'] for track in tracks if track]
        self._api.add_songs_to_playlist(playlist_id, track_ids)
Example #4
0
class GmSession:
    def __init__(self):
        self.session = Mobileclient()
        self.device_id = gmusic_device_id
        self.cred_path = gmusic_cred_path
        self.playlist_id = gmusic_playlist_id

    def login(self):
        self.session.oauth_login(device_id=self.device_id,
                                 oauth_credentials=self.cred_path)

    def logout(self):
        self.session.logout()

    def search(self, artist, song):
        search_string = f'{artist.lower()}' + f', {song.lower()}'
        results = self.session.search(search_string, max_results=20)
        if len(results['song_hits']) > 0:
            first_result = results['song_hits'][0]['track']
            if 'storeId' in first_result.keys():
                return first_result['storeId']
            elif 'id' in first_result.keys():
                print('bad id')
                return first_result['id']
            elif 'nid' in first_result.keys():
                print('bad id')
                return results['song_hits'][0]['track']['nid']
        else:
            print('No songs found...')

    def add_to_playlist(self, song_list):
        playlists = self.session.get_all_user_playlist_contents()
        for playlist in playlists:
            if playlist['id'] == self.playlist_id:
                to_remove = []
                for track in playlist['tracks']:
                    to_remove.append(track['id'])

                print('Adding new songs...')
                res = self.session.add_songs_to_playlist(
                    self.playlist_id, song_list)
                print('Removing previous songs...')
                out = self.session.remove_entries_from_playlist(to_remove)
                print('Finished')
Example #5
0
# Foreach deleted entry, check if it's undeleted in any of the source playlists
# If so, delete it
for row in deletedTracks:
    trackId = row[0]
    sql = """
        SELECT `gpm_entryid`
        FROM `gpm_playlist_entries`
        JOIN `gpm_playlists` USING (`gpm_playlistid`)
        WHERE `gpm_playlists`.`deleted` = 0
            AND `gpm_playlists`.`name` LIKE 'Background %%'
            AND `gpm_playlist_entries`.`deleted` = 0
            AND `gpm_trackid` = %(trackId)s
    """
    params = {
        "trackId": trackId,
    }
    cursor.execute(sql, params)
    otherListEntries = cursor.fetchall()

    if len(otherListEntries) < 1:
        continue

    logger.info("Deleted track " + trackId + " was found in another playlist... deleting")
    otherEntryIds = []
    for otherRow in otherListEntries:
        otherEntryIds.append(otherRow[0])
    logger.info("Deleting playlist entries: "+ ", ".join(otherEntryIds))
    gpm.remove_entries_from_playlist(otherEntryIds)

logger.info("DONE!")
Example #6
0
big_playlist = [p for p in playlists if p['name'] == secret.BIG_PLAYLIST][0]
uncategorized_lst = [p for p in playlists if p['name'] == secret.UNCATEGORIZED]
category_a_lst = [p for p in playlists if p['name'] == secret.CATEGORY_A]
category_b_lst = [p for p in playlists if p['name'] == secret.CATEGORY_B]

# If "Uncategorized" playlist already exists, remove all songs from it.
# Otherwise create the playlist.
if uncategorized_lst:
    uncategorized_playlist = uncategorized_lst[0]
    if 'tracks' in uncategorized_playlist:
        old_uncategorized_songs_set = {
            song['id']
            for song in uncategorized_playlist['tracks']
        }
        old_uncategorized_songs_lst = list(old_uncategorized_songs_set)
        api.remove_entries_from_playlist(old_uncategorized_songs_lst)
        print("Cleared all songs from uncategorized playlist named",
              secret.UNCATEGORIZED)
else:
    api.create_playlist(secret.UNCATEGORIZED)
    print("Created playlist for uncategorized songs, named",
          secret.UNCATEGORIZED)

# If "Category A"playlist does not exist, create it
if not category_a_lst:
    api.create_playlist(secret.CATEGORY_A)
    print("Created playlist named", secret.CATEGORY_A)

# If "Category B"playlist does not exist, create it
if not category_b_lst:
    api.create_playlist(secret.CATEGORY_B)
class MusicSync(object):
    def __init__(self, email=None, password=None):
        self.mm = Musicmanager()
        self.wc = Webclient()
        self.mc = Mobileclient()
        if not email:
            email = raw_input("Email: ")
        if not password:
            password = getpass()

        self.email = email
        self.password = password

        self.logged_in = self.auth()

        print "Fetching playlists from Google..."
        self.playlists = self.mc.get_all_user_playlist_contents()
        #self.playlists = self.mc.get_all_playlists()
        #self.playlists = self.wc.get_all_playlist_ids(auto=False)
        self.all_songs = self.mc.get_all_songs()
        #print "Got %d playlists." % len(self.playlists['user'])
        print "Got %d playlists containing %d songs." % (len(
            self.playlists), len(self.all_songs))
        print ""

    def auth(self):
        self.logged_in = self.mc.login(self.email, self.password)
        #self.logged_in = self.wc.login(self.email, self.password)
        if not self.logged_in:
            print "Login failed..."
            exit()

        print ""
        print "Logged in as %s" % self.email
        print ""

        if not os.path.isfile(OAUTH_FILEPATH):
            print "First time login. Please follow the instructions below:"
            self.mm.perform_oauth()
        self.logged_in = self.mm.login()
        if not self.logged_in:
            print "OAuth failed... try deleting your %s file and trying again." % OAUTH_FILEPATH
            exit()

        print "Authenticated"
        print ""

    def sync_playlist(self, filename, remove_missing):
        #def sync_playlist(self, filename, remove_missing=False):
        filename = self.get_platform_path(filename)
        os.chdir(os.path.dirname(filename))
        title = os.path.splitext(os.path.basename(filename))[0]
        print "Syncing playlist: %s" % filename
        #if title not in self.playlists['user']:
        #print "   didn't exist... creating..."
        #self.playlists['user'][title] = [self.wc.create_playlist(title)]
        print ""

        plid = ""

        for pl in self.playlists:
            if pl['name'] == title:
                plid = pl['id']
                goog_songs = pl['tracks']

        if plid == "":
            print "   didn't exist... creating..."
            plid = self.mc.create_playlist(self, title)

        #plid = self.playlists['user'][title][0]
        #goog_songs = self.wc.get_playlist_songs(plid)
        print "%d songs already in Google Music playlist" % len(goog_songs)
        pc_songs = self.get_files_from_playlist(filename)
        print "%d songs in local playlist" % len(pc_songs)
        print ""

        # Sanity check max 1000 songs per playlist
        if len(pc_songs) > MAX_SONGS_IN_PLAYLIST:
            print "    Google music doesn't allow more than %d songs in a playlist..." % MAX_SONGS_IN_PLAYLIST
            print "    Will only attempt to sync the first %d songs." % MAX_SONGS_IN_PLAYLIST
            del pc_songs[MAX_SONGS_IN_PLAYLIST:]

        existing_files = 0
        added_files = 0
        failed_files = 0
        removed_files = 0
        fatal_count = 0

        for fn in pc_songs:
            if self.file_already_in_list(fn, goog_songs, self.all_songs):
                existing_files += 1
                continue
            print ""
            print "Adding: %s" % os.path.basename(fn).encode('cp1252')
            #print "Adding: %s" % os.path.basename(fn)
            #online = False
            online = self.find_song(fn, goog_songs, self.all_songs)
            #online = self.find_song(fn)
            song_id = None
            if online:
                song_id = online['id']
                print "   already uploaded [%s]" % song_id
            else:
                attempts = 0
                result = []
                while not result and attempts < MAX_UPLOAD_ATTEMPTS_PER_FILE:
                    print "   uploading... (may take a while)"
                    attempts += 1
                    try:
                        result = self.mm.upload(fn)
                    except (BadStatusLine, CannotSendRequest):
                        # Bail out if we're getting too many disconnects
                        if fatal_count >= MAX_CONNECTION_ERRORS_BEFORE_QUIT:
                            print ""
                            print "Too many disconnections - quitting. Please try running the script again."
                            print ""
                            exit()

                        print "Connection Error -- Reattempting login"
                        fatal_count += 1
                        self.wc.logout()
                        self.mc.logout()
                        self.mm.logout()
                        result = []
                        time.sleep(STANDARD_SLEEP)

                    except:
                        result = []
                        time.sleep(STANDARD_SLEEP)

                try:
                    if result[0]:
                        song_id = result[0].itervalues().next()
                    else:
                        song_id = result[1].itervalues().next()
                    print "   upload complete [%s]" % song_id
                except:
                    print "      upload failed - skipping"
                    tag = self.get_id3_tag(fn)
                    print "      failed song:\t%s\t%s\t%s" % (
                        tag['title'].encode('cp1252'),
                        tag['artist'].encode('cp1252'),
                        tag['album'].encode('cp1252'))

            if not song_id:
                failed_files += 1
                continue

            added = self.mc.add_songs_to_playlist(plid, song_id)
            time.sleep(.3)  # Don't spam the server too fast...
            print "   done adding to playlist"
            added_files += 1

        if remove_missing:
            for g in goog_songs:
                for s in self.all_songs:
                    if g['trackId'] == s['id']:
                        print ""
                        print "Removing: %s" % s['title'].encode('cp1252')
                        self.mc.remove_entries_from_playlist(g['id'])
                        #self.wc.remove_songs_from_playlist(plid, s.id)
                        time.sleep(.3)  # Don't spam the server too fast...
                        removed_files += 1

        print ""
        print "---"
        print "%d songs unmodified" % existing_files
        print "%d songs added" % added_files
        print "%d songs failed" % failed_files
        print "%d songs removed" % removed_files

    def get_files_from_playlist(self, filename):
        files = []
        f = codecs.open(filename, encoding='cp1252')
        #f = codecs.open(filename, encoding='utf-8')
        for line in f:
            line = line.rstrip().replace(u'\ufeff', u'')
            if line == "" or line[0] == "#":
                continue
            path = os.path.abspath(self.get_platform_path(line))
            if not os.path.exists(path):
                print "File not found: %s" % line
                continue
            files.append(path)
        f.close()
        return files

    def file_already_in_list(self, filename, goog_songs, all_songs):
        tag = self.get_id3_tag(filename)
        print "Searching for\t%s\t%s\t%s" % (tag['title'].encode('cp1252'),
                                             tag['artist'].encode('cp1252'),
                                             tag['album'].encode('cp1252'))
        i = 0
        while i < len(goog_songs):
            for s in all_songs:
                if goog_songs[i]['trackId'] == s['id']:
                    if self.tag_compare(s, tag):
                        print "Found match\t%s\t%s\t%s" % (
                            s['title'].encode('cp1252'),
                            s['artist'].encode('cp1252'),
                            s['album'].encode('cp1252'))
                        goog_songs.pop(i)
                        return True
            i += 1
        return False

    def get_id3_tag(self, filename):
        data = mutagen.File(filename, easy=True)
        r = {}
        if 'title' not in data:
            title = os.path.splitext(os.path.basename(filename))[0]
            print 'Found song with no ID3 title, setting using filename:'
            print '  %s' % title
            print '  (please note - the id3 format used (v2.4) is invisible to windows)'
            data['title'] = [title]
            data.save()
        r['title'] = data['title'][0]
        r['track'] = int(data['tracknumber'][0].split('/')
                         [0]) if 'tracknumber' in data else 0
        # If there is no track, try and get a track number off the front of the file... since thats
        # what google seems to do...
        # Not sure how google expects it to be formatted, for now this is a best guess
        if r['track'] == 0:
            m = re.match("(\d+) ", os.path.basename(filename))
            if m:
                r['track'] = int(m.group(0))
        r['artist'] = data['artist'][0] if 'artist' in data else ''
        r['album'] = data['album'][0] if 'album' in data else ''
        return r

    def find_song(self, filename, goog_songs, all_songs):
        tag = self.get_id3_tag(filename)
        print "Searching for\t%s\t%s\t%s" % (tag['title'].encode('cp1252'),
                                             tag['artist'].encode('cp1252'),
                                             tag['album'].encode('cp1252'))
        #results = self.wc.search(tag['title'])
        # NOTE - diagnostic print here to check results if you're creating duplicates
        #print results['song_hits']
        #for r in goog_songs:
        #for r in results['song_hits']:
        for s in all_songs:
            #if r['trackId'] == s['id']:
            if self.tag_compare(s, tag):
                # TODO: add rough time check to make sure its "close"
                print "Found match\t%s\t%s\t%s" % (
                    s['title'].encode('cp1252'), s['artist'].encode('cp1252'),
                    s['album'].encode('cp1252'))
                return s
        return None

    def tag_compare(self, g_song, tag):
        # If a google result has no track, google doesn't return a field for it
        if 'title' not in g_song:
            g_song['title'] = ""
        if 'artist' not in g_song:
            g_song['artist'] = ""
        if 'album' not in g_song:
            g_song['album'] = ""
        if 'track' not in g_song:
            g_song['track'] = 0
        if (g_song['title'].lower() == tag['title'].lower() and g_song['artist'].lower() == tag['artist'].lower()) or\
           (g_song['album'].lower() == tag['album'].lower() and g_song['title'].lower() == tag['title'].lower()) or\
           (g_song['artist'].lower() == tag['artist'].lower() and g_song['album'].lower() == tag['album'].lower() and g_song['track'] == tag['track']):
            print "Partial match\t%s\t%s\t%s" % (
                g_song['title'].encode('cp1252'),
                g_song['artist'].encode('cp1252'),
                g_song['album'].encode('cp1252'))
        return g_song['title'].lower() == tag['title'].lower() and\
               g_song['artist'].lower() == tag['artist'].lower() and\
               g_song['album'].lower() == tag['album'].lower() #and\
        #g_song['track'] == tag['track']

    def delete_song(self, sid):
        self.mc.delete_songs(sid)
        print "Deleted song by id [%s]" % sid

    def get_platform_path(self, full_path):
        # Try to avoid messing with the path if possible
        if os.sep == '/' and '\\' not in full_path:
            return full_path
        if os.sep == '\\' and '\\' in full_path:
            return full_path
        if '\\' not in full_path:
            return full_path
        return os.path.normpath(full_path.replace('\\', '/'))
class MusicSync(object):
    def __init__(self, email=None, password=None):
        self.mm = Musicmanager()
        self.wc = Webclient()
        self.mc = Mobileclient()
        if not email:
            email = raw_input("Email: ")
        if not password:
            password = getpass()

        self.email = email
        self.password = password

        self.logged_in = self.auth()

        print "Fetching playlists from Google..."
        self.playlists = self.mc.get_all_user_playlist_contents()
        #self.playlists = self.mc.get_all_playlists()
        #self.playlists = self.wc.get_all_playlist_ids(auto=False)
        self.all_songs = self.mc.get_all_songs()
        #print "Got %d playlists." % len(self.playlists['user'])
        print "Got %d playlists containing %d songs." % (len(self.playlists), len(self.all_songs))
        print ""


    def auth(self):
        self.logged_in = self.mc.login(self.email, self.password)
        #self.logged_in = self.wc.login(self.email, self.password)
        if not self.logged_in:
            print "Login failed..."
            exit()

        print ""
        print "Logged in as %s" % self.email
        print ""

        if not os.path.isfile(OAUTH_FILEPATH):
            print "First time login. Please follow the instructions below:"
            self.mm.perform_oauth()
        self.logged_in = self.mm.login()
        if not self.logged_in:
            print "OAuth failed... try deleting your %s file and trying again." % OAUTH_FILEPATH
            exit()

        print "Authenticated"
        print ""


    def sync_playlist(self, filename, remove_missing):
    #def sync_playlist(self, filename, remove_missing=False):
        filename = self.get_platform_path(filename)
        os.chdir(os.path.dirname(filename))
        title = os.path.splitext(os.path.basename(filename))[0]
        print "Syncing playlist: %s" % filename
        #if title not in self.playlists['user']:
            #print "   didn't exist... creating..."
            #self.playlists['user'][title] = [self.wc.create_playlist(title)]
        print ""

        plid = ""

        for pl in self.playlists:
            if pl['name'] == title:
                plid = pl['id']
                goog_songs = pl['tracks']

        if plid == "":
            print "   didn't exist... creating..."
            plid = self.mc.create_playlist(self, title)

        #plid = self.playlists['user'][title][0]
        #goog_songs = self.wc.get_playlist_songs(plid)
        print "%d songs already in Google Music playlist" % len(goog_songs)
        pc_songs = self.get_files_from_playlist(filename)
        print "%d songs in local playlist" % len(pc_songs)
        print ""

        # Sanity check max 1000 songs per playlist
        if len(pc_songs) > MAX_SONGS_IN_PLAYLIST:
            print "    Google music doesn't allow more than %d songs in a playlist..." % MAX_SONGS_IN_PLAYLIST
            print "    Will only attempt to sync the first %d songs." % MAX_SONGS_IN_PLAYLIST
            del pc_songs[MAX_SONGS_IN_PLAYLIST:]

        existing_files = 0
        added_files = 0
        failed_files = 0
        removed_files = 0
        fatal_count = 0

        for fn in pc_songs:
            if self.file_already_in_list(fn, goog_songs, self.all_songs):
                existing_files += 1
                continue
            print ""
            print "Adding: %s" % os.path.basename(fn).encode('cp1252')
            #print "Adding: %s" % os.path.basename(fn)
            #online = False
            online = self.find_song(fn, goog_songs, self.all_songs)
            #online = self.find_song(fn)
            song_id = None
            if online:
                song_id = online['id']
                print "   already uploaded [%s]" % song_id
            else:
                attempts = 0
                result = []
                while not result and attempts < MAX_UPLOAD_ATTEMPTS_PER_FILE:
                    print "   uploading... (may take a while)"
                    attempts += 1
                    try:
                        result = self.mm.upload(fn)
                    except (BadStatusLine, CannotSendRequest):
                        # Bail out if we're getting too many disconnects
                        if fatal_count >= MAX_CONNECTION_ERRORS_BEFORE_QUIT:
                            print ""
                            print "Too many disconnections - quitting. Please try running the script again."
                            print ""
                            exit()

                        print "Connection Error -- Reattempting login"
                        fatal_count += 1
                        self.wc.logout()
                        self.mc.logout()
                        self.mm.logout()
                        result = []
                        time.sleep(STANDARD_SLEEP)

                    except:
                        result = []
                        time.sleep(STANDARD_SLEEP)

                try:
                    if result[0]:
                        song_id = result[0].itervalues().next()
                    else:
                        song_id = result[1].itervalues().next()
                    print "   upload complete [%s]" % song_id
                except:
                    print "      upload failed - skipping"
                    tag = self.get_id3_tag(fn)
                    print "      failed song:\t%s\t%s\t%s" % (tag['title'].encode('cp1252'), tag['artist'].encode('cp1252'), tag['album'].encode('cp1252'))

            if not song_id:
                failed_files += 1
                continue

            added = self.mc.add_songs_to_playlist(plid, song_id)
            time.sleep(.3) # Don't spam the server too fast...
            print "   done adding to playlist"
            added_files += 1

        if remove_missing:
            for g in goog_songs:
                for s in self.all_songs:
                    if g['trackId'] == s['id']:
                        print ""
                        print "Removing: %s" % s['title'].encode('cp1252')
                        self.mc.remove_entries_from_playlist(g['id'])
                        #self.wc.remove_songs_from_playlist(plid, s.id)
                        time.sleep(.3) # Don't spam the server too fast...
                        removed_files += 1

        print ""
        print "---"
        print "%d songs unmodified" % existing_files
        print "%d songs added" % added_files
        print "%d songs failed" % failed_files
        print "%d songs removed" % removed_files


    def get_files_from_playlist(self, filename):
        files = []
        f = codecs.open(filename, encoding='cp1252')
        #f = codecs.open(filename, encoding='utf-8')
        for line in f:
            line = line.rstrip().replace(u'\ufeff',u'')
            if line == "" or line[0] == "#":
                continue
            path  = os.path.abspath(self.get_platform_path(line))
            if not os.path.exists(path):
                print "File not found: %s" % line
                continue
            files.append(path)
        f.close()
        return files

    def file_already_in_list(self, filename, goog_songs, all_songs):
        tag = self.get_id3_tag(filename)
        print "Searching for\t%s\t%s\t%s" % (tag['title'].encode('cp1252'), tag['artist'].encode('cp1252'), tag['album'].encode('cp1252'))
        i = 0
        while i < len(goog_songs):
            for s in all_songs:
                if goog_songs[i]['trackId'] == s['id']:
                    if self.tag_compare(s, tag):
                        print "Found match\t%s\t%s\t%s" % (s['title'].encode('cp1252'), s['artist'].encode('cp1252'), s['album'].encode('cp1252'))
                        goog_songs.pop(i)
                        return True
            i += 1
        return False

    def get_id3_tag(self, filename):
        data = mutagen.File(filename, easy=True)
        r = {}
        if 'title' not in data:
            title = os.path.splitext(os.path.basename(filename))[0]
            print 'Found song with no ID3 title, setting using filename:'
            print '  %s' % title
            print '  (please note - the id3 format used (v2.4) is invisible to windows)'
            data['title'] = [title]
            data.save()
        r['title'] = data['title'][0]
        r['track'] = int(data['tracknumber'][0].split('/')[0]) if 'tracknumber' in data else 0
        # If there is no track, try and get a track number off the front of the file... since thats
        # what google seems to do...
        # Not sure how google expects it to be formatted, for now this is a best guess
        if r['track'] == 0:
            m = re.match("(\d+) ", os.path.basename(filename))
            if m:
                r['track'] = int(m.group(0))
        r['artist'] = data['artist'][0] if 'artist' in data else ''
        r['album'] = data['album'][0] if 'album' in data else ''
        return r

    def find_song(self, filename, goog_songs, all_songs):
        tag = self.get_id3_tag(filename)
        print "Searching for\t%s\t%s\t%s" % (tag['title'].encode('cp1252'), tag['artist'].encode('cp1252'), tag['album'].encode('cp1252'))
        #results = self.wc.search(tag['title'])
        # NOTE - diagnostic print here to check results if you're creating duplicates
        #print results['song_hits']
        #for r in goog_songs:
        #for r in results['song_hits']:
        for s in all_songs:
            #if r['trackId'] == s['id']:
            if self.tag_compare(s, tag):
                # TODO: add rough time check to make sure its "close"
                print "Found match\t%s\t%s\t%s" % (s['title'].encode('cp1252'), s['artist'].encode('cp1252'), s['album'].encode('cp1252'))
                return s
        return None

    def tag_compare(self, g_song, tag):
        # If a google result has no track, google doesn't return a field for it
        if 'title' not in g_song:
            g_song['title'] = ""
        if 'artist' not in g_song:
            g_song['artist'] = ""
        if 'album' not in g_song:
            g_song['album'] = ""
        if 'track' not in g_song:
            g_song['track'] = 0
        if (g_song['title'].lower() == tag['title'].lower() and g_song['artist'].lower() == tag['artist'].lower()) or\
           (g_song['album'].lower() == tag['album'].lower() and g_song['title'].lower() == tag['title'].lower()) or\
           (g_song['artist'].lower() == tag['artist'].lower() and g_song['album'].lower() == tag['album'].lower() and g_song['track'] == tag['track']):
            print "Partial match\t%s\t%s\t%s" % (g_song['title'].encode('cp1252'), g_song['artist'].encode('cp1252'), g_song['album'].encode('cp1252'))
        return g_song['title'].lower() == tag['title'].lower() and\
               g_song['artist'].lower() == tag['artist'].lower() and\
               g_song['album'].lower() == tag['album'].lower() #and\
               #g_song['track'] == tag['track']

    def delete_song(self, sid):
        self.mc.delete_songs(sid)
        print "Deleted song by id [%s]" % sid

    def get_platform_path(self, full_path):
        # Try to avoid messing with the path if possible
        if os.sep == '/' and '\\' not in full_path:
            return full_path
        if os.sep == '\\' and '\\' in full_path:
            return full_path
        if '\\' not in full_path:
            return full_path
        return os.path.normpath(full_path.replace('\\', '/'))
Example #9
0
# google play musicの一致するプレイリストを取得
filteredPlaylistsAndContentsIter = filter(
    lambda v: v['name'] == iPlaylist.itunesAttibutes['Name'],
    gPlaylistsAndContents)

# 一致するプレイリストが見つかったら
for filteredPlaylistAndContents in filteredPlaylistsAndContentsIter:
    # googleplaymusicのプレイリストIDを取得
    gPlaylistId = filteredPlaylistAndContents['id']

    # プレイリストに含まれるトラックidのリストを取得して
    includeTrackIdsIter = map(lambda v: v['id'],
                              filteredPlaylistAndContents['tracks'])

    # プレイリストから消去
    mc.remove_entries_from_playlist(
        [trackId for trackId in includeTrackIdsIter])
    break

# プレイリストの登録曲数がgoogle play musicの最大登録数よりも多い場合は
iPlaylistItems = len(iPlaylist.items)
if (iPlaylistItems > MAX_GPLAYLIST_SONGS_NUM):
    # オーバーしている旨のメッセージを出す
    print("playlistName = {p} is over max playlist song size :{n}".format(
        p=iPlaylist.itunesAttibutes['Name'], n=iPlaylistItems))
    # プレイリストが存在している場合は削除する。
    if gPlaylistId != None:
        mc.delete_playlist(gPlaylistId)
    # return
    exit()

# プレイリストが見つからなかったら新たに作成する。
Example #10
0
class GoogleMusic:
    def __init__(self):
        self.api = Mobileclient(debug_logging=False)
        with open(path + "oauth.cred", 'w+') as tmp:
            tmp.write(settings['google']['mobileclient'])
            tmp.close()
            self.api.oauth_login(Mobileclient.FROM_MAC_ADDRESS, tmp.name)
            os.remove(tmp.name)

    def createPlaylist(self, name, songs, public):
        playlistId = self.api.create_playlist(name=name, description=None, public=public)
        self.addSongs(playlistId, songs)
        print("Success: created playlist \"" + name + "\"")

    def addSongs(self, playlistId, songs):
        songIds = []
        songlist = list(songs)
        notFound = list()
        for i, song in enumerate(songlist):
            song = song.replace(" &", "")
            result = self.api.search(query=song, max_results=2)
            if len(result['song_hits']) == 0:
                notFound.append(song)
            else:
                songIds.append(self.get_best_fit_song_id(result['song_hits'], song))
            if i % 20 == 0:
                print(str(i) + ' searched')

        self.api.add_songs_to_playlist(playlistId, songIds)

        with open(path + 'noresults.txt', 'w', encoding="utf-8") as f:
            f.write("\n".join(notFound))
            f.close()

    def removeSongs(self, playlistId):
        pl = self.api.get_all_user_playlist_contents()
        tracks = next(x for x in pl if x['id'] == playlistId)['tracks']
        self.api.remove_entries_from_playlist([x['id'] for x in tracks])

    def getPlaylistId(self, name):
        pl = self.api.get_all_playlists()
        return next(x for x in pl if x['name'].find(name) != -1)['id']

    def get_best_fit_song_id(self, results, song):
        match_score = {}
        for res in results:
            compare = res['track']['artist'] + ' ' + res['track']['title']
            match_score[res['track']['storeId']] = difflib.SequenceMatcher(a=song.lower(), b=compare.lower()).ratio()

        return max(match_score, key=match_score.get)

    def remove_playlists(self, pattern):
        pl = self.api.get_all_playlists()
        p = re.compile("{0}".format(pattern))
        matches = [song for song in pl if p.match(song['name'])]
        print("The following playlists will be removed:")
        print("\n".join([song['name'] for song in matches]))
        print("Please confirm (y/n):")

        choice = input().lower()
        if choice[:1] == 'y':
            [self.api.delete_playlist(song['id']) for song in matches]
            print(str(len(matches)) + " playlists deleted.")
        else:
            print("Aborted. No playlists were deleted.")
Example #11
0
class MusicPlayer(object):

    def __init__(self):
        self.playlist = []                  # Array of all tracks
        self.playlist_id = 0                # Id of playlist
        self.current_track_index = 0        # Index of current song
        self.player = Player()              # MPlayer instance
        self.webclient = Webclient()        # Client for WebInterface
        self.mobileclient = Mobileclient()  # Client for MobileInterface
        self.timer = None                   # Timer to start next track
        self.deviceid = 0                   # DeviceId to use
        self.playtype = PlayType.LINEAR     # LINEAR or SHUFFLE

    def login(self, username, password):
        """ Login to Google Music.

        Keyword arguments:
        username -- the username
        password -- the password

        Returns:
        True if successful else False

        """

        # If either the web client or the mobile client failed to login return False
        if not self.webclient.login(username, password) or not self.mobileclient.login(username, password):
            return False

        # Use first found devices as ID
        devices = self.webclient.get_registered_devices();

        # Convert HEX to INT
        self.deviceid = int(devices[0]['id'], 16)

        return True

    def load_playlist(self, playlist_name):
        # Load playlist
        for playlist in self.mobileclient.get_all_user_playlist_contents():
            if playlist['name'] == playlist_name:
                for track_obj in playlist['tracks']:
                    track_obj['track']['id'] = track_obj['id']
                    self.playlist.append(track_obj['track'])

                # Set playlist_id
                self.playlist_id = playlist['id']
                break;

        # If playlist has not been found, create it
        if self.playlist_id == 0:
            self.playlist_id = self.mobileclient.create_playlist(playlist_name)

    def add_track_to_playlist(self, track):
        """ Append a track to the end of playlist

        Keyword arguments:
        track -- a dictionary containing the track informations

        """
        track_id = self.mobileclient.add_songs_to_playlist(self.playlist_id, track['nid'])[0]
        track['id'] = track_id
        self.playlist.append(track)

        # Notify all clients about the new track
        factory.forwarder.dispatch(PLAYLIST_EVENT_TRACK_ADDED, json.dumps(track))

    def remove_track_from_playlist(self, track_id):
        """ Removes a track from the playlist

        Keyword arguments:
        track_id -- The id of the track to remove

        """
        self.mobileclient.remove_entries_from_playlist(track_id)

        index_to_remove = self._find_index_of_track_id(track_id)

        del self.playlist[index_to_remove]

        factory.forwarder.dispatch(PLAYLIST_EVENT_TRACK_REMOVED, track_id)

    def play_track(self, track_id):
        """ Play a track

        Keyword arguments:
        track_id -- Id of the track to play

        """

        index_of_track = self._find_index_of_track_id(track_id)

        track_to_play = self.playlist[index_of_track]

        if track_to_play is not None:
            # Request stream url from google music
            stream_url = self.mobileclient.get_stream_url(track_to_play["storeId"], self.deviceid)

            # Load stream url to mplayer
            self.player.loadfile(stream_url)

            # For some reason OSX needs to unpause mplayer
            if sys.platform == "darwin":
                self.player.pause()

            # Set track
            self.current_track_index = index_of_track

            # Cancel previous timer
            if self.timer is not None:
                self.timer.cancel()

            # How many minutes does the track last
            track_duration = long(track_to_play["durationMillis"]) / 1000

            # Set Timer to play next track when trackDuration is over
            self.timer = Timer(track_duration, self.play_next_track)
            self.timer.daemon = True
            self.timer.start()

            print "playing", track_to_play["artist"], " - ", track_to_play["title"], " : ", stream_url

            # Fire event that a new track is playing
            factory.forwarder.dispatch(TRACK_EVENT_PLAYBACK, json.dumps(track_to_play))

            return True
        else:
            return False

    def play_next_track(self):
        """ Play the next track in the playlist.

        Returns:
        True or False

        """

        if self.playtype == PlayType.LINEAR:
            # Index of next track to play
            next_track_index = self.current_track_index + 1

            # Restart at index 0 if end of playlist is reached
            if next_track_index >= len(self.playlist):
                next_track_index = 0

        elif self.playtype == PlayType.SHUFFLE:
            # Index of next track to play at random
            next_track_index = random.randrange(0, len(self.playlist), 1)

        # Obtain the id of the next track to play
        next_track_id = self.playlist[next_track_index]['id']

        # Play track with that id
        return self.play_track(next_track_id)

    def play_previous_track(self):
        """ Play the previous track in the playlist.

        Returns:
        True or False

        """

        if self.playtype == PlayType.LINEAR:
            # Index of previous track to play
            previous_track_index = self.current_track_index - 1

            # Contiune from the end of the playlist
            if previous_track_index <= 0:
                previous_track_index = len(self.playlist) - 1

        elif self.playtype == PlayType.SHUFFLE:
            # Index of the previous track is random
            previous_track_index = random.randrange(0, len(self.playlist), 1)

        # Obtain the id of the previous track to play
        previous_track_id = self.playlist[previous_track_index]['id']

        # Play track with that id
        return self.play_track(previous_track_id)

    def stop(self):
        """ Stop playback.

        """

        if self.timer is not None:
            self.timer.cancel()

        if self.player is not None:
            self.player.stop()

    def play(self):
        """ Start playing current track

        Returns:
        True if track has been started. Else False

        """
        current_track_id = self.playlist[self.current_track_index]
        return self.play_track(current_track_id)

    def _find_index_of_track_id(self, track_id):
        index = 0

        for track in self.playlist:
            if track['id'] == track_id:
                return index
            index += 1

        return None
# Get contents of our playlist
playlist = list(
    filter(lambda p: p['id'] == playlistId,
           mc.get_all_user_playlist_contents()))[0]

# If a track's been modified since it was added, it's been played.
# Find all the played tracks at the start of the playlist.
playedTracks = list(
    takewhile(
        lambda pt: pt['creationTimestamp'] < list(
            filter(lambda t: t['id'] == pt['trackId'], allTracks))[0][
                'lastModifiedTimestamp'], playlist['tracks']))
playedTrackIds = list(map(lambda pt: pt['id'], playedTracks))

# Remove the played tracks from the playlist
mc.remove_entries_from_playlist(playedTrackIds)
print('Removed {0} played tracks'.format(len(playedTrackIds)))

trackCount = len(playlist['tracks']) - len(playedTrackIds)
print('{0} tracks on playlist'.format(trackCount))

# Pick out all the albums from the songs our library and shuffle them
albums = list(
    set(map(lambda t: t['albumArtist'] + '/' + t['album'], allTracks)))
random.shuffle(albums)

# Keep adding albums until we've got at least 900 tracks on the playlist
while trackCount < 900:
    album = albums.pop(0)

    # Get the tracks on the album sorted by track number
class PlaylistManager(object):
    def __init__(self, email_file):
        self.login(email_file)
        self._get_songs()
        self._get_playlists()

    def login(self, email_file):
        with open(os.path.expanduser(email_file), 'r') as gmail_email_file:
            gmail_email = gmail_email_file.read()
        print "Password for " + gmail_email.strip('\n') + ":"
        pw = getpass.getpass()
        self.client = Mobileclient()
        self.client.login(gmail_email, pw)

    def _get_songs(self):
        self.all_songs = self.client.get_all_songs()
        assert isinstance(self.all_songs, list)
        self.all_songs_by_id = {}
        for song in self.all_songs:
            self.all_songs_by_id[song['id']] = song

    def _playlist_entry_dict(self, entry_dict, playlist_name):
        track_dict = self.all_songs_by_id[entry_dict['trackId']]
        track_hash = hash(playlist_name + track_dict['title'] + track_dict['artist'] + track_dict['album'])
        return {'title': track_dict['title'], 'entry_id': entry_dict['id'], 'track_id': entry_dict['trackId'],
                'hash': track_hash}

    def _get_playlists(self):
        self.all_playlists = self.client.get_all_user_playlist_contents()
        assert isinstance(self.all_playlists, list)


    def sort_and_deduplicate_playlists(self):
        """de-duplicates and then sorts all user playlists"""
        playlist_entry_ids_to_be_removed = []
        for playlist in self.all_playlists:
            current_playlist = []
            current_playlist_entry_hashes = []
            for track in playlist['tracks']:
                if not track['deleted']:
                    current_track = self._playlist_entry_dict(track, playlist['name'])
                    if not current_track['hash'] in current_playlist_entry_hashes:
                        current_playlist.append(current_track)
                        current_playlist_entry_hashes.append(current_track['hash'])
                    else:
                        # we will remove these duplicates later, so they don't mess up our sorting
                        playlist_entry_ids_to_be_removed.append(current_track['entry_id'])
            if playlist_entry_ids_to_be_removed != []:
                print "De-duplicated " + playlist['name']
            get_track_title = lambda track_dict: track_dict['title']
            sorted_songs = sorted(current_playlist, key=get_track_title)
            sorted_track_ids = []
            sorted_entry_ids = []
            for track in sorted_songs:
                sorted_track_ids.append(track['track_id'])
                sorted_entry_ids.append(track['entry_id'])
            # if the playlist is already sorted, don't bother sorting it
            if sorted_songs != current_playlist:
                # remove all things at once for maximum efficiency
                self.client.add_songs_to_playlist(playlist['id'], sorted_track_ids)
                playlist_entry_ids_to_be_removed += sorted_entry_ids
                print "Re-ordered " + playlist['name']
        if playlist_entry_ids_to_be_removed != []:
            # remove all things to be removed at once
            self.client.remove_entries_from_playlist(playlist_entry_ids_to_be_removed)

    def export_songs(self, csv_output):
        """writes a csv file containing info on all the songs"""
        # these are the field names. More might exist, but I haven't found them
        field_names = [u'comment', u'rating', u'composer', u'year', u'creationTimestamp', u'id', u'album',
                       u'totalDiscCount', u'title', u'recentTimestamp', u'albumArtist', u'trackNumber', u'discNumber',
                       u'deleted', u'totalTrackCount', u'estimatedSize', u'beatsPerMinute', u'genre', u'playCount',
                       u'kind', u'artist', u'lastModifiedTimestamp', u'clientId', u'durationMillis', u'albumArtRef',
                       u'artistId', u'storeId', u'nid', u'albumId', u'artistArtRef', u'trackType', u'trackOrigin',
                       u'contentType', u'lastRatingChangeTimestamp']
        with open(csv_output, 'w') as output_file_obj:
            csv_writer = csv.DictWriter(output_file_obj, field_names)
            csv_writer.writeheader()
            for song in self.all_songs:
                for x in song:
                    # remove the unicode, replacing bad characters with "?"
                    if isinstance(song[x], unicode):
                        song[x] = song[x].encode('ascii', 'replace')
                csv_writer.writerow(song)

    def export_playlists(self, output_path):
        """writes the csv contents of each playlist to the playlist-named file
        in the specified folder"""
        if not os.path.exists(output_path):
            os.mkdir(output_path)
        if not os.path.isdir(output_path):
            raise Exception("Not a folder!")
        playlist_entry_keys = [u'absolutePosition', u'clientId', u'creationTimestamp', u'deleted', u'id', u'kind',
                               u'lastModifiedTimestamp', u'playlistId', u'source', u'trackId']
        for playlist in self.all_playlists:
            file_name = os.path.join(output_path, playlist[u'name'] + '.csv')
            with open(file_name, 'w') as output_file:
                csv_writer = csv.DictWriter(output_file, playlist_entry_keys)
                csv_writer.writeheader()
                for track in playlist[u'tracks']:
                    for x in track:
                        # remove the unicode, replacing bad characters with "?"
                        if isinstance(track[x], unicode):
                            track[x] = track[x].encode('ascii', 'replace')
                    csv_writer.writerow(track)


    def make_local_xspf_playlists(self):
        """write playlists in xspf format to named files in the playlist folder.
        Credit to https://github.com/alastair/xspf for the wonderful xspf python module"""
        # output_path = 'playlists'
        output_path = os.path.expanduser('~/Music/Playlists')
        music_path = os.path.expanduser('~/Music')
        extension = '.mp3'
        if not os.path.exists(output_path):
            os.mkdir(output_path)
        if not os.path.isdir(output_path):
            raise Exception("Not a folder!")
        for playlist in self.all_playlists:
            output_file_path = os.path.join(output_path, playlist[u'name'] + '.xspf')
            playlist_xspf = xspf.Xspf()
            playlist_xspf.title = playlist[u'name']
            for track in playlist['tracks']:
                track_xspf = xspf.Track()
                track_id = track['trackId']
                track_dict = self.all_songs_by_id[track_id]
                artist = track_dict['artist']
                album = track_dict['album']
                title = track_dict['title']
                track_xspf.title = title
                track_xspf.album = album
                track_xspf.creator = artist
                # replace is to fix the slash in 'AC/DC'
                track_path = 'file://' + os.path.join(music_path, artist.replace('/', ','), album.replace('/', ','),
                                                      title.replace('/', ',') + extension)
                track_xspf.location = track_path
                length = str(int(track_dict['durationMillis']) / 1000)
                track_xspf.duration = length
                playlist_xspf.add_track(track_xspf)
            with open(output_file_path, 'wb') as output_file:
                # we write this header so that Sublime Text recognizes it as an XML file, and sets syntax accordingly
                output_file.write('<?xml version="1.0" encoding="UTF-8"?>\n')
                output_file.write(playlist_xspf.toXml(pretty_print=True))
Example #14
0
    index = -1
    # Ensure no duplicate songs in the playlist
    while (unused_index == False):
        # Randomly select a number from the total length of songs
        index = random.randint(0, len(songs) - 1)
        try:
            # Will error if the number has not already been used
            used_index.index(index)
        except ValueError:
            # If it errors, add the value and continue
            used_index.append(index)
            # Break out of the loop
            unused_index = True
    reshuffled_songs.append(songs[index])
# Get all current songs in the reshuffled playlist
current_songs = mc.get_all_user_playlist_contents()
# Delete all songs from current playlist
for playlist in current_songs:
    # Find the correct playlist
    if playlist.get('id') == reshuffled_playlist_id:
        print('Deleting ', len(playlist.get('tracks')),
              ' old songs from the reshuffled playlist')
        # Iterate over the tracks in it
        for song in playlist.get('tracks'):
            mc.remove_entries_from_playlist(song.get('id'))
# Add new to playlist
print('Adding new songs')
for song in reshuffled_songs:
    mc.add_songs_to_playlist(reshuffled_playlist_id, song.get('id'))
# End
print('Done')
category_a_playlist = [p for p in playlists if p['name'] == secret.CATEGORY_A][0]
category_b_playlist = [p for p in playlists if p['name'] == secret.CATEGORY_B][0]

# Splitting up songs by whether they are categorized or not
all_songs_set = get_trackids_set(big_playlist)
cat_a_songs_set = get_trackids_set(category_a_playlist)
cat_b_songs_set = get_trackids_set(category_b_playlist)
all_categorized_songs_set = cat_a_songs_set | cat_b_songs_set
uncategorized_songs_set = all_songs_set - all_categorized_songs_set

# Remove songs from uncategorized that have been categorized already
print("Removing newly categorized songs from the uncategorized playlist named", secret.UNCATEGORIZED)
uncategorized_playlist_songs_set = get_trackids_set(uncategorized_playlist)
already_categorized_songs_set = all_categorized_songs_set & uncategorized_playlist_songs_set
already_categorized_songs_ids = [song['id'] for song in uncategorized_playlist['tracks'] if song['trackId'] in already_categorized_songs_set]
api.remove_entries_from_playlist(already_categorized_songs_ids)
print("Removed", len(already_categorized_songs_ids), "songs from the uncategorized playlist named", secret.UNCATEGORIZED)

# Add songs that are not categorized, to uncategorized
# First, don't re-add songs that are still uncategorized
print("Adding uncategorized songs to playlist named",  secret.UNCATEGORIZED)
newly_uncategorized_songs_set = uncategorized_songs_set - uncategorized_playlist_songs_set
api.add_songs_to_playlist(uncategorized_playlist['id'], list(newly_uncategorized_songs_set))
print("Success! Added", len(newly_uncategorized_songs_set), "songs to playlist named", secret.UNCATEGORIZED)
api.logout()
print("Logged out")




Example #16
0
class Gopma():
    def __init__(self, action=None):
        print "Initialising GOPMA."
        config = ConfigParser.ConfigParser()
        config.read('config.ini')

        email = config.get('login', 'email')
        password = config.get('login', 'password')
        try:
            auth_token = config.get('login', 'auth_token')
        except:
            auth_token = False
            print "No auth token could be found"

        print "Logging into Google Play Music as", email
        logged_in = False
        bad_auth = False
        while not logged_in:
            if not auth_token or bad_auth:
                self.api = Mobileclient()
                login = self.api.login(email, password,
                                       Mobileclient.FROM_MAC_ADDRESS)
                if not login:
                    print "Login failed, check your credentials."
                    sys.exit()

                # Save the auth token for later
                with open('config.ini', 'w+') as f:
                    config.set('login', 'auth_token',
                               self.api.session._authtoken)
                    config.write(f)
                    f.close()
                    print "Saved auth token for later."

                logged_in = True
            else:
                print "Found an auth token, trying it."
                self.api = Mobileclient()
                self.api.session._authtoken = auth_token
                self.api.session.is_authenticated = True
                try:
                    # Test the auth token
                    self.api.get_registered_devices()
                    logged_in = True
                except:
                    # Failed
                    print "Bad auth token, manually signing in."
                    bad_auth = True
        print "Successfully logged in as", email

        if action != 'reset_genres':
            print "Loading data."
            self.playlists = self.api.get_all_playlists()
            self.content = self.api.get_all_user_playlist_contents()
            self.root_genres, self.child_genres = self.load_genres()
            print "Data successfully loaded."

    def create_or_retrieve_playlists(self, playlists):
        """ Helper function to create or retrieve playlist IDs for a given agg_lists

            Input: List of playlist names
            Output: Dict of playlist names and IDs
        """
        if type(playlists) is not list:
            print "Stop passing non-lists to this function."
            sys.exit()

        agg_lists = [
            p for p in self.content
            if p.get('type') == 'USER_GENERATED' and p.get('name') in playlists
        ]

        # Get all playlist IDs
        agg_playlists = {}
        existing_playlists = [playlist['name'] for playlist in agg_lists]
        for name in playlists:
            if name not in existing_playlists:
                print "Playlist not found, creating", name
                agg_playlists[name] = self.api.create_playlist(name)
                self.api.edit_playlist(agg_playlists[name], public=True)
            else:
                print "Playlist found", name + ", retrieving ID."
                playlist_id = [
                    p['id'] for p in agg_lists if p.get('name') == name
                ][0]
                agg_playlists[name] = playlist_id
                # self.api.edit_playlist(agg_playlists[name], public=True)

        return agg_playlists

    def load_genres(self, reset=False):
        """ Load all genres
        """
        # Get the root genres
        if os.path.isfile(ROOT_GENRE_FILE):
            print "Found a root genres file."
            if reset:
                root_genres = self.api.get_genres()

                with open(ROOT_GENRE_FILE, 'w') as fp:
                    pickle.dump(root_genres, fp)
                print "Root genres have been reset."
            else:
                with open(ROOT_GENRE_FILE) as fp:
                    root_genres = pickle.load(fp)
        else:
            print "Couldn't find a root genres file, retrieving data."
            root_genres = self.api.get_genres()

            with open(ROOT_GENRE_FILE, 'w') as fp:
                pickle.dump(root_genres, fp)

            print "Root genres file created."

        # Get the child genres
        if os.path.isfile(CHILD_GENRE_FILE):
            print "Found a child genres file."
            if reset:
                child_genres = {}

                for genre in root_genres:
                    children = self.api.get_genres(genre['id'])
                    child_names = []
                    for child in children:
                        child_names.append(child['name'])
                    child_genres[genre['id']] = child_names

                with open(CHILD_GENRE_FILE, 'w') as fp:
                    pickle.dump(child_genres, fp)
                print "Child genres have been reset."
            else:
                with open(CHILD_GENRE_FILE) as fp:
                    child_genres = pickle.load(fp)
        else:
            print "Couldn't find a child genres file, retrieving data."
            child_genres = {}

            for genre in root_genres:
                children = self.api.get_genres(genre['id'])
                child_names = []
                for child in children:
                    child_names.append(child['name'])
                child_genres[genre['id']] = child_names

            with open(CHILD_GENRE_FILE, 'w') as fp:
                pickle.dump(child_genres, fp)
            print "Child genres file created."

        return root_genres, child_genres

    def delete_empty_playlists(self):
        """ Delete ALL empty playlists. Be careful with this.
        """
        playlists = self.content
        for playlist in playlists:
            if len(playlist['tracks']
                   ) == 0 and playlist['name'] != AGGREGATE_PLAYLIST_NAME:
                self.api.delete_playlist(playlist['id'])
                print "Deleted", playlist['name']

    def create_playlists(self):
        """ Create all needed playlists
        """
        print "Creating/updating playlists."
        self.create_or_retrieve_playlists(
            [AGGREGATE_PLAYLIST_NAME, SHARED_PLAYLIST_NAME])
        self.create_or_retrieve_playlists(
            [PLAYLIST_PREFIX + genre for genre in GENRE_PLAYLISTS.values()])

    def get_playlist_urls(self):
        """ Get all gopma playlist URLS
        """
        urls = {}
        for playlist in self.playlists:
            if PLAYLIST_PREFIX in playlist['name'] and playlist[
                    'type'] == 'USER_GENERATED':
                urls[playlist[
                    'name']] = "https://play.google.com/music/playlist/" + playlist[
                        'shareToken']
        return urls

    def get_playlist_id(self, name):
        """ Get the playlist ID for a given playlist name
        """
        playlist = [p for p in self.playlists if p.get('name') == name][0]
        return playlist['id']

    def get_share_token(self, playlist_id):
        """ Get the share token for a given playlist ID
        """
        playlist = [p for p in self.playlists if p.get('id') == playlist_id]
        return playlist[0]['shareToken']

    def get_playlist_tracks(self, playlist_id):
        """ Get the tracks for a specified playlist id
        """
        return [p for p in self.content
                if p.get('id') == playlist_id][0]['tracks']

    def get_parent_genre_id(self, genre_name):
        """ Get the parent id for a given genre name
        """
        # Check the root genres first
        for genre in self.root_genres:
            if genre_name == genre['name']:
                return genre['id']

        # Check children genres
        for gid, genres in self.child_genres.items():
            for genre in genres:
                if genre == genre_name:
                    return gid

    def wipe_all_playlists(self):
        """ Wipe all Gopma playlists
        """
        for playlist in self.playlists:
            if PLAYLIST_PREFIX in playlist[
                    'name'] and SHARED_PLAYLIST_NAME not in playlist['name']:
                print "Wiping playlist: ", playlist['name']
                self.wipe_playlist(playlist['id'])

    def wipe_playlist(self, playlist_id):
        """ Wipe a given playlist
        """
        playlist_tracks = self.get_playlist_tracks(playlist_id)
        song_ids = [track['id'] for track in playlist_tracks]
        self.api.remove_entries_from_playlist(song_ids)

    def reset_daily_playlists(self):
        """ Reset the daily playlists
        """
        # Get playlists
        agg_playlists = self.create_or_retrieve_playlists([TODAY, YESTERDAY])
        yest_id = agg_playlists[YESTERDAY]
        today_id = agg_playlists[TODAY]

        # Wipe yesterday
        print "Wiping yesterday's playlist."
        self.wipe_playlist(yest_id)

        # Copy today to yesterday
        print "Copying", TODAY, "to", YESTERDAY
        today_tracks = self.get_playlist_tracks(today_id)
        self.api.add_songs_to_playlist(yest_id,
                                       [t['trackId'] for t in today_tracks])

        # Wipe today
        print "Wiping today's playlist."
        self.wipe_playlist(today_id)

    def update_group_playlist(self):
        """ Update the big group aggregate and the daily playlist with any new shared songs
        """
        # Get the aggregate playlist songs
        agg_token = self.get_share_token(
            self.get_playlist_id(AGGREGATE_PLAYLIST_NAME))
        agg_playlists = [
            p for p in self.playlists if p.get('type') == 'USER_GENERATED'
            and p.get('shareToken') == agg_token
        ]
        agg_id = agg_playlists[0]['id']

        # Get tracks
        agg_tracks = self.api.get_shared_playlist_contents(agg_token)
        agg_tracks_ids = [track['trackId'] for track in agg_tracks]
        print "Updating group playlists."

        # Get the playlists we want to update with
        shared_lists = [
            p for p in self.playlists if p.get('name') == SHARED_PLAYLIST_NAME
        ]

        for playlist in shared_lists:
            shared_tracks = self.api.get_shared_playlist_contents(
                playlist['shareToken'])
            print "\nRetrieving from", playlist[
                'name'], "by", playlist['ownerName'] + ":"

            # Add songs to aggregate playlist
            if len(shared_tracks) == 0:
                print "<< Playlist is empty. >>"
            else:
                no_new = True
                for track in shared_tracks:
                    if track['trackId'] not in agg_tracks_ids:
                        # Add to giant aggregate playlist
                        self.api.add_songs_to_playlist(agg_id,
                                                       track['trackId'])
                        # Add to daily playlist
                        self.api.add_songs_to_playlist(
                            self.get_playlist_id(TODAY), track['trackId'])
                        # Add to genre relevant playlist
                        self.api.add_songs_to_playlist(
                            self.get_playlist_id(
                                PLAYLIST_PREFIX +
                                GENRE_PLAYLISTS[self.get_parent_genre_id(
                                    track['track']['genre'])]),
                            track['trackId'])
                        title = track['track']['title'].encode(
                            'ascii', 'ignore')
                        artist = track['track']['artist'].encode(
                            'ascii', 'ignore')
                        print "+", title, "by", artist, "has been added."
                        no_new = False
                if no_new:
                    print "<< There are no new tracks to be added from this playlist. >>"

        print "Finished updating group playlists."

    def update_songs(self):
        """ Update the database with song information
        """
        # Connect to the database
        config = ConfigParser.ConfigParser()
        config.read('config.ini')

        dbname = config.get('database', 'dbname')
        dbuser = config.get('database', 'user')
        dbhost = config.get('database', 'host')
        dbpass = config.get('database', 'password')

        try:
            conn = psycopg2.connect("dbname=" + dbname + " user="******" host=" + dbhost + " password="******"<< Could not connect to the db. >>"
            print e
            sys.exit()

        # Update songs
        for c in self.content:
            if c.get('type') == 'USER_GENERATED' and c.get(
                    'name') == AGGREGATE_PLAYLIST_NAME:
                songs = c.get('tracks')
                for s in songs:
                    # Song details
                    details = s['track']
                    # Date song was added
                    date_added = datetime.fromtimestamp(
                        int(s.get('creationTimestamp')) / 1000000)
                    # Values to save
                    values = [
                        str(s.get('trackId')),
                        str(details.get('title').encode('UTF-8', 'ignore')),
                        str(details.get('artist').encode('UTF-8', 'ignore')),
                        str(details.get('album').encode('UTF-8', 'ignore')),
                        str(details.get('genre')), date_added
                    ]
                    # SQL query
                    insert_song = "INSERT INTO playlists_song VALUES (%s, %s, %s, %s, %s, %s) ON CONFLICT (tid) DO NOTHING;"
                    # Save to DB
                    self.commit_changes(conn, cur, insert_song, values)

        print "Songs successfully updated."
        # Close connection
        cur.close()
        conn.close()

    def commit_changes(self, conn, cur, query, values):
        try:  # Commit our changes made
            cur.execute(query, values)
            conn.commit()
        except psycopg2.Error as exc:
            print exc
            sys.exit()
Example #17
0
    return s1 in s2 or s2 in s1


similar = {}

print("starting now")
for i in range(len(songs)):
    if not songs[i] in used:
        for j in range(i + 1, len(songs)):
            if not songs[j] in used:
                if isSimilar(songs[i], songs[j]):
                    used.append(songs[j])
                    if songs[i]["title"] not in similar:
                        similar[songs[i]["title"]] = [songs[i]]
                    similar[songs[i]["title"]].append(songs[j])

for sim in similar:
    print("---" + sim + "---")
    delete = True
    while delete:
        ss = similar[sim]
        for i in range(len(ss)):
            print(str(i) + " " + ss[i]["title"] + " by " + ss[i]["artist"])
        which = int(input("which one to delete? (if none then type n+1)"))
        if which >= len(ss):
            delete = False
        else:
            print(
                "deleted" +
                str(client.remove_entries_from_playlist(ss[which]["entryId"])))
            ss.pop(which)
Example #18
0
rfcTitle = data[['artist','title','energy','tempo','danceability','artist_discovery','speechiness','year','duration','trackType','acousticness','liveness','loudness','time_signature','valence','id','albumArtRef','storeId']]
rfcTitle = rfcTitle.dropna(subset = filter(lambda x: x != "albumArtRef", rfcTitle.columns))
rfc = rfcTitle[['energy','tempo','danceability','artist_discovery','speechiness','year','trackType','acousticness','liveness','loudness','time_signature','valence']]

km = pickle.load(open("/home/drew/tempo_scripts/tempo_model.p", "rb" ))
klbls = km.labels_
rfcTitle['label'] = klbls

results = []

for index, value in enumerate(rfcTitle.values):
    results.append({'artist': value[0], 'title': value[1], 'energy': value[2], 'tempo': value[3], 'danceability': value[4], 'artist_discovery': value[5], 'speechiness': value[6], 'year': value[7], 'duration': value[8], 'trackType': value[9], 'acousticness': value[10], 'liveness': value[11], 'loudness': value[12], 'time_signature': value[13], 'valence': value[14], 'cluster': value[18], 'id': value[15], 'albumArtRef': value[16], 'storeId': value[17]})

#playlists = api.get_all_playlists()
#print json.dumps(playlists, indent=4, separators=(',', ': '))
plsongs = api.get_all_user_playlist_contents()
#print json.dumps(plsongs, indent=4, separators=(',', ': '))

data = pd.read_csv("/home/drew/gpmusic_fixed.csv")
ret = {'results': []}

for i,v in enumerate(plsongs[0]['tracks']):
    for i2,v2 in enumerate(results):
        #print v2['storeId'], "==", plsongs[i]['track']['storeId']
        if v2['id'] == v['trackId']:
            ret['results'].append(v2)
            break
api.remove_entries_from_playlist("1c5aa722-db07-3801-8966-54b6cef43513")
print json.dumps(plsongs, indent=4, separators=(',', ': '))
print json.dumps(ret, indent=4, separators=(',', ': '))