class gmObject: def __init__(self): self.mc = Mobileclient() self.wc = Webclient() self.mm = Musicmanager() def login(self, username, password): error.e = 0 if not self.mc.login(username, password): gmtPrintV("gmObject.login: Wrong username or password (or no internet connection)") error.e = error.LOGIN_FAILED return if not self.wc.login(username, password): gmtPrintV("gmObject.login: Wrong username or password (or no internet connection)") error.e = error.LOGIN_FAILED return if not self.mm.login(config.cred_path): gmtPrintV("gmObject.login: Wrong credentials (or no internet connection)") error.e = error.LOGIN_FAILED return def logout(self): error.e = 0 try: self.mc.logout() self.wc.logout() self.mm.logout() except: gmtPrintV("gmObject.logout: Logout failed") error.e = error.LOGOUT_FAILED
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 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
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 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 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 __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()
class GoogleManager(): def __init__(self, directory): self.music_dir = directory self.Google = Musicmanager() self.Google.login() def upload(self): files = [] for dirpath, dirnames, filenames in walk(self.music_dir): for name in filenames: if name.endswith('.mp3'): files += [join(dirpath, name)] for f in files: ret = self.Google.upload(f) print(ret)
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)
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 download_user_track(mgr: gmusicapi.Musicmanager, full_path, track): dirname = os.path.dirname(full_path) fp, temp_path = tempfile.mkstemp(dir=dirname) try: fname, audio = mgr.download_song(track['id']) fp.write(audio) os.rename(temp_path, full_path) finally: if os.path.exists(temp_path): os.unlink(temp_path)
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 __init__(self): """ Log into Musicmanager and get the library, either by loading an existing library file, or by generating a new one. """ self.kind = 'free' self.mm = Musicmanager() self.mm.login() self.songs = [] self.load_library() if not self.songs: self.gen_library()
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 __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 init(self, oauth_credentials): # Initialize the database logger.info("%s: Initializing database" % self.email) self._data_init() # Create the Musicmanager logger.info("%s: Logging in to Google music" % self.email) self.mm = Musicmanager() if not self.mm.login(oauth_credentials): logger.info("%s: Error logging in to Google music" % self.email) return False # Check if we already have any watch paths configured config = self._read_config() watched_paths = config["watched_paths"] if "watched_paths" in config else [] logger.info("%s: Found previously watched paths %s" % (self.email, watched_paths)) # Create the FileWatcher logger.info("%s: Creating the FileWatcher" % (self.email)) self.fw = FileWatcher(self.email, self._finished_writing_callback, watched_paths) return True
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.")
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 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 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 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")
from gmusicapi import Musicmanager, clients from node_translator import Translator import sys, json translator = Translator() # Get file paths from node file_names = translator.get_input() # Returns path to system stored oauth oauth_path = clients.OAUTH_FILEPATH # Init Musicmanager and login mm = Musicmanager() is_logged_in = mm.login(oauth_path) if is_logged_in: # Matching set to false due to lack of ffmpeg or avconv upload_result = mm.upload(file_names, '320k', False) print json.dumps(upload_result) # return upload_result if upload_result[0] != {}: print('Something happened here!') else: sys.exit('Not logged in')
from gmusicapi import Musicmanager from os import listdir from os.path import isfile, join import os import time import subprocess api = Musicmanager() api.login() mypath = '/home/pi/musics' while True: onlyfiles = [ f for f in listdir(mypath) if isfile(join(mypath,f)) ] if len(onlyfiles) > 0: time.sleep(5) for file in onlyfiles: print(file) api.upload(mypath + '/' + file) os.remove(mypath + '/' + file)
if __name__ == '__main__': original_sigint = signal.getsignal(signal.SIGINT) signal.signal(signal.SIGINT, exit_cleanly) parser = argparse.ArgumentParser(description="Google Music Player") parser.add_argument('-l','--login', required=False, help='Create login credentials.', action="store_true") parser.add_argument('-s','--shuffle', required=False, help='Play in random order.', action="store_true") parser.add_argument('-r', '--refresh', required=False, help='Refresh Library.', action="store_true") parser.add_argument('-d', '--display', required=False, help='Display playlist only.', action="store_true") parser.add_argument('-t', '--artist', required=False, help='Artist Filter' ) args = parser.parse_args() mm = Musicmanager() if args.login: mm.perform_oath() sys.exit(0) print "Logging In..." mm.login() if args.refresh: print "Getting Songs" library = mm.get_uploaded_songs() with open('library.txt','w') as f: pickle.dump( library, f) print "Loading Library..." with open('library.txt','r') as f:
class GoolgeMusicUploader(object): "Google music upload class" def __init__(self, config): self.credential_file = '' if len(config.googleplay_credential_file) > 0: self.credential_file = config.googleplay_credential_file else: self.credential_file = clients.OAUTH_FILEPATH self.mac_address = config.mac_address_for_gplay self.manager = Musicmanager(False) self.logger = logging.getLogger(__name__) def login(self): "Logs in" if not self.manager.login(self.credential_file, self.mac_address): raise AuthError( 'Could not authenticate music manager using {}'.format( self.credential_file)) def logout(self): "Logs out" if self.manager.is_authenticated: success = self.manager.logout() if success: self.logger.info('Logged out of Google Play Music') else: self.logger.warning('Failed to log out of Google Play Music') def upload(self, track_dir): "Does the upload." if not self.manager.is_authenticated: raise AuthError( "Music Manager not authenticated. Call 'login' first.") if not isdir(track_dir): raise DirectoryNotFoundError(track_dir) files = absolute_files(track_dir) info = TrackInfo() info.load(get_track_info_file(files)) track_file = get_track_file(files) result = UploadResult(track_dir, track_file, info.full_title) if track_file == DEFAULT_FILE_NAME: result.set_failure('MP3 Track file not found') return result locked = lock_file_exists(track_dir) if locked: result.set_failure('Lock file exists') return result metadata = AudioMetadata(track_file) metadata.apply_album_art(get_album_art_file(files)) metadata.apply_track_info(info) success, message = self.__upload_file__(track_file) if success: result.set_success(message) else: result.set_failure(message) return result def __upload_file__(self, track_file): self.logger.info('Uploading %s', track_file) upload_result = self.manager.upload(track_file) if upload_result[0] != {}: return True, upload_result[0] elif upload_result[1] != {}: return True, upload_result[2] elif upload_result[2] != {}: reason = list(upload_result[2].items())[0] return False, 'Couldn\'t upload {} because {}'.format( reason[0], reason[1])
class GPMClient(): def __init__(self, loop): self.loop = loop self.tpool = ThreadPoolExecutor(max_workers=2) self.client = Musicmanager(debug_logging=False) self.bot_dir = Path.cwd() self.dl_dir = self.bot_dir/"audio_cache" self.gpm_config_dir = self.bot_dir/"config"/"gpm" self.gpm_config_dir.mkdir(exist_ok=True) self.credential = None if (self.gpm_config_dir/"credential").is_file(): self.credential = str(self.gpm_config_dir/"credential") self.logged_in = False # Throws exception self.logged_in = self.client.login(self.credential) self.ffprobe = self._find_ffprobe() # Just wrap blocking functions to run in other thread. async def update_db(self): return await self.loop.run_in_executor(self.tpool, partial(self._update_db)) async def download(self, entry): return await self.loop.run_in_executor(self.tpool, partial(self._download, entry)) async def search(self, args): return await self.loop.run_in_executor(self.tpool, partial(self._search, args)) # This is a native coroutine async def play(self, player, trackinfo, **meta): return await player.playlist.add_gpm_entry(trackinfo, **meta) async def play_from_id(self, player, gpmid): trackinfo = await self.loop.run_in_executor(self.tpool, partial(self._get_trackinfo, gpmid)) if not trackinfo: raise ExtractionError("Failed to get trackinfo matches given GPMID.") await player.playlist.add_gpm_entry(trackinfo) def _update_db(self): tracklist = self.client.get_uploaded_songs() if not tracklist: return None db = sqlite3.connect(str(self.gpm_config_dir/"track.db")) db.execute("DROP TABLE IF EXISTS gpm") db.execute("CREATE TABLE IF NOT EXISTS gpm(title, artist, album, gpmid)") db.executemany("INSERT INTO gpm VALUES (:title, :artist, :album, :id)", tracklist) db.commit() db.close() return len(tracklist) def _download(self, entry): target = self.dl_dir/entry.expected_filename # Let it try 3 times for _ in range(3): _, abyte = self.client.download_song(entry.gpmid) if abyte: break if not abyte: return False, None with open(target, "wb") as f: f.write(abyte) return True, target def _get_duration(self, audio_file): if not self.ffprobe: return target = str(audio_file) cmd = self.ffprobe + " -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 " + target proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) stdout, __ = proc.communicate() log.debug("ffprobe stdout says: {}".format(stdout.decode("utf-8"))) # S**T # Ensure with regular expression return int(float(stdout.decode("utf-8").strip())) def _search(self, args): db = sqlite3.connect(str(self.gpm_config_dir/"track.db")) db.execute("CREATE TABLE IF NOT EXISTS gpm(title, artist, album, gpmid)") # Need better way to search DB... query = "%" + "%".join(args) + "%" cur = db.execute("SELECT * FROM gpm WHERE title||' '||artist||' '||album LIKE ?", [query, ]) result = cur.fetchall() db.close() res = [] for item in result: res.append(GPMTrack(item)) return res def _get_trackinfo(self, gpmid): db = sqlite3.connect(str(self.gpm_config_dir/"track.db")) db.execute("CREATE TABLE IF NOT EXISTS gpm(title, artist, album, gpmid)") true_gpmid = gpmid.split(":")[2] if not true_gpmid: return cur = db.execute("SELECT * FROM gpm WHERE gpmid = ?", [true_gpmid, ]) result = cur.fetchone() db.close() return GPMTrack(result) if result else None def _find_ffprobe(self): program = "ffprobe" # Original: musicbot/player.py def is_exe(fpath): found = os.path.isfile(fpath) and os.access(fpath, os.X_OK) if not found and sys.platform == 'win32': fpath = fpath + ".exe" found = os.path.isfile(fpath) and os.access(fpath, os.X_OK) return found fpath, __ = os.path.split(program) if fpath: if is_exe(program): return program else: for path in os.environ["PATH"].split(os.pathsep): path = path.strip('"') exe_file = os.path.join(path, program) if is_exe(exe_file): return exe_file log.debug("Failed to get ffprobe.") return None
from gmusicapi import Musicmanager mm = Musicmanager() mm.login() songs = mm.get_all_songs() print len(songs)
def play_song(song): 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) btn = OnButtonPress() btn.start() for song in song_dict: m = re.match(song_pattern, song['title']) print(m) if re.match(song_pattern, song['title']) 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('Mobileclient could not authenticate.') Mobileclient.logout(gpm)
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)
#! /usr/bin/env python3 from gmusicapi import Musicmanager from os.path import expanduser, join mm = Musicmanager() if not mm.login(): print('Login failed: did you run oauth_login.py?') quit() # No point properly checking for duplicates when overwriting them # gives the same result. songs = {} for song in mm.get_purchased_songs(): songs[song['id']] = ' - '.join( [song['title'], song['artist'], song['album']] ) for song in mm.get_uploaded_songs(): songs[song['id']] = ' - '.join( [song['title'], song['artist'], song['album']] ) print('Downloading %d songs to ~/.local/share/pmcli/songs. ' 'This might take a while...' % len(songs)) song_dir = join(expanduser('~'), '.local', 'share', 'pmcli', 'songs') i = 1 for id in songs: print('%d/%d: %s' % (i, len(songs), songs[id])) dl_path = join(song_dir, '%s.mp3' % songs[id].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 FreeClient(Client): """ Client for free users with limited functionality. Free users only have access to songs that they have either purchased or uploaded, and they must be downloaded before they can be played. Artists and albums cannot be generated, so the expand and radio methods have no use. """ def __init__(self): """ Log into Musicmanager and get the library, either by loading an existing library file, or by generating a new one. """ self.kind = 'free' self.mm = Musicmanager() self.mm.login() self.songs = [] self.load_library() if not self.songs: self.gen_library() def load_library(self): path = join(common.DATA_DIR, 'library.zip') common.w.outbar_msg('Loading library...') if not isfile(path): common.w.addstr(common.w.infobar, 'Could not find library file.') return try: with zipfile.ZipFile(path) as z: try: lib = json.loads(z.read('library.json').decode('utf-8')) except json.JSONDecodeError: # The .json file is invalid. common.w.addstr(common.w.infobar, 'Library file is corrupt.') return except zipfile.BadZipFile: # The .zip file is invalid. common.w.addstr(common.w.infobar, 'Library file is corrupt.') return for item in lib['songs']: try: self.songs.append( music_objects.LibrarySong(item, source='json')) except KeyError: # The file has the wrong data. common.w.addstr(common.w.infobar, 'Library file is corrupt.') return l = len(self.songs) common.w.outbar_msg('Loaded %s song%s.' % (l, '' if l is 1 else 's')) def gen_library(self): ids = [] # Avoid duplicates between purchased and uploaded songs. common.w.outbar_msg('Generating your library...') for song in self.mm.get_uploaded_songs(): if song['id'] not in ids: self.songs.append(music_objects.LibrarySong(song)) ids.append(song['id']) for song in self.mm.get_purchased_songs(): if song['id'] not in ids: self.songs.append(music_objects.LibrarySong(song)) ids.append(song['id']) # Todo: Use something other than json for library storage since it # doesn't really make logical sense (songs is a list, not a dict), # but for now it's very easy to use. with zipfile.ZipFile(join(common.DATA_DIR, 'library.zip'), 'w') as z: z.writestr('library.json', json.dumps({'songs': self.songs})) l = len(self.songs) common.w.outbar_msg('Generated %d song%s.' % (l, '' if l is 1 else 's')) common.w.now_playing() def expand(self, arg=None): """ Artists/albums cannot be generated. so free users cannot expand songs.. Keyword arguments: arg=None: Irrelevant. """ common.q.error_msg('Free users cannot use expand') def radio(self, arg=None): """ Artists/albums cannot be generated. so free users cannot create radio stations. Keyword arguments: arg=None: Irrelevant. """ common.q.error_msg('Free users cannot use radio') def search(self, query): """ Search the library for some query. and update the view with the results. Keyword arguments: query=None: The search query. """ if query is None: common.w.error_msg('Missing search query') return # Save the current view in case there are no results. cache = common.v.copy() if common.w.curses: limit = common.w.main.ylimit - 4 else: limit = 10 common.w.outbar_msg('Searching for \'%s\'...' % query) common.v.clear() count, query = 0, query.lower() # Search is case-insensitive. for song in self.songs: if any(query in song[k].lower() for k in ('name', 'artist', 'album')): count += 1 common.v['songs'].append(song) if count == limit: break common.w.outbar_msg('Search returned %d results.' % len(common.v)) if common.v.is_empty(): common.v.replace(cache)
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
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, 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 "Synching 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 = 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) # 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 "" print "Adding: %s" % os.path.basename(fn) 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.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" 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 if remove_missing: for s in goog_songs: print "" print "Removing: %s" % s['title'] 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='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): 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): tag = self.get_id3_tag(filename) results = self.wc.search(tag['title']) # NOTE - dianostic print here to check results if you're creating duplicates #print results['song_hits'] #print "%s ][ %s ][ %s ][ %s" % (tag['title'], tag['artist'], tag['album'], tag['track']) for r in results['song_hits']: if self.tag_compare(r, tag): # TODO: add rough time check to make sure its "close" return r 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 'track' not in g_song: g_song['track'] = 0 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.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('\\', '/'))
# Join the two strings in order to form the full filepath. filepath = path.join(root, filename) file_paths.append(filepath) return file_paths def uploadfiles(api, files): for f in files: upload = api.upload(f, transcode_quality="320k", enable_matching=True) print(upload) def get_dir(): parser = argparse.ArgumentParser() parser.add_argument( '-dir', action='store', dest='dir', required=True, help='Full directory path from which to upload songs') args = parser.parse_args() return args.dir if __name__ == "__main__": directory = get_dir() client = Musicmanager() logged_in = client.login() if logged_in: print "Successfully logged in. \n" \ "Attempting upload songs in directory {}".format(directory) uploadfiles(client, get_file_paths(directory))
def main(): #### Requests user specifies update library and/or playlists if len(sys.argv) != 3: print('Specify T/F arguments for uploading and updating playlists') print('e.g. python ' + sys.argv[0] + ' 1 0') print('which would:\n--> upload new songs\n--> NOT update playlists') sys.exit(0) #### Parameters music_dir = '/home/conor/Music/' print('Local music directory set to:', music_dir) accepted = input('Type "y" if this is correct directory: ') if accepted.lower() != 'y': print('Edit music_dir variable in source to run script...') print('Ending music management.') sys.exit(0) #### Some general information needed for both tasks is collected here # Get mp3 file names from music folder local_song_paths = glob.glob(music_dir + '*.mp3') # Get individual song names local_song_names = set() for p in local_song_paths: _, song_name = os.path.split(p) local_song_names.add(song_name) # Authenticate mc = Mobileclient() mc.oauth_login('38e42c4b00ca0a10') # Authenticates using on-disk token print('Mobile client authentication complete...') # Create dict of gpm 'song'': 'id' pairs song_ids = {} gpm_songs = mc.get_all_songs() for song in gpm_songs: song_ids[song['title']] = song['id'] #### Manage upload/deletion of songs uploading = sys.argv[1] if uploading == '1': mm = Musicmanager() mm.login(uploader_id='EE:20:80:B4:17:A9' ) # Authenticates using on-disk token print('Music manager authentication complete...') # Delete songs that no longer exist locally to_delete = set() for song in song_ids: if song not in local_song_names: to_delete.add(song) if len(to_delete) == 0: print('No songs to delete.') else: print('{} songs to delete:'.format(len(to_delete))) print([s for s in to_delete]) # delete_songs() method requires a list as input to_delete_ids = [] for s in to_delete: song_id = song_ids[s] to_delete_ids.append(song_id) mc.delete_songs(to_delete_ids) print('Deleted songs.') #### Uploading to_upload = [] for s in local_song_names: if s not in song_ids: to_upload.append(music_dir + s) print('{} songs to upload.'.format(len(to_upload))) if len(to_upload) != 0: accepted = input('Type "y" to commence upload now: ') if accepted.lower() != 'y': print('Ending music management.') sys.exit(0) mm.upload(to_upload) #### Create and edit playlists as required # Works by deleting all playlists and then re-creating from scratch playlisting = sys.argv[2] if playlisting == '1': # Refresh song list # (since we have uploaded new songs since original list generated) song_ids = {} gpm_songs = mc.get_all_songs() for song in gpm_songs: song_ids[song['title']] = song['id'] # Flush old playlists print('Deleting old playlists...') gpm_playlists = mc.get_all_playlists() for pl in gpm_playlists: mc.delete_playlist(pl['id']) print('Playlists deleted.') # Keep a dictionary of created playlists to prevent duplication playlist_ids = {} total = len(song_ids) completed = 0 # Create and update playlists print('Organising songs:') for s in song_ids: sid = song_ids[s] req_pls = required_playlists(s) for pl in req_pls: if pl in playlist_ids: pid = playlist_ids[pl] else: pid = mc.create_playlist(name=pl) playlist_ids[pl] = pid mc.add_songs_to_playlist(pid, sid) completed += 1 # Console output for number of songs sorted sys.stdout.write("\r{}/{} processed".format(completed, total)) sys.stdout.flush() print()
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('\\', '/'))
from gmusicapi import Musicmanager from os import listdir from os.path import isfile, join import os import time import subprocess api = Musicmanager() api.login() mypath = '/home/pi/musics' while True: onlyfiles = [f for f in listdir(mypath) if isfile(join(mypath, f))] if len(onlyfiles) > 0: time.sleep(5) for file in onlyfiles: print(file) api.upload(mypath + '/' + file) os.remove(mypath + '/' + file)
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("\\", "/"))
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
shutil.rmtree(mypath, ignore_errors=True) os.mkdir(mypath) # Gets URL of playlist url = input("Enter Youtube Playlist link (press enter for default): ") if (url == ""): url = default_url # Sets up Google Music api = Mobileclient() logged_in = False while (not logged_in): email = input("\nEmail: ") password = input("Password: "******"\n\nDownloading Videos") pl = Playlist(url) pl.download_all(mypath) # Gets list of all files onlyfiles = [f for f in listdir(mypath) if isfile(join(mypath, f))] # Converts each MP4 to audio num_digits = len( str(len(onlyfiles)) ) # Determines the number of letters to take off the beginning of the audio file name print("\n\nConverting to Audio")
def api_init(): api = Musicmanager() api.login() return api
#!/usr/bin/env python """ An upload script for Google Music using https://github.com/simon-weber/Unofficial-Google-Music-API. You may contact the author (thebigmunch) in #gmusicapi on irc.freenode.net. """ import os import sys from gmusicapi import Musicmanager input = sys.argv[1:] if len(sys.argv) > 1 else '.' formats = ('.mp3', '.flac', '.ogg', '.m4a', '.m4b', '.wma') MM = Musicmanager(debug_logging=False) def do_auth(): """ Authenticates the MM client. """ attempts = 0 # Attempt to login. Perform oauth only when necessary. while attempts < 3: if MM.login(): break MM.perform_oauth() attempts += 1
def get_musicmanager(debug=True): mm = Musicmanager(debug_logging=debug) if not mm.login(): mm.perform_oauth() return mm
#!/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 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()]