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 _process_youtube_upload(youtube_url, ydl_opts, music, metadata_opts, credential, uploader_name): manager = Musicmanager() manager.login(credential, uploader_name=uploader_name) with youtube_dl.YoutubeDL(ydl_opts) as ydl: info_dict = ydl.extract_info(youtube_url, download=False) if music.title == "": music.title = info_dict.get('title', None) music.save() metadata_opts = { i: getattr(music, i) for i in [ 'title', 'album', 'composer', 'genre', 'language', 'artist', 'album_artist' ] } logger.debug('New metadata opts: ' + str(metadata_opts)) ffmpeg_mp3_metadata_pp = FFmpegMP3MetadataPP(ydl, metadata_opts) ydl.add_post_processor(ffmpeg_mp3_metadata_pp) ydl.download([youtube_url]) music_filepath = ydl.prepare_filename(info_dict) if not music_filepath.endswith('.mp3'): music_filepath = music_filepath.replace( music_filepath[music_filepath.rfind('.'):], '.mp3') logger.debug("Music filepath: " + music_filepath) manager.upload(music_filepath, enable_matching=True, enable_transcoding=False) # Already transcoding. if os.path.isfile(music_filepath): os.remove(music_filepath)
def download(mode, url, num): print(f"Downloading for {mode}") #Options ydl_opts = { 'format': 'bestaudio/best', 'postprocessors': [{ 'key': 'FFmpegExtractAudio', 'preferredcodec': 'mp3', 'preferredquality': '320', }], 'logger': MyLogger(), 'progress_hooks': [my_hook], 'outtmpl': folders[num][mode][0] + '/%(title)s.%(ext)s' } #Download the video and extract all the metadata with youtube_dl.YoutubeDL(ydl_opts) as ydl: info_dict = ydl.extract_info(url, download=True) video_title = info_dict.get('title', None) video_filename = '.'.join( ydl.prepare_filename(info_dict).split('.')[:-1]) + '.mp3' print(video_filename) #Edit mp3 tag. try: print(f"Editing artist tag to {mode.capitalize()}...") mp3 = MP3File(video_filename) mp3.artist = mode.title() mp3.save() insert_album_art(video_filename, info_dict['id']) print("Done!\n") except Exception as e: print("Error at editing mp3 tag.\n") print(e) #Backup if num != 3: try: print(f"Making a backup of {video_title}...") copy(video_filename, folders[num][mode][1]) print("Done!\n") except: print("Error at doing backup.\n") #Upload to google if num != 3: try: print(f"Uploading {video_title} to Google Music\n") print(f'With url {url}') mm = Musicmanager() mm.login(uploader_id='D0:50:99:83:B0:0C') mm.upload(video_filename) print("Done!\n") except Exception as e: print("Error at uploading the song to google:\n" + e)
def init(): mm = Musicmanager() try: script_path = os.path.dirname(os.path.abspath(__file__)) except NameError: script_path = os.getcwd() mm.login(oauth_credentials=os.path.join(script_path, "oauth.cred")) return mm
def upload(path): mm = Musicmanager() mm.login() for root, dirs, files in os.walk(path): for file_ in files: mp3FilePath = os.path.join(root, file_) print( "upload : " + file_ ) mm.upload(mp3FilePath) os.remove(mp3FilePath)
class GoogleMusicManager: def __init__(self): self.api = Musicmanager(debug_logging=False) with open(path + "oauth.cred", 'w+') as tmp: tmp.write(settings['google']['musicmanager']) tmp.close() self.api.login(tmp.name) os.remove(tmp.name) def upload_song(self, file): self.api.upload(file)
class GoogleMusicManager: def __init__(self): self.api = Musicmanager(debug_logging=False) refresh_token = json.loads( settings['google']['musicmanager'])['refresh_token'] credentials = session.credentials_from_refresh_token( refresh_token, session.Mobileclient.oauth) self.api.login(credentials) def upload_song(self, file): self.api.upload(file)
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")
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 upload(directory='.', oauth=os.environ['HOME'] + '/oauth', remove=False, uploader_id=__DEFAULT_MAC__): logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) logger.info("Init Daemon - Press Ctrl+C to quit") api = Musicmanager() event_handler = MusicToUpload() event_handler.api = api event_handler.path = directory event_handler.willDelete = remove event_handler.logger = logger if not api.login(oauth, uploader_id): print("Error with oauth credentials") sys.exit(1) files = [file for file in glob.glob(directory + '/**/*', recursive=True)] for file_path in files: if os.path.isfile(file_path): logger.info("Uploading : " + file_path) uploaded, matched, not_uploaded = api.upload(file_path, True) if remove and (uploaded or matched): os.remove(file_path) observer = Observer() observer.schedule(event_handler, directory, recursive=True) observer.start() try: while True: time.sleep(1) except KeyboardInterrupt: observer.stop() observer.join()
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 index(request): args = {} if request.user.is_authenticated: credential = request.user.profile.google_oauth if not credential: return HttpResponse('No credentials found. Remake an account.') manager = Musicmanager() # TODO: Maybe change mac address for each user? login_success = manager.login( credential, uploader_name="GMusicManagerOnline - {}".format( request.user.username)) args.update({'login_success': login_success}) if login_success: quota = manager.get_quota() default_fields_form = DefaultFieldsForm( request.POST or None, instance=request.user.profile) if default_fields_form.is_valid(): default_fields_form.save() return redirect('index') args.update({ 'currently_uploaded': quota[0], 'upload_limit': quota[1], 'default_fields_form': default_fields_form }) manager.logout() return render(request, 'core/index.html', args)
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 download(directory=".", oauth=os.environ['HOME'] + "/oauth", device_id=__DEFAULT_MAC__): logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) logger.info("Init Daemon - Press Ctrl+C to quit") api = Musicmanager() if not api.login(oauth, device_id): print("Error with oauth credentials") sys.exit(1) for song in api.get_uploaded_songs(): folder_path = os.path.join(directory, song['album_artist'], song['album']) file_path = os.path.join( folder_path, '%d - %s.mp3' % (song['track_number'], song['title'].replace('/', '_'))) file_path = file_path.encode('utf8') folder_path = folder_path.encode('utf8') if not os.path.exists(file_path): filename, audio = api.download_song(song['id']) if not os.path.exists(folder_path): os.makedirs(folder_path) with open(file_path, 'wb') as f: f.write(audio)
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 initializeClient(): client = Musicmanager() if (client.login()): return client else: client.perform_oauth(open_browser=True) initializeClient()
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 download(base_dir: str = ".", creds: str = __DEFAULT_CREDS__, device_id: str = __DEFAULT_MAC__) -> None: api = Musicmanager() if not api.login(creds, device_id): logger.error("Error with oauth credentials") sys.exit(1) Song = namedtuple('Song', ['artist', 'album', 'track', 'title', 'id']) def _download(song: Song, downloader: Callable) -> None: logger.debug(f"Downloading song '{song.title}'") f, audio = downloader(song.id) folder = os.path.join(base_dir, song.artist, song.album) if not os.path.exists(folder): logger.debug(f"Creating folder '{folder}'") os.makedirs(folder) file = os.path.join(folder, f'{song.track}-{song.title}.mp3') with open(file, 'wb') as f: logger.debug(f"Writing file '{file}'") f.write(audio) songs = api.get_uploaded_songs() n = len(songs) logger.debug(f"Downloading '{n}' to folder '{base_dir}'") future_to_song = {} with ThreadPoolExecutor() as executor: for song in songs: artist = song['album_artist'] album = song['album'] track = song['track_number'] title = song['title'].replace('/', '_').replace('?', '_') iden = song['id'] s = Song(artist=artist, album=album, track=track, title=title, id=iden) future = executor.submit(_download, song=s, downloader=api.download_song) future_to_song[future] = s succeeded = 0 failed = 0 for future in concurrent.futures.as_completed(future_to_song): s = future_to_song[future] if future.exception(): logger.warning( f"Failed to download song '{s.title}' because '{future.exception()}'" ) failed += 1 continue succeeded += 1 logger.debug( f"Completed. Total {n} succeded {succeeded} failed {failed}")
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 youtube_upload(request): # TODO: Async status updates? if not request.user.is_authenticated: return HttpResponse('log in first') credential = request.user.profile.google_oauth if not credential: return HttpResponse('no creds') manager = Musicmanager() # TODO: Maybe change mac address for each user? login_success = manager.login( credential, uploader_name="GMusicManagerOnline - {}".format(request.user.username)) form = YoutubeUploadForm() args = {'can_login': login_success, 'form': form, 'success': False} if request.method == "POST": form = YoutubeUploadForm(request.POST) if form.is_valid(): music = form.save() for i in [ 'title', 'album', 'composer', 'genre', 'language', 'artist', 'album_artist' ]: if getattr(music, i) == "": setattr(music, i, getattr(request.user.profile, "default_" + i)) music.save() youtube_url = request.POST.get('youtube_url') metadata_opts = { i: getattr(music, i) for i in [ 'title', 'album', 'composer', 'genre', 'language', 'artist', 'album_artist' ] if getattr(music, i) != "" } ydl_opts = { 'format': 'bestaudio/best', 'outtmpl': settings.MEDIA_ROOT + "/{}{}.%(ext)s".format( request.user.username, int(time.time())), 'postprocessors': [{ 'key': 'FFmpegExtractAudio', 'preferredcodec': 'mp3', 'preferredquality': '320', }], } upload_args = (youtube_url, ydl_opts, music, metadata_opts, credential, "GMusicManagerOnline - {}".format( request.user.username)) upload_thread = threading.Thread(target=_process_youtube_upload, args=upload_args) upload_thread.start() args.update({'success': True}) args.update({'form': form}) manager.logout() return render(request, 'core/youtube.html', args)
def download_all(outdir: str = DEF_OUT_DR, device_id: str = DEF_DEV_ID, mac_addr: str = DEF_MAC_AD): mc = Mobileclient() mm = Musicmanager() mc.oauth_login(DEF_DEV_ID) mm.login(uploader_id=DEF_MAC_AD) songs = mc.get_all_songs() print(f'Downloading {len(songs)}') for song in songs: filename, audio = mm.download_song(song['id']) print(f'Downloading {song["id"]} : {filename}', flush=True) with open(f'{outdir}/{filename}', 'wb') as fh: fh.write(audio) with open(f'{outdir}/{filename}.meta', 'w') as fh: json.dump(song, fh, indent=2, sort_keys=True)
def main(): path = sys.argv[1] if not os.path.exists(path): print("Invalid file path. %s" % path) return api = Musicmanager() api.login() if not api.is_authenticated(): print("Login Error\n") return print("start upload...\n") upload_info = api.upload(path) print(upload_info) print("upload is completed.\n") api.logout()
def download(directory: str = ".", oauth: str = __DEFAULT_OAUTH_PATH__, device_id: str = __DEFAULT_MAC__, down_logger: logging.Logger = logger) -> None: api = Musicmanager() if not api.login(oauth, device_id): if down_logger: down_logger.error("Error with oauth credentials") sys.exit(1) if down_logger: down_logger.info("Init Daemon - Press Ctrl+C to quit") songs = api.get_uploaded_songs() songs_total = len(songs) if down_logger: logger.debug("Downloading '%d' to folder '%s'" % (songs_total, directory)) future_to_song = {} with ThreadPoolExecutor() as executor: for song in songs: artist = song['album_artist'] album = song['album'] track_number = song['track_number'] title = song['title'].replace('/', '_').replace('?', '_') track_id = song['id'] song_object = Song(artist=artist, album=album, track_number=track_number, title=title, id=track_id) future = executor.submit(_download, song=song_object, api=api, base_dir=directory, thread_logger=down_logger) future_to_song[future] = song succeeded = 0 failed = 0 for future in concurrent.futures.as_completed(future_to_song): song = future_to_song[future] if future.exception(): if down_logger: down_logger.warning( "Failed to download song '%s' because '%s'" % (song.title, future.exception())) failed += 1 continue succeeded += 1 if down_logger: down_logger.debug( "Completed. Total %d | %d succeeded | %d failed" % (songs_total, succeeded, 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
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 MyCdList: mm = None library = None def authenticatewithgoogle(self, option): self.mm = Musicmanager() self.mm.login() # currently named oauth_login for the Mobileclient if option == 0: self.library = self.mm.get_purchased_songs() elif option == 1: self.library = self.mm.get_uploaded_songs() def getallartist(self): donotaddthis = "The 100 Most Essential Pieces of Classical Music" artists = [] artistsset = set() [ artistsset.add(track['artist']) for track in self.library if track['album'] != donotaddthis ] artists = list(artistsset) artists.sort() return artists def getalbumsforartist(self, artist): albums = [] albumsset = set() [ albumsset.add(track['album']) for track in self.library if track['artist'] == artist ] albums = list(albumsset) albums.sort() return albums
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 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(request): # TODO: Async status updates? if not request.user.is_authenticated: return HttpResponse('log in first') credential = request.user.profile.google_oauth if not credential: return HttpResponse('no creds') manager = Musicmanager() # TODO: Maybe change mac address for each user? login_success = manager.login( credential, uploader_name="GMusicManagerOnline - {}".format(request.user.username)) form = MusicUploadForm() args = {'can_login': login_success, 'form': form, 'success': False} if request.method == "POST": form = MusicUploadForm(request.POST, request.FILES) if form.is_valid(): music = form.save() music_file = request.FILES.get('music_file') ext = music_file.name[music_file.name.rfind('.'):] fs = FileSystemStorage() filename = fs.save("{0}{1}".format(request.user.username, ext), music_file) music_filepath = fs.path(filename) post_filepath = music_filepath + ".mp3" options = { i: getattr(music, i) for i in [ 'title', 'album', 'composer', 'genre', 'language', 'artist', 'album_artist' ] if getattr(music, i) != "" } logger.info("Transcoding metadata: " + str(options)) options.update({'quality': '320k'}) _transcode(music_filepath, options, post_filepath) if os.path.isfile(music_filepath): os.remove(music_filepath) success, _, _ = manager.upload( # Already transcoding. post_filepath, enable_matching=True, enable_transcoding=False) if os.path.isfile(post_filepath): os.remove(post_filepath) args.update({'success': True}) args.update({'form': form}) manager.logout() return render(request, 'core/upload.html', args)
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 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 Kotone: def __init__(self, device_id: str, cred_mc: oauth2client.client.OAuth2Credentials, cred_mm: oauth2client.client.OAuth2Credentials): self._mc = Mobileclient() if not self._mc.oauth_login(device_id, cred_mc): raise RuntimeError('Mobileclient login failed') self._mm = Musicmanager() if not self._mm.login(cred_mm, _UPLOADER_ID, _UPLOADER_NAME): raise RuntimeError('Musicmanager login failed') def get_songs(self): return self._mc.get_all_songs() def download_song(self, song_id: str) -> Tuple[str, bytes]: return self._mm.download_song(song_id) def stream_url(self, song_id: str) -> str: return self._mc.get_stream_url(song_id) def upload(self, paths): return self._mm.upload(paths)
def upload(directory='.', oauth=os.environ['HOME'] + '/oauth', remove=False, uploader_id=__DEFAULT_MAC__, oneshot=False): logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) logger.info("Init Daemon - Press Ctrl+C to quit") api = Musicmanager() if not api.login(oauth, uploader_id): print("Error with oauth credentials") sys.exit(1) observer = None if not oneshot: event_handler = MusicToUpload() event_handler.api = api event_handler.oauth = oauth event_handler.uploader_id = uploader_id event_handler.path = directory event_handler.remove = remove event_handler.logger = logger observer = Observer() observer.schedule(event_handler, directory, recursive=True) observer.start() files = [ file for file in glob.glob(glob.escape(directory) + '/**/*', recursive=True) ] for file_path in files: upload_file(api, file_path, logger, remove=remove) if oneshot: sys.exit(0) try: while True: time.sleep(1) except KeyboardInterrupt: observer.stop() observer.join()
print "Reading config from: " + cfg_file with open(cfg_file) as config_file: cfg = json.load(config_file) assert os.path.isdir(cfg['library']) except: print "Failed to load configuration from settings.json" sys.exit(); # Login to GoogleMusic's Mobile API to get library metada api = Mobileclient() api.login(cfg["email"], cfg["password"], Mobileclient.FROM_MAC_ADDRESS) # And now login to the Musicmanager to perform downloads. mm = Musicmanager() if (not mm.login()): mm.perform_oauth() # Get the local copy of the track ids (these have been sync'd from remote) create_path_if_not_exist(APP_DIRS.user_data_dir) track_ids_file = os.path.join(APP_DIRS.user_data_dir, 'track_ids') local_track_ids = None print "Reading local Track Ids from: " + track_ids_file try: with open (track_ids_file, "r") as file_handle: local_track_ids = json.loads(file_handle.read()) print "Loaded {0} Track Id(s)".format(len(local_track_ids)) except IOError as io_error: if io_error.errno == errno.ENOENT: local_track_ids = []
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'])
#!/usr/bin/env python3 from gmusicapi import Musicmanager # pip install gmusicapi from glob import glob from argparse import ArgumentParser m = Musicmanager() if not m.login(): m.perform_oauth() m.login() def main(): parser = ArgumentParser() parser.add_argument("files", nargs="+", help="Files to upload") args = parser.parse_args() for file in args.files: if '*' in file: for subfile in glob(file): print("Starting on {}...".format(subfile), end="\r") m.upload(subfile) print("Completed {} ".format(subfile)) else: print("Starting on {}...".format(file), end="\r") m.upload(file) print("Completed {} ".format(file)) if __name__ == "__main__": main()
# 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))
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 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 python3 from gmusicapi import Musicmanager mm = Musicmanager() mm.perform_oauth() if mm.login(): print('Authorization successful.') mm.logout() else: print('Authorization failed.')
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'])
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.") # remove mp3 file from directory (default) # if you want to keep the file change config (removeFile to true) if "True" in removeFile: os.remove(latestFile) print("Removed downloaded file. Goodbye.") else: print("Goodbye.") time.sleep(1)
else: print " upload failed !" upload_ok = False # remove uploaded file if upload_ok : os.remove(PUSH_DIR + musique) # init id_list={} try : id_list = marshal.load(open(DICT_FILE, "rb")) except : pass mm = Musicmanager() if not mm.login() : mm.perform_oauth() mm.login() for arg in sys.argv : if arg == 'pull' : print 'pulling...' pull() elif arg == 'push' : print 'pushing...' push() # finish mm.logout() marshal.dump(id_list, open(DICT_FILE, 'wb'))
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 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, 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')
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.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 User: def __init__(self, email, app_data_dir): self.email = email self.app_data_dir = app_data_dir self.db_lock = threading.Lock() 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 logout(self): self.mm.logout() self.fw.stop_watching() def _read_config(self): return util.read_config(os.path.join(self.app_data_dir, self.email, CFG_FILE_NAME)) def _write_config(self, config): util.write_config(config, os.path.join(self.app_data_dir, self.email, CFG_FILE_NAME)) def get_watched_paths(self): logger.debug("reading config from %s" % os.path.join(self.app_data_dir, self.email)) config = self._read_config() logger.debug("read config: %s" % config) return config["watched_paths"] if "watched_paths" in config else [] def add_watch_path(self, path): # Add to file watcher self.fw.watch(path) # Add to the config config = self._read_config() if "watched_paths" not in config: config["watched_paths"] = [path] else: if path not in config["watched_paths"]: config["watched_paths"].append(path) self._write_config(config) def remove_watch_path(self, path): # Remove from the file watcher self.fw.remove_watch(path) # Remove from the config config = self._read_config() if "watched_paths" in config: if path in config["watched_paths"]: config["watched_paths"].remove(path) else: logger.info("%s trying to remove watch path %s that we weren't watching" % (self.email, path)) self._write_config(config) def set_default_action(self, default_action): config = self._read_config() config["default_action"] = default_action self._write_config(config) def get_default_action(self): config = self._read_config() return config.get("default_action", "scan_only") def scan_existing_files(self): watched_paths = self.get_watched_paths() logger.debug("%s Scanning existing files in these directories: %s" % (self.email, watched_paths)) for watched_path in watched_paths: logger.debug("Scanning existing files in %s" % watched_path) for root, subFolders, files in os.walk(watched_path): logger.debug("root: %s, subfolders: %s, files: %s" % (root, subFolders, files)) for file in files: filename, fileExtension = os.path.splitext(file) logger.debug("looking at file %s, filename = %s, file extension = %s" % (file, filename, fileExtension)) if fileExtension == ".mp3": logger.debug("Found file %s" % file); self._update_path(os.path.join(root, file), FileStatus.Scanned) logger.debug("scanning finished"); def upload_scanned(self): songs = self.get_all_songs() for song_path in songs.keys(): if songs[song_path]["status"] == FileStatus.Scanned: logger.debug("Uploading song %s" % song_path) self.upload(song_path) return def _data_init(self): with self.db_lock: con = sql.connect(os.path.join(self.app_data_dir, self.email, DB_NAME)) with con: cur = con.cursor() cur.execute('''CREATE TABLE IF NOT EXISTS songs(path TEXT PRIMARY KEY, id TEXT, status TEXT)''') def _update_path(self, path, status, id=None, override=False): logger.info("Updating path %s with id %s and status %s" % (path, id, status)) info = ((path, "" if not id else id, status) ) with self.db_lock: con = sql.connect(os.path.join(self.app_data_dir, self.email, DB_NAME)) with con: cur = con.cursor() if not override: # Check if the song is already in the data store and, if so, what its status is cur.execute('''SELECT status FROM songs WHERE path=(?)''', (path,)) res = cur.fetchone() if res: res = res[0] if res == FileStatus.Uploaded: # If it's already been uploaded, don't override that status with something else return cur.execute('''REPLACE INTO songs VALUES(?, ?, ?)''', info) def _finished_writing_callback(self, new_file_path): logger.debug("New file %s" % new_file_path) filename, file_extension = os.path.splitext(new_file_path) if file_extension != ".mp3": logger.debug("Skipping non-mp3 file") return self._update_path(new_file_path, FileStatus.Scanned) if self.get_default_action() == "auto_upload": logger.info("Uploading new file: %s" % new_file_path) self.upload(new_file_path) @staticmethod def _find_gmusic_song(scanned_song_tags, gmusic_songs): try: artist = scanned_song_tags.artist.lower() album = scanned_song_tags.album.lower() title = scanned_song_tags.title.lower() #logger.debug("Found scanned song %s - %s - %s" % (artist, album, title)) except: logger.debug("Error grabbing song meta data") return # Search for an uploaded song that matches for gmusic_song in gmusic_songs: up_artist = gmusic_song['artist'].lower() up_album = gmusic_song['album'].lower() up_title = gmusic_song['title'].lower() #logger.debug("Looking at song %s - %s - %s" % (up_artist, up_album, up_title)) if artist == up_artist and album == up_album and title == up_title: #logger.debug("Found match!") return gmusic_song return None def sync_library(self): logger.debug("Syncing") uploaded_songs = self.mm.get_all_songs() scanned_songs = self.get_all_songs() logger.debug("found %d scanned songs" % len(scanned_songs)) # Go through all songs marked 'scanned' and search for a matching that's already been uploaded. # If we find one, grab the id and mark the song as uploaded for song_path in scanned_songs.keys(): # Since we only have the path, scan its tags to get the meta data audioFile = eyed3.load(song_path) if audioFile and audioFile.tag: local_song = scanned_songs[song_path] gmusic_song = User._find_gmusic_song(audioFile.tag, uploaded_songs) # Now make sure our static is in sync, possibilities: # 1) We show it as uploaded but google doesn't -> mark it as 'scanned', remove our id # 2) Google shows it as uploaded but we don't -> mark it as 'uploaded', add the id # 3) We both show it as uploaded and the ids match -> do nothing # 4) Neither of us think it was uploaded -> do nothing # 5) Google has it but we don't at all -> TODO!! (option for download?) we'll need to detect this another way (currently searching only by scanned songs) if gmusic_song: # Google shows this song if local_song['status'] == FileStatus.Scanned: # Google shows it as uploaded but we don't. Mark it as uploaded and update the id #logger.debug("'%s - %s - %s' was already uploaded, updating its id to %s" % (gmusic_song['artist'], gmusic_song['album'], gmusic_song['title'], gmusic_song['id'])) self._update_path(song_path, FileStatus.Uploaded, gmusic_song['id'], override=True) elif local_song['status'] == FileStatus.Uploaded: # We both show it as uploaded, make sure ids match if local_song['id'] != gmusic_song['id']: #logger.debug("Ids differ! Updating to use google's id") self._update_path(song_path, FileStatus.Uploaded, gmusic_song['id'], override=True) else: pass #logger.debug("Ids match! No update needed") else: # No matching song on google found if local_song['status'] == FileStatus.Uploaded: #logger.debug("We show the song as uploaded but google doesn't, changing status to scanned and clearing id") self._update_path(song_path, FileStatus.Scanned, override=True) else: pass #logger.debug("Neither side thinks it's uploaded, no update needed") else: logger.debug("Error loading metadata for song %s" % song_path) def upload(self, file_path): uploaded, matched, not_uploaded = self.mm.upload(file_path, enable_matching=False) # async me! if uploaded: logger.info("Uploaded song %s with ID %s" % (file_path, uploaded[file_path])) self._update_path(file_path, FileStatus.Uploaded, uploaded[file_path]) if matched: logger.info("Matched song %s with ID %s" % (file_path, matched[file_path])) self._update_path(file_path, FileStatus.Uploaded, uploaded[file_path]) if not_uploaded: reason_string = not_uploaded[file_path] if "ALREADY_EXISTS" in reason_string: song_id = reason_string[reason_string.find("(") + 1 : reason_string.find(")")] logger.info("Song already exists with ID %s, updating database" % song_id) # The song ID is located within parentheses in the reason string self._update_path(file_path, FileStatus.Uploaded, song_id) else: logger.info("Unable to upload song %s because %s" % (file_path, reason_string)) self._update_path(file_path, FileStatus.Error, reason_string) def get_all_songs(self): songs = {} with self.db_lock: con = sql.connect(os.path.join(self.app_data_dir, self.email, DB_NAME)) with con: cur = con.cursor() for row in cur.execute('''SELECT * FROM songs'''): song_path = row[0] song_id = row[1] song_status = row[2] songs[song_path] = {'id': song_id, 'status': song_status} return songs
#!/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 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 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('\\', '/'))
def api_init(): api = Musicmanager() api.login() return api
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
# FORMATTER formatter = logging.Formatter('%(asctime)s :: %(levelname)s :: %(message)s') # HANDLER -> activity.log file_handler = RotatingFileHandler('logs/activity.log', 'a', 1000000, 1) #Append, 1Mo, 1 backup file_handler.setLevel(logging.DEBUG) file_handler.setFormatter(formatter) logger.addHandler(file_handler) logger.info('Edgar, reporting for duty ...') ### SETUP: GOOGLE MUSIC API - MUSICMANAGER requests.packages.urllib3.disable_warnings() oauth_file = '/root/.oauthfile' mac_address = 'XXXX' api = Musicmanager(True,True,True) musicmanager_login_status = api.login(oauth_file, mac_address) logger.debug("Musicmanager login status: " + str(musicmanager_login_status)) ### SETUP: GOOGLE MUSIC API - WEBCLIENT google_login = '******' google_passw = 'XXXX' webclient = Webclient(True, True, True) webclient_login_status = webclient.login(google_login, google_passw) logger.debug("Webclient login status: " + str(webclient_login_status)) ### SETUP: SOUNDCLOUD API soundcloud_userid = 'XXXX' soundcloud_clientid = 'XXXX' soundcloud_api_baseurl = 'https://api-v2.soundcloud.com/users/' soundcloud_api_favoriteparam = '/likes?limit=10&offset=0&client_id=' soundcloud_favorites_url = soundcloud_api_baseurl + soundcloud_userid + soundcloud_api_favoriteparam + soundcloud_clientid