def main(): args, config = init() if not os.path.isdir(config['PROG']['DownloadPath']): os.mkdir(config['PROG']['DownloadPath']) sc_download( config['SOUNDCLOUD']['PlaylistUrl'], config['PROG']['DownloadPath'] ) mc = Mobileclient() mc.login(config['GMUSIC']['User'], config['GMUSIC']['Password'], Mobileclient.FROM_MAC_ADDRESS) mm = Musicmanager() if not (os.path.exists(gmclients.OAUTH_FILEPATH) and mm.login(gmclients.OAUTH_FILEPATH)): mm.perform_oauth(gmclients.OAUTH_FILEPATH, open_browser=True) if not mm.login(gmclients.OAUTH_FILEPATH): sys.stderr.write('Musicmanager could not authenticate') if config['GMUSIC']['TargetPlaylist'] not in set([item['name'] for item in mc.get_all_playlists() if not item['deleted']]): mc.create_playlist(name=config['GMUSIC']['TargetPlaylist'], description='Tracks synchronized using {}'.format(__prog__), public=False) playlist_id, current_members = gm_get_current_pl_member(mc, config['GMUSIC']['TargetPlaylist']) for track in os.listdir(config['PROG']['DownloadPath']): print('Uploading {}'.format(track)) uploaded_id = gm_extract_id(mm.upload('{}{}'.format(config['PROG']['DownloadPath'], track))) mc.add_songs_to_playlist(playlist_id, uploaded_id)
def machineautn(): mm = Mobileclient() mm.perform_oauth() mm2 = Musicmanager() mm2.perform_oauth()
def initializeClient(): client = Musicmanager() if (client.login()): return client else: client.perform_oauth(open_browser=True) initializeClient()
def run(): global download_dir, notify_plex, mm download_dir, notify_plex = parse_args() log("Creating music manager") mm = Musicmanager() log("Attempting login") if not mm.login(): print "OAuth required:" mm.perform_oauth() get_songs()
class GoogleMusic: def __init__(self): self.api = Musicmanager() try: print(os.getcwd()) if not self.api.login(oauth_credentials=config.auth): self.api.perform_oauth(storage_filepath=config.auth, open_browser=False) self.api.login(oauth_credentials=config.auth) except: pass def upload_audio(self, filepath, transcode_quality='320k'): self.api.upload(filepath, enable_matching=False, transcode_quality=transcode_quality) print("Upload finished")
class GoogleClient(): def __init__(self, username=None, password=None): self._username = username self._password = password # Initiates the oAuth def Authenticate(self): self.MusicManager = Musicmanager(debug_logging=False) attempts = 0 # Attempt to login. Perform oauth only when necessary. while attempts < 3: if self.MusicManager.login(): break self.MusicManager.perform_oauth() attempts += 1 if not self.MusicManager.is_authenticated(): print("Sorry, login failed.") return False print("OAuth successfull\n") username = self._username password = self._password if not username or not password: cred_path = os.path.join(os.path.expanduser('~'), '.gmusicfs') if not os.path.isfile(cred_path): raise Exception( '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 Exception( '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') if not username or not password: raise Exception( 'No username/password could be read from config file' ': %s' % cred_path) self.Api = Mobileclient(debug_logging = False) if not self.Api.login(username, password, Mobileclient.FROM_MAC_ADDRESS): raise Exception('login failed for %s' % username) return True
def main(): cli = Musicmanager(debug_logging=False) if credfile.is_file(): if cli.login(oauth_credentials=str(credfile)): print("Login successful. Don't need to perform oauth.") return else: os.remove(credfile) cli.perform_oauth(storage_filepath=str(credfile), open_browser=True) if cli.login(oauth_credentials=str(credfile)): print("Login successful. Restart the bot!") else: print("Failed to auth. Try again later.")
def authorize_manager(parameters): # api = Webclient() # api = Mobileclient() api = Musicmanager() # after running api.perform_oauth() once: # api.oauth_login('<a previously-registered device id>') # api.login(email=parameters.username, password=parameters.password) # => True if not os.path.exists(authorize_file + '_manager'): api.perform_oauth(authorize_file + '_manager', True) api.login(authorize_file + '_manager') if not api.is_authenticated(): return None return api
def download_songs(self): api = Musicmanager() ip = urllib2.urlopen('http://ip.42.pl/raw').read() #Obtain your public IP address mac_binary = str(get_mac()) #Obtain binary MAC address temp = mac_binary.replace(':', '').replace('-', '').replace('.', '').upper() mac_h3x = temp[:2] + ":" + ":".join([temp[i] + temp[i+1] for i in range(2,12,2)]) #Convert MAC from 48bit int to hexadecimal string user = pwd.getpwuid(os.getuid())[0] #Get your system's username hostname = '<' + ip + '>' + '' + '(gmusicapi-{2.0.0})' Musicmanager.perform_oauth(storage_filepath='/home/' + user + '/.config/gmusicapi/oauth.cred', open_browser=False) api.login(oauth_credentials='/home/' + user + '/.config/gmusicapi/oauth.cred', uploader_id=mac_h3x, uploader_name=hostname) gmusicapi.clients.Musicmanager(debug_logging=True, validate=True) playlist_id = raw_input("insert id: ") api_ = Mobileclient() api_.login(self.email, self.password) playlist_method = api_.get_all_playlists()
def upload(file_path): storage = oauth2client.file.Storage(CREDENTIALS_PATH) credentials = storage.get() if not credentials or credentials.invalid: Musicmanager.perform_oauth(CREDENTIALS_PATH, open_browser=False) mm = Musicmanager() mm.login(CREDENTIALS_PATH) result = mm.upload(file_path, enable_matching=True) if result[1]: raise Exception('{}はアップロード済みです'.format(file_path)) elif result[2]: raise Exception('アップロード失敗 {}'.format(result[2][file_path])) os.remove(file_path)
def api_init(): mm = Musicmanager() e = settings['email'] creds = os.path.expanduser("~/.local/share/gmusicapi/oauth.cred") # default oauth store location if OTHERACCOUNT: e = settings['email2'] creds = os.path.expanduser("~/.local/share/gmusicapi/oauth2.cred") if e is not None: if settings['first'] == '1' or OTHERACCOUNT and settings['first2'] == '1': print "Performing OAUTH for %s" % e mm.perform_oauth(storage_filepath=creds) update_first(e) log("Logging in as %s" % e) if mm.login(oauth_credentials=creds): return mm log("Login failed for second user") return False
def api_init(): mm = Musicmanager() e = settings['email'] creds = os.path.expanduser("~/.local/share/gmusicapi/oauth.cred") # default oauth store location if OTHERACCOUNT: e = settings['email2'] creds = os.path.expanduser("~/.local/share/gmusicapi/oauth2.cred") if e is not None: if settings['first'] == '1' or OTHERACCOUNT and settings['first2'] == '1': print("Performing OAUTH for %s" % e) mm.perform_oauth(storage_filepath=creds) update_first(e) log("Logging in as %s" % e) if mm.login(oauth_credentials=creds, uploader_id=settings['uploader_id']): return mm log("Login failed for second user") return False
class GoogleClient(): # Initiates the oAuth def Authenticate(self): self.MusicManager = Musicmanager(debug_logging=False) attempts = 0 # Attempt to login. Perform oauth only when necessary. while attempts < 3: if self.MusicManager.login(): break self.MusicManager.perform_oauth() attempts += 1 if not self.MusicManager.is_authenticated(): print "Sorry, login failed." return False print "Successfully logged in.\n" return True
def main(): if len(sys.argv) != 2: print_help() sys.exit(1) else: username = sys.argv[1] password = getpass.getpass() mc = Mobileclient() mc.login(username, password, Mobileclient.FROM_MAC_ADDRESS) mm = Musicmanager() mm.perform_oauth() mm.login() uploaded_songs = mm.get_uploaded_songs() uploaded_ids = [track['id'] for track in uploaded_songs] for part in chunks(uploaded_ids, 100): complete = mc.delete_songs(part) if len(complete) != len(part): print("Something is wrong")
class GMusicPodcastSyncDestination(PodcastSyncDestination): def __init__(self): super(GMusicPodcastSyncDestination, self).__init__() self.serviceIdentifier = "GOO" self.serviceName = "Google Music" self.musicManager = Musicmanager() self.mobileClient = Mobileclient() oAuthFile = "gMusic.oauth" if not os.path.isfile(oAuthFile): if not self.musicManager.perform_oauth(oAuthFile, True): print "Failed to authenticate Music Manager." raise PodcastSyncDestinationException("Authentication Failure.") else: try: self.musicManagerauthenticated = self.musicManager.login(oAuthFile) except gmusicapi.exceptions.AlreadyLoggedIn: pass username = raw_input("Enter Google Username: "******"Enter Google Password: "******"Authentication Failure.") # perform a push task. should return a PodFastPodcastPushedEpisode instance def pushEpisode(self, podcastSyncTaskEpisodePush): (uploaded, matched, not_uploaded) = self.musicManager.upload([podcastSyncTaskEpisodePush.localFilename]) songGoogleMusicID = "" if not_uploaded: # If the track was not uploaded, it may have been uploaded in the past. p = re.compile("ALREADY_EXISTS\\((.*)\\)") m = p.findall(not_uploaded[podcastSyncTaskEpisodePush.localFilename]) songGoogleMusicID = m[0] else: songGoogleMusicID = uploaded[podcastSyncTaskEpisodePush.localFilename] print "Track uploaded Successfully. ID:" + songGoogleMusicID gmusicPlayLists = self.mobileClient.get_all_playlists() playListExists = False gmusicPlaylistID = "" for gmusicPlayList in gmusicPlayLists: if gmusicPlayList["name"] == podcastSyncTaskEpisodePush.playlistName: playListExists = True gmusicPlaylistID = gmusicPlayList["id"] break if not playListExists: print "Creating playlist..." gmusicPlaylistID = self.mobileClient.create_playlist(podcastSyncTaskEpisodePush.playlistName) addedEntries = self.mobileClient.add_songs_to_playlist(gmusicPlaylistID, [songGoogleMusicID]) print "Moved track to playlist." return songGoogleMusicID # Pull (deletes) an episode from the destination returns true on success, False on faiilure def pullEpisode(self, podcastSyncTaskEpisodePull): self.mobileClient.delete_songs([podcastSyncTaskEpisodePull.syncDestinationID]) # TODO: Error check here. return True
def songs_uploader(self): ip = urllib2.urlopen('http://ip.42.pl/raw').read() #Obtain your public IP address mac_binary = str(get_mac()) #Obtain binary MAC address temp = mac_binary.replace(':', '').replace('-', '').replace('.', '').upper() mac_h3x = temp[:2] + ":" + ":".join([temp[i] + temp[i+1] for i in range(2,12,2)]) #Convert MAC from 48bit int to hexadecimal string user = pwd.getpwuid(os.getuid())[0] #Get your system's username api = Musicmanager() hostname = '<' + ip + '>' + '' + '(gmusicapi-{2.0.0})' Musicmanager.perform_oauth(storage_filepath='/home/' + user + '/.config/gmusicapi/oauth.cred', open_browser=False) api.login(oauth_credentials='/home/' + user + '/.config/gmusicapi/oauth.cred', uploader_id=mac_h3x, uploader_name=hostname) gmusicapi.clients.Musicmanager(debug_logging=True, validate=True) #newWorkingDirectory = '../home' #os.path.join(os.path.abspath(sys.path[0]), newWorkingDirectory) #Change the working directory filepath = '/home/blackram/Scrivania/BRES_/UMM/ciao.mp3' uploading = api.upload(filepath, transcode_quality=3, enable_matching=False) print 'Uploading...' f = open('uploading.txt','w') #log f.write(str(uploading)) f.close() final = re.search("GetUploadSession error 200: this song is already uploaded", open('uploading.txt','r').read()) if final is None: print '\033[32mTrack uploaded!\033[0m' else: print '\033[31mTrack already exists in your library!\033[0m' choice = raw_input("Exit from uploader? [Y/N] ") if choice == 'y' or choice == 'Y': print 'Return to main menu.' Musicmanager.logout(revoke_oauth=False) UMM.read_information() elif choice == 'n' or choice == 'N': print 'Okay.' UMM.songs_uploader()
def setup_music_manager_api(): global music_manager_api music_manager_api = Musicmanager() if not config.get_is_authenticated(): print "Follow the instructions to authenticate with Google..." credentials = music_manager_api.perform_oauth() if credentials is not None: config.set_is_authenticated(True) else: print "Failed to authenticate, try again." sys.exit(0) music_manager_logged_in = music_manager_api.login() if not music_manager_logged_in: print "Failed to log in to the music manager API, you will be asked to authenticate again next run." sys.exit(0)
from gmusicapi import Musicmanager, clients import os.path oauth_path = clients.OAUTH_FILEPATH if os.path.isfile(oauth_path): print 'OAuth credentials already exist' else: # oauth login mm = Musicmanager() oath_path = mm.perform_oauth(oauth_path, True)
class MusicSync(object): def __init__(self, email=None, password=None): self.mm = Musicmanager() self.wc = Webclient() 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.wc.get_all_playlist_ids(auto=False) print "Got %d playlists." % len(self.playlists['user']) print "" def auth(self): 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, artist_title_array, playlist_title=-99): if playlist_title == -99: title = "GMusicSync Playlist %3d" % time.time() else: title = str(playlist_title) print "Synching playlist: %s" % title if title not in self.playlists['user']: print " didn't exist... creating..." self.playlists['user'][title] = [self.wc.create_playlist(title)] print "" 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 = artist_title_array print "%d songs in local playlist" % len(pc_songs) # 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): existing_files += 1 continue print "" try: print "Adding: %s - %s" % (fn[0], fn[1]) except: print "Incorrect format for %r, expecting ('artist','title')" % fn continue online = self.find_song(fn) song_id = None if online: song_id = online['id'] print " already uploaded [%s]" % song_id else: print " Sorry, can't find song." if not song_id: failed_files += 1 continue added = self.wc.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 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='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, artist_title, goog_songs): i = 0 while i < len(goog_songs): if self.song_compare(goog_songs[i], artist_title): goog_songs.pop(i) return True i += 1 return False def find_song(self, artist_title): try: artist = artist_title[0] title = artist_title[1] except: return None results = self.wc.search(title) print "\t", results[:2] for r in results['song_hits']: if self.song_compare(r, artist_title): return r return None def song_compare(self, g_song, artist_title): try: artist = artist_title[0] title = artist_title[1] except: return False # TODO: add fuzzy matching return g_song['title'].lower() == title.lower() and\ g_song['artist'].lower() == artist.lower() 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('\\', '/'))
#!/usr/bin/env python from gmusicapi import Mobileclient from gmusicapi import Musicmanager from getpass import getpass api = Musicmanager() api.perform_oauth()
os.chdir('.yt_to_play') Path('download_temp').mkdir(exist_ok=True) os.chdir('download_temp') ydl_opts = { 'format': 'bestaudio/best', 'postprocessors': [{ 'key': 'FFmpegExtractAudio', 'preferredcodec': 'mp3', 'preferredquality': '192', }], 'outtmpl': '%(title)s.%(ext)s', 'download_archive': '../downloaded.txt', } with youtube_dl.YoutubeDL(ydl_opts) as ydl: ydl.download(args) print('Uploading...') mm = Musicmanager() oauth = Path('../oauth.cred') if not (oauth.exists() and oauth.is_file()): mm.perform_oauth(oauth) mm.login(oauth) mm.upload([os.path.join(os.getcwd(), f) for f in os.listdir(os.getcwd())]) for f in os.listdir(os.getcwd()): os.remove(f)
class MusicSync(object): def __init__(self, email=None, password=None): self.mm = Musicmanager() self.wc = Webclient() 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.wc.get_all_playlist_ids(auto=False) print "Got %d playlists." % len(self.playlists['user']) print "" def auth(self): 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, artist_title_array, playlist_title = -99): if playlist_title == -99: title = "GMusicSync Playlist %3d"%time.time() else: title = str(playlist_title) print "Synching playlist: %s" % title if title not in self.playlists['user']: print " didn't exist... creating..." self.playlists['user'][title] = [self.wc.create_playlist(title)] print "" 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 = artist_title_array print "%d songs in local playlist" % len(pc_songs) # 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): existing_files += 1 continue print "" try: print "Adding: %s - %s"%(fn[0],fn[1]) except: print "Incorrect format for %r, expecting ('artist','title')"%fn continue online = self.find_song(fn) song_id = None if online: song_id = online['id'] print " already uploaded [%s]" % song_id else: print " Sorry, can't find song." if not song_id: failed_files += 1 continue added = self.wc.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 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='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, artist_title, goog_songs): i = 0 while i < len(goog_songs): if self.song_compare(goog_songs[i], artist_title): goog_songs.pop(i) return True i += 1 return False def find_song(self, artist_title): try: artist = artist_title[0] title = artist_title[1] except: return None results = self.wc.search(title) print "\t",results[:2] for r in results['song_hits']: if self.song_compare(r, artist_title): return r return None def song_compare(self, g_song, artist_title): try: artist = artist_title[0] title = artist_title[1] except: return False # TODO: add fuzzy matching return g_song['title'].lower() == title.lower() and\ g_song['artist'].lower() == artist.lower() 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 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 self.manager_id = 0 if verbose > 1: self.verbose = True self.__login_and_setup(username, password) self.__register_music_manager() 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') if not username or not password: raise NoCredentialException( 'No username/password 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 __register_music_manager(self): self.manager = GoogleMusicManager() self.manager_id = ':'.join(re.findall('..', '%012x' % uuid.getnode())).upper() log.info('Registering the google music manager...') cred_path = os.path.join(os.path.expanduser('~'), '.gmusicfs.ocred') if not os.path.isfile(cred_path): log.info('Authorizing GMusicFS application against Google...') self.manager.perform_oauth(storage_filepath=cred_path) os.chmod(cred_path, 0600) 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.manager.login(cred_path, self.manager_id, 'GMusicFS') log.info('Successfully registered the google music manager...') 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 = normalize(track['artist']) # Get the Album object if it already exists: key = '%s|||%s' % (formatNames(artist), formatNames(normalize(track['album']))) album = all_artist_albums.get(key, None) if not album: # New Album if artist == '': artist = 'unknown' album = all_artist_albums[key] = Album( self, formatNames(normalize(track['album']))) 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
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 self.manager_id = 0 if verbose > 1: self.verbose = True self.__login_and_setup(username, password) self.__register_music_manager() 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') if not username or not password: raise NoCredentialException( 'No username/password 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 __register_music_manager(self): self.manager = GoogleMusicManager() self.manager_id = ':'.join(re.findall('..', '%012x' % uuid.getnode())).upper() log.info('Registering the google music manager...') cred_path = os.path.join(os.path.expanduser('~'), '.gmusicfs.ocred') if not os.path.isfile(cred_path): log.info('Authorizing GMusicFS application against Google...') self.manager.perform_oauth(storage_filepath=cred_path) os.chmod(cred_path, 0600) 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.manager.login(cred_path, self.manager_id, 'GMusicFS') log.info('Successfully registered the google music manager...') 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 = normalize(track['artist']) # Get the Album object if it already exists: key = '%s|||%s' % (formatNames(artist), formatNames(normalize(track['album']))) album = all_artist_albums.get(key, None) if not album: # New Album if artist == '': artist = 'unknown' album = all_artist_albums[key] = Album( self, formatNames(normalize(track['album']))) 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
class Gmusic(BeetsPlugin): def __init__(self): super(Gmusic, self).__init__() # Checks for OAuth2 credentials, # if they don't exist - performs authorization self.m = Musicmanager() if os.path.isfile(gmusicapi.clients.OAUTH_FILEPATH): self.m.login() else: self.m.perform_oauth() def commands(self): gupload = Subcommand('gmusic-upload', help=u'upload your tracks to Google Play Music') gupload.func = self.upload search = Subcommand('gmusic-songs', help=u'list of songs in Google Play Music library' ) search.parser.add_option('-t', '--track', dest='track', action='store_true', help='Search by track name') search.parser.add_option('-a', '--artist', dest='artist', action='store_true', help='Search by artist') search.func = self.search return [gupload, search] def upload(self, lib, opts, args): items = lib.items(ui.decargs(args)) files = [x.path.decode('utf-8') for x in items] ui.print_(u'Uploading your files...') self.m.upload(filepaths=files) ui.print_(u'Your files were successfully added to library') 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') @staticmethod def match(files, args, search_by): for file in files: if ' '.join(ui.decargs(args)) in file[search_by]: print(file['artist'], file['title'], file['album'])
from gmusicapi import Mobileclient, Musicmanager # This only needs to be run once. Re-use the creds from where it is stored mobile = Mobileclient() mobile.perform_oauth(storage_filepath="/Users/jd/ws/gmusic/.creds", open_browser=True) manager = Musicmanager() manager.perform_oauth(storage_filepath="/Users/jd/ws/gmusic/.manager_creds", open_browser=True)
from gmusicapi import Musicmanager import os.path storage_filepath = '/home/alex/.local/share/gmusicapi/oauth.cred' mm = Musicmanager() if os.path.isfile(storage_filepath): mm.login() else: Musicmanager.perform_oauth(storage_filepath, open_browser=True) songs = mm.get_uploaded_songs(incremental=False) print(songs) song_id = [] for x in songs: song_id.append(x.get('id')) print(song_id) for an_id in song_id: filename, audio = mm.download_song(an_id) with open(filename, 'wb') as f: f.write(audio) input("Enter: ") mm.logout(revoke_oauth=False)
from gmusicapi import Musicmanager # login mm = Musicmanager() mm.perform_oauth() # once mm.login() # get music dict mymusics = mm.get_uploaded_songs() # diff? # MUST consider directories oldmusics = "hogehoge" # for example id = mymusics[0]["id"] filename, audio_bytes = mm.download_song(id) with open(filename, "wb") as f: f.write(audio_bytes) # logout mm.logout()
def gmtConfigRead(): global std_usr, root_dir, trash_path, cred_path, list_path try: with open(conf_path, "r") as file: for line in file: if(line[:17] == "StandardUsername="******"gmtConfigRead: StandardUser Config: " + std_usr) elif(line[:14] == "RootDirectory="): root_dir = line[14:-1] gmtPrintV("gmtConfigRead: RootDirectory Config: " + root_dir) if not os.path.exists(root_dir): gmtPrintV("gmtConfigRead: Song directory not found") error.e = error.ROOT_DIR_NOT_FOUND return elif(line[:10] == "TrashPath="): trash_path = line[10:-1] gmtPrintV("gmtConfigRead: TrashPath Config: " + trash_path) if not os.path.exists(trash_path): gmtPrintV("gmtConfigRead: Couldn't find trash directory, generating empty one now") try: os.makedirs(trash_path) except IOError: gmtPrintV("gmtConfigReadCouldn't generate trash directory") error.e = error.TRASH_ERROR return elif(line[:16] == "CredentialsPath="): cred_path = line[16:-1] gmtPrintV("gmtConfigRead: CredentialsPath Config: " + cred_path) if not os.path.isfile(cred_path): if gmtAskUser("Couldn't find credentials. Generate them now (y/n)? ") == "y": try: Musicmanager.perform_oauth(cred_path) except: gmtPrintV("gmtConfigRead: Generating credentials failed") error.e = error.FILE_ERROR else: gmtPrintV("gmtConfigRead: Credentials needed to upload songs") error.e = error.LOGIN_FAILED elif(line[:17] == "UploadedListPath="): list_path = line[17:-1] gmtPrintV("gmtConfigRead: UploadedListPath Config: " + list_path) if not os.path.isfile(list_path): gmtPrintV("gmtConfigRead: Couldn't find list of uploaded files, generating empty one now") try: file = open(list_path, "w") file.close() except IOError: gmtError("gmtConfigRead: Couldn't generate list of uploaded files") error.e = error.LIST_ERROR return except IOError: gmtPrintV("gmtConfigRead: Couldn't open config file") error.e = error.CONFIG_READ_ERROR return
#!/usr/bin/python ################## from gmusicapi import Musicmanager from os.path import expanduser oauthPath = expanduser("~") + "/.oauthfile" print("storing the oauthPath in " + oauthPath) manager = Musicmanager() manager.perform_oauth(storage_filepath = oauthPath)
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 Gmusic(BeetsPlugin): def __init__(self): super(Gmusic, self).__init__() self.m = Musicmanager() self.config.add({ u'auto': False, u'uploader_id': '', u'uploader_name': '', u'device_id': '', u'oauth_file': gmusicapi.clients.OAUTH_FILEPATH, }) if self.config['auto']: self.import_stages = [self.autoupload] def commands(self): gupload = Subcommand('gmusic-upload', help=u'upload your tracks to Google Play Music') gupload.func = self.upload search = Subcommand('gmusic-songs', help=u'list of songs in Google Play Music library') search.parser.add_option('-t', '--track', dest='track', action='store_true', help='Search by track name') search.parser.add_option('-a', '--artist', dest='artist', action='store_true', help='Search by artist') search.func = self.search return [gupload, search] def authenticate(self): if self.m.is_authenticated(): return # Checks for OAuth2 credentials, # if they don't exist - performs authorization oauth_file = self.config['oauth_file'].as_str() if os.path.isfile(oauth_file): uploader_id = self.config['uploader_id'] uploader_name = self.config['uploader_name'] self.m.login(oauth_credentials=oauth_file, uploader_id=uploader_id.as_str().upper() or None, uploader_name=uploader_name.as_str() or None) else: self.m.perform_oauth(oauth_file) def upload(self, lib, opts, args): items = lib.items(ui.decargs(args)) files = self.getpaths(items) self.authenticate() ui.print_(u'Uploading your files...') self.m.upload(filepaths=files) ui.print_(u'Your files were successfully added to library') def autoupload(self, session, task): items = task.imported_items() files = self.getpaths(items) self.authenticate() self._log.info(u'Uploading files to Google Play Music...', files) self.m.upload(filepaths=files) self._log.info(u'Your files were successfully added to your ' + 'Google Play Music library') def getpaths(self, items): return [x.path for x in items] def search(self, lib, opts, args): password = config['gmusic']['password'] email = config['gmusic']['email'] uploader_id = config['gmusic']['uploader_id'] device_id = config['gmusic']['device_id'] password.redact = True email.redact = True # Since Musicmanager doesn't support library management # we need to use mobileclient interface mobile = Mobileclient() try: new_device_id = (device_id.as_str() or uploader_id.as_str().replace(':', '') or Mobileclient.FROM_MAC_ADDRESS).upper() mobile.login(email.as_str(), password.as_str(), new_device_id) 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') @staticmethod def match(files, args, search_by): for file in files: if ' '.join(ui.decargs(args)) in file[search_by]: print(file['artist'], file['title'], file['album'])
#!/usr/bin/env python2 # see http://unofficial-google-music-api.readthedocs.org/en/latest/usage.html#usage # arch linux 'pacman -S python2-pip && pip2 install gmusicapi' from gmusicapi import Musicmanager from gmusicapi.compat import my_appdirs import sys import os.path mm = Musicmanager() # TODO use generic path for credentials OAUTH_FILEPATH = os.path.join(my_appdirs.user_data_dir, 'oauth.cred') if not os.path.isfile(OAUTH_FILEPATH): mm.perform_oauth() mm.login() # TODO handle errors (existing tracks/duplicates ...) # TODO handle errors (existing tracks/duplicates ...) track = sys.argv[1] uploaded, matched, not_uploaded = mm.upload(track) if uploaded[track]: sys.exit(0) sys.exit(1)
class Gmusic(object): def __init__(self, playlists_to_sync, credentials_storage_location, debug): self.playlists_to_sync = playlists_to_sync self.credentials_storage_location = credentials_storage_location self._client = Mobileclient(debug_logging=debug) self._manager = Musicmanager(debug_logging=debug) def client_login(self): credentials = self.credentials_storage_location if not os.path.isfile(credentials): credentials = self._client.perform_oauth( storage_filepath=self.credentials_storage_location, open_browser=True) if not self._client.oauth_login( device_id=Mobileclient.FROM_MAC_ADDRESS, oauth_credentials=credentials, ): logger.error("Gmusic mobile client authentication failed") return False logger.info("Gmusic mobile client authentication succeeded.") return True def manager_login(self): credentials = self.credentials_storage_location if not os.path.isfile(credentials): credentials = self._manager.perform_oauth( storage_filepath=self.credentials_storage_location, open_browser=True) if not self._manager.login(oauth_credentials=credentials, ): logger.error("Gmusic music manager authentication failed") return False logger.info("Gmusic music manager authentication succeeded.") return True @property def client(self): if not self._client.is_authenticated(): self.client_login() return self._client @property def manager(self): if not self._manager.is_authenticated(): self.manager_login() return self._manager @cached_property def uploaded_songs(self): return {song['id']: song for song in self.manager.get_uploaded_songs()} @property def _playlists(self): playlists = self.client.get_all_user_playlist_contents() logger.debug("Loaded {} playlists".format(len(playlists))) return playlists @cached_property def playlists(self): playlists_to_sync = [] for playlist in self._playlists: if playlist['name'] in self.playlists_to_sync: playlists_to_sync.append(playlist) return playlists_to_sync def get_latest_addition_date(self, playlist): lastModified = playlist.get('lastModifiedTimestamp') if lastModified: return datetime.fromtimestamp(int(lastModified) / 10**6).replace(tzinfo=pytz.utc) return None
class 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.wc.get_all_playlist_ids(auto=False) print "Got %d playlists." % len(self.playlists["user"]) print "" def auth(self): self.logged_in = self.wc.login(self.email, self.password) self.logged_in = self.mc.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 add_rhapsody_playlist(self, filename, remove_missing=False): filename = self.get_platform_path(filename) os.chdir(os.path.dirname(filename)) # playlist_title = os.path.splitext(os.path.basename(filename))[0] print "Synching File: %s" % filename print "Parsing Songs from %s" % filename pc_songs = self.get_songs_from_file(filename) # print (pc_songs) print "%d songs in local file: %s" % (len(pc_songs), filename) # 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 song in pc_songs: playlist_title = song["playlist"] if playlist_title not in self.playlists["user"]: self.playlists["user"][playlist_title] = [self.mc.create_playlist(playlist_title)] time.sleep(0.7) print "Starting Playlist Sync with Google music..." for song in pc_songs: # print song plid = "" print "--------------------------------" print "" print "Playlist: %s" % song["playlist"] print "Artist: %s" % song["artist"] print "Song: %s" % song["title"] print "Album: %s" % song["album"] playlist_title = song["playlist"] plid = self.playlists["user"][playlist_title][0] goog_songs = self.wc.get_playlist_songs(plid) if self.song_already_in_list(song, goog_songs): existing_files += 1 print "Result: Song Already Added" continue print "Total %d songs in Google playlist: %s" % (len(goog_songs), playlist_title) print "%s - %s, didn't exist...Will try to add..." % (song["artist"], song["title"]) print "" print "--------------------------------" results = self.mc.search_all_access(song["title"], max_results=50) nid = self.filter_search_results(results, song) print "AA nId: %s " % nid if nid: song_id = self.mc.add_aa_track(nid) added = self.wc.add_songs_to_playlist(plid, song_id) print "Playlist UUid: %s" % plid print "Song ID: %s" % song_id time.sleep(0.3) # Don't spam the server too fast... print "Result: done adding to playlist" added_files += 1 continue else: query = "%s %s" % (song["artist"], song["title"].split(" ")[0]) print "Query %s" % query results = self.mc.search_all_access(query, max_results=50) nid = self.filter_search_results(results, song) if nid: song_id = self.mc.add_aa_track(nid) added = self.wc.add_songs_to_playlist(plid, song_id) print "Playlist UUid: %s" % plid print "Song ID: %s" % song_id time.sleep(0.3) # Don't spam the server too fast... print " -- done adding to playlist" added_files += 1 continue print "Result: NID Blank, Song not Found in All Access" 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_songs_from_file(self, filename): songs = [] f = codecs.open(filename, encoding="utf-8") for line in f: line = line.rstrip().replace(u"\ufeff", u"") if line == "" or line[0] == "#": continue la = line.split("\\") regex_filter = "[^A-Za-z0-9\,\-\.\ \(\)'\!\?\$\/ \& \:]" artist = re.sub(regex_filter, "", la[1]) playlist = re.sub(regex_filter, "", la[0]) album = re.sub(regex_filter, "", la[2]) title = re.sub(regex_filter, "", la[3]) # print "Filtered Strings:" # print "Artist: %s" % artist # print "Playlist: %s" % playlist # print "Song: %s" % title # print "Album: %s" % album dt = {"playlist": playlist, "artist": artist, "album": album, "title": title} # print (dt) songs.append(dt) f.close() return songs def get_songs_from_playlist(self, filename): songs = [] 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 songs.append(path) f.close() return songs def get_files_from_playlist(self, filename): files = [] 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 song_already_in_list(self, song, goog_songs): # tag = self.get_id3_tag(filename) i = 0 while i < len(goog_songs): # print goog_songs if self.tag_compare(goog_songs[i], song): goog_songs.pop(i) return True i += 1 return False def file_already_in_list(self, filename, goog_songs): tag = self.get_id3_tag(filename) i = 0 while i < len(goog_songs): if self.tag_compare(goog_songs[i], tag): 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, plid): tag = self.get_id3_tag(filename) print "Song Tag: %s " % tag print "Filename: %s" % filename ws_plids = [] ws_plids.append(plid) print (ws_plids) playlists = self.wc.get_all_playlist_ids() print (playlists) results = self.wc.get_playlist_songs(ws_plids) # NOTE - dianostic print here to check results if you're creating duplicates print results print "%s ][ %s ][ %s ][ %s" % (tag["title"], tag["artist"], tag["album"], tag["track"]) for r in results: if self.tag_compare(r, tag): # TODO: add rough time check to make sure its "close" return r return None def filter_search_results(self, results, song): # Try Exact Matching for g_song in results["song_hits"]: if self.tag_compare(g_song["track"], song): return g_song["track"]["nid"] elif self.song_compare(g_song["track"], song, "artist"): # try just the artist return g_song["track"]["nid"] elif self.song_compare(g_song["track"], song, "part-song"): # try part of song and artist return g_song["track"]["nid"] return None def song_compare(self, g_song, tag, type): if "track" not in g_song: g_song["track"] = 0 title_parts = tag["title"].split("(") # removing shit like (featuring wiz) tp = title_parts[0].split(" ") # First word maybe if "artist" in type: return g_song["artist"].lower() == tag["artist"].lower() if "part-song" in type: return g_song["title"].find(tp[0]) and g_song["artist"].lower() == tag["artist"].lower() return None def tag_compare(self, g_song, tag): if "track" not in g_song: g_song["track"] = 0 return ( g_song["title"].split(" ")[0].lower() == tag["title"].split(" ")[0].lower() and g_song["artist"].lower() == tag["artist"].lower() ) def delete_song(self, sid): self.wc.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("\\", "/"))
# find the mp3 file that was downloaded files = glob.glob(f'{downloadPath}\*.mp3') latestFile = max(files, key=os.path.getctime) # connect to gmusicapi mm = Musicmanager() # check if firstRun if "True" in firstRun: print( "Since this is your first time using the app you will need to allow your google account to authenticate..." ) print( "If you would like to change the app settings please modify the config file." ) mm.perform_oauth() config = open("yt2gpmCONFIG.txt", "w") firstRun = False config.write( f"firstRun:{firstRun}\nYoutube-DL Args:{ytDlString}\nremoveDownloadedFile (saves storage space):{removeFile}" ) config.close() print("Attempting to login to GPM.") mm.login() print(f"Successfuly logged into GPM, Uploading file: {latestFile}...") c = mm.upload(latestFile) mm.logout() print("File upload complete! Finishing up.")
def get_musicmanager(debug=True): mm = Musicmanager(debug_logging=debug) if not mm.login(): mm.perform_oauth() return mm
class GoogleMusic(object): def __init__(self, config, log=print): self.OAUTH_PATH = config.get('oauth_path', '/tmp/oauth.cred') self.mm = Musicmanager() if os.path.isfile(self.OAUTH_PATH): success = self.mm.login(oauth_credentials=self.OAUTH_PATH) if not success: self.mm.perform_oauth(storage_filepath=self.OAUTH_PATH, open_browser=True) else: self.mm.perform_oauth(storage_filepath=self.OAUTH_PATH, open_browser=True) random.seed() self.songs = self.mm.get_uploaded_songs() self.queue = Queue() self.thread = None self.log = log self._enqueue_output() def _enqueue_output(self): song = random.choice(self.songs) self.log("get song id" + song['id']) retry = 3 while retry > 0: try: filename, audio = self.mm.download_song(song['id']) if len(audio) == 0: self.log("audio size 0") song = random.choice(self.songs) continue filelike = StringIO.StringIO(audio) metadata = mutagen.File(filelike) output = { 'song_length': 0, 'album': '', 'artist': '', 'title': '', 'audio': audio } if metadata: output['song_length'] = metadata.info.length output['album'] = fix_name( (metadata.tags or metadata).get('TALB', dummy).text[0]) output['artist'] = fix_name( (metadata.tags or metadata).get('TPE1', dummy).text[0]) output['title'] = fix_name( (metadata.tags or metadata).get('TIT2', dummy).text[0]) self.queue.put(output) break except CallFailure: self.log("call failure") song = random.choice(self.songs) retry -= 1 if retry == 0: self.log("Google Music download fail, please restart the program") self.queue.put({}) def get(self): # TODO: set timeout from config, blacklist this instance when retry fail output = self.queue.get(block=True) self.thread = StoppableThread(target=self._enqueue_output) self.thread.daemon = True self.thread.start() return output
def play_song_by_artist(song, artist): if Mobileclient.is_authenticated(gpm): mm = Musicmanager() mm.login('/home/pi/oauth.cred') if Musicmanager.is_authenticated(mm): song_dict = mm.get_purchased_songs() song_pattern = re.compile( r'(?:.)*\s?(' + re.escape(song) + r')\s?(?:.)*', re.IGNORECASE) artist_pattern = re.compile( r'(?:.)*\s?(' + re.escape(artist) + r')\s?(?:.)*', re.IGNORECASE) btn = OnButtonPress() btn.start() for song in song_dict: m = re.match(artist_pattern, song['artist']) print(m) if (re.match(song_pattern, song['title']) is not None and re.match(artist_pattern, song['artist']) is not None): print('Song found!') song_id = song['id'] (filename, audio) = mm.download_song(song_id) # get rid of non-ascii characters in file name filename = filename.encode('ascii', errors='ignore') # check if song is already downloaded # path will look something like: # /home/pi/Music/02 - Raindrop Prelude.mp3 # forces filename to be a string filename = filename.decode('ascii') path = song_location + filename try: if os.path.isfile(path): print('Song is already downloaded...') print(path) print('Playing song.') vlc_instance = vlc.Instance() p = vlc_instance.media_player_new() media = vlc_instance.media_new(path) p.set_media(media) events = p.event_manager() events.event_attach( vlc.EventType.MediaPlayerEndReached, SongFinished) p.play() p.audio_set_volume(58) while finish == 0: duration = p.get_time() / 1000 (m, s) = divmod(duration, 60) print('Current song is: ', path) print('Length:', '%02d:%02d' % (m, s)) time.sleep(5) p.stop() break else: with open(path, 'wb') as f: f.write(audio) print('Song has been added to: ' + path) print('Playing song.') vlc_instance = vlc.Instance() p = vlc_instance.media_player_new() media = vlc_instance.media_new(path) p.set_media(media) events = p.event_manager() events.event_attach( vlc.EventType.MediaPlayerEndReached, SongFinished) p.play() p.audio_set_volume(58) while finish == 0: duration = p.get_time() / 1000 m, s = divmod(duration, 60) print('Current song is: ', path) print('Length:', '%02d:%02d' % (m, s)) time.sleep(5) p.stop() break except (OSError, IOError): print('An error has occurred.') break else: print('Song not found yet.') else: print('Looks like you need to authenticate.') mm.perform_oauth('/home/pi/oauth.cred') print('Logging out.') Mobileclient.logout(gpm) mm.logout() else: print('Mobile client is not authenticated.') Mobileclient.logout(gpm)
class Gmusic(BeetsPlugin): def __init__(self): super().__init__() self.m = Musicmanager() # OAUTH_FILEPATH was moved in gmusicapi 12.0.0. if hasattr(Musicmanager, 'OAUTH_FILEPATH'): oauth_file = Musicmanager.OAUTH_FILEPATH else: oauth_file = gmusicapi.clients.OAUTH_FILEPATH self.config.add({ 'auto': False, 'uploader_id': '', 'uploader_name': '', 'device_id': '', 'oauth_file': oauth_file, }) if self.config['auto']: self.import_stages = [self.autoupload] def commands(self): gupload = Subcommand('gmusic-upload', help='upload your tracks to Google Play Music') gupload.func = self.upload search = Subcommand('gmusic-songs', help='list of songs in Google Play Music library') search.parser.add_option('-t', '--track', dest='track', action='store_true', help='Search by track name') search.parser.add_option('-a', '--artist', dest='artist', action='store_true', help='Search by artist') search.func = self.search return [gupload, search] def authenticate(self): if self.m.is_authenticated(): return # Checks for OAuth2 credentials, # if they don't exist - performs authorization oauth_file = self.config['oauth_file'].as_filename() if os.path.isfile(oauth_file): uploader_id = self.config['uploader_id'] uploader_name = self.config['uploader_name'] self.m.login(oauth_credentials=oauth_file, uploader_id=uploader_id.as_str().upper() or None, uploader_name=uploader_name.as_str() or None) else: self.m.perform_oauth(oauth_file) def upload(self, lib, opts, args): items = lib.items(ui.decargs(args)) files = self.getpaths(items) self.authenticate() ui.print_('Uploading your files...') self.m.upload(filepaths=files) ui.print_('Your files were successfully added to library') def autoupload(self, session, task): items = task.imported_items() files = self.getpaths(items) self.authenticate() self._log.info('Uploading files to Google Play Music...', files) self.m.upload(filepaths=files) self._log.info('Your files were successfully added to your ' + 'Google Play Music library') def getpaths(self, items): return [x.path for x in items] def search(self, lib, opts, args): password = config['gmusic']['password'] email = config['gmusic']['email'] uploader_id = config['gmusic']['uploader_id'] device_id = config['gmusic']['device_id'] password.redact = True email.redact = True # Since Musicmanager doesn't support library management # we need to use mobileclient interface mobile = Mobileclient() try: new_device_id = (device_id.as_str() or uploader_id.as_str().replace(':', '') or Mobileclient.FROM_MAC_ADDRESS).upper() mobile.login(email.as_str(), password.as_str(), new_device_id) files = mobile.get_all_songs() except NotLoggedIn: ui.print_( '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') @staticmethod def match(files, args, search_by): for file in files: if ' '.join(ui.decargs(args)) in file[search_by]: print(file['artist'], file['title'], file['album'])
def auth(auth_file: str = os.environ['HOME'] + '/oauth') -> None: api = Musicmanager() if api.perform_oauth(auth_file): print("Logged successfully")
from gmusicapi import Musicmanager mm = Musicmanager() mm.perform_oauth(storage_filepath=u'./oauth.cred')
class Gmusic(BeetsPlugin): def __init__(self): super(Gmusic, self).__init__() # Checks for OAuth2 credentials, # if they don't exist - performs authorization self.m = Musicmanager() if os.path.isfile(gmusicapi.clients.OAUTH_FILEPATH): self.m.login() else: self.m.perform_oauth() def commands(self): gupload = Subcommand('gmusic-upload', help=u'upload your tracks to Google Play Music') gupload.func = self.upload search = Subcommand('gmusic-songs', help=u'list of songs in Google Play Music library') search.parser.add_option('-t', '--track', dest='track', action='store_true', help='Search by track name') search.parser.add_option('-a', '--artist', dest='artist', action='store_true', help='Search by artist') search.func = self.search return [gupload, search] def upload(self, lib, opts, args): items = lib.items(ui.decargs(args)) files = [x.path.decode('utf-8') for x in items] ui.print_(u'Uploading your files...') self.m.upload(filepaths=files) ui.print_(u'Your files were successfully added to library') 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') @staticmethod def match(files, args, search_by): for file in files: if ' '.join(ui.decargs(args)) in file[search_by]: print(file['artist'], file['title'], file['album'])
def main(): storage = oauth2client.file.Storage(CREDENTIALS_PATH) credentials = storage.get() if not credentials or credentials.invalid: Musicmanager.perform_oauth(CREDENTIALS_PATH, open_browser=False)
class GMusicSync(BeetsPlugin): def __init__(self): super(GMusicSync, self).__init__() self._mm = Musicmanager(debug_logging=False) self._library_paths = get_library_paths('default') if not os.path.exists(self._library_paths.base): os.mkdir(self._library_paths.base); self._db = open_db(self._library_paths.db_file) if not os.path.exists(self._library_paths.oauth_file): self._mm.perform_oauth(self._library_paths.oauth_file) else: self._mm.login(self._library_paths.oauth_file) sync_command = make_command('gmusic-sync', self.sync_library, help='Sync library with Google Play Music') sync_command.parser.add_option('-p', '--pretend', dest='pretend', action='store_true', default=False) self._commands = [ sync_command, ] self.config['password'].redact = True def commands(self): return self._commands def sync_library(self, lib, opts, args): total_count = 0 uploaded_count = 0 error_count = 0 for item in lib.items(query=args): total_count = total_count + 1 status = self.sync_track(item, pretend=opts.pretend) if status == 'uploaded': uploaded_count = uploaded_count + 1 elif status == 'error': error_count = error_count + 1 print 'Summary:' print ' {0} tracks analyzed.'.format(total_count) print ' {0} tracks {1}uploaded.'.format(uploaded_count, 'would be ' if opts.pretend else '') print ' {0} tracks errored.'.format(error_count) def sync_track(self, item, pretend=False): item_mtime = arrow.get(item.current_mtime()) track_row = self._db.get_track(item.id) upload_track = track_row is None or \ track_row.gmusic_sync_time is None or \ track_row.gmusic_sync_time < item_mtime if upload_track: try: track_id = self.upload_track(item, pretend) if not pretend: track_row = TrackRow(id=item.id, gmusic_track_id=track_id, gmusic_sync_time=arrow.utcnow()) self._db.update_track(track_row) return 'uploaded' except Exception as err: print '>>> track failed to upload: {0}'.format(err) return 'error' return 'ok' def upload_track(self, item, pretend=False): print u'Uploading track: {artist} - {album} - [{track}] {title}'.format(**item) track_id = None if not pretend: uploaded, matched, not_uploaded = self._mm.upload(item.path, enable_matching=True) if item.path in uploaded: track_id = uploaded[item.path] print '>>> track uploaded (gmusic_trackid: {track_id})'.format(track_id=track_id) elif item.path in matched: track_id = matched[item.path] print '>>> track matched (gmusic_trackid: {track_id})'.format(track_id=track_id) else: reason = not_uploaded[item.path] m = re.search('ALREADY_EXISTS\((.*)\)', reason) if not m: raise GMusicTrackError(reason) track_id = m.group(1) print '>>> track already exists (gmusic_trackid: {track_id}'.format(track_id=track_id) else: track_id = '?' print '>>> track would be uploaded' return track_id
class GMClient(object): 'Wrapper class of gmusicapi.Mobileclient' def __init__(self): # Aplying patch to session.Musicmanager session.Musicmanager.login = MethodType(patched_musicmanaer_login, None, session.Musicmanager) self.man = Musicmanager(verify_ssl=False) self.all_songs = None def login(self): if not os.path.exists(OAUTH_PATH): logging.error('No {} exists'.format(OAUTH_PATH)) raise Exception('No {} exists'.format(OAUTH_PATH)) else: self.man.login(oauth_credentials=OAUTH_PATH, uploader_name='raspi_home') logging.info('Success!') # These are required to change meta data. # raspi_home does not require it. # if ('GOOGLE_PLAY_MUSIC_PASS' in os.environ and # 'GOOGLE_PLAY_MUSIC_USER' in os.environ): # self.api = Mobileclient() # self.api.login(os.environ['GOOGLE_PLAY_MUSIC_USER'], # os.environ['GOOGLE_PLAY_MUSIC_PASS'], # Mobileclient.FROM_MAC_ADDRESS) # logging.info('Logged in to google music') # self.is_available = True # else: # logging.warn('environmental variable GOOGLE_PLAY_MUSIC_PASS or GOOGLE_PLAY_MUSIC_USER' # ' is not available') # self.api = None def oauth(self): 'Run oauth for uploading/downloading songs' oauth_dir = os.path.dirname(OAUTH_PATH) if not os.path.exists(oauth_dir): logging.info('No oauth directory, create it') os.makedirs(oauth_dir) self.man.perform_oauth(open_browser=False, storage_filepath=OAUTH_PATH) # methods communicating with google server def update_songs(self): # if self.api is not None: # self.all_songs = self.api.get_all_songs() # else: # self.all_songs = [] self.all_songs = self.man.get_uploaded_songs() def get_all_songs(self): if self.all_songs is None: self.update_songs() return self.all_songs def get_songs(self, artist=None): return [ song for song in self.get_all_songs() if song['artist'] == artist ] def upload(self, file): if not os.path.exists(file): logging.error('No {} exists'.format(file)) else: (uploaded, matched, not_uploaded) = self.man.upload([file], enable_matching=True) if not_uploaded: logging.error('not uploaded because {}'.format(not_uploaded)) def has_song(self, title): return title in [song['title'] for song in self.get_all_songs()]