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)
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}")
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 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
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/gpymusic/songs. ' 'This might take a while...' % len(songs)) song_dir = join(expanduser('~'), '.local', 'share', 'gpymusic', '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('/', '---')) with open(dl_path, 'wb') as f: f.write(mm.download_song(id)[1])
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: library = pickle.load(f) # Create playlist playlist = [] for song in library: if args.artist: if args.artist.lower() not in song['artist'].lower(): continue playlist.append(song)
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: library = pickle.load( f ) # Create playlist playlist = [] for song in library: if args.artist: if args.artist.lower() not in song['artist'].lower(): continue playlist.append( song )
class TheGoogs: DEFAULT_CREDS_DIR = "~/gmusic/.oauth" DEFAULT_MOBILE_DEVICE_ID = "342e914abacc484d" # Galaxy Tab DEFAULT_MANAGER_MAC_ADDRESS = "A2:C2:E2:CC:C7:37" # Made-up def __init__(self, creds_dir=DEFAULT_CREDS_DIR): self.creds_dir = os.path.expanduser(creds_dir) logger.info("Creating TheGoogs from creds at {}".format( self.creds_dir)) self.mobile_creds = os.path.join(self.creds_dir, "mobile.creds") self.manager_creds = os.path.join(self.creds_dir, "manager.creds") self.mobile = Mobileclient() self.manager = Musicmanager() logger.debug("Logging in") self.mobile.oauth_login(device_id=self.DEFAULT_MOBILE_DEVICE_ID, oauth_credentials=self.mobile_creds) self.manager.login(uploader_id=self.DEFAULT_MANAGER_MAC_ADDRESS, oauth_credentials=self.manager_creds) def get_libdata(self): logger.info("Fetching libdata ...") logger.info("... fetching registered devices") registered_devices = self.mobile.get_registered_devices() logger.info("... fetching all songs") library = self.mobile.get_all_songs() logger.info("... fetching playlist metadata") playlists = self.mobile.get_all_playlists() logger.info("... fetching playlist contents") playlist_contents = self.mobile.get_all_user_playlist_contents() logger.info("... fetching uploaded songs") uploaded_songs = self.manager.get_uploaded_songs() logger.info("... fetching purchased songs") purchased_songs = self.manager.get_purchased_songs() return Libdata(timestamp=datetime.utcnow(), registered_devices=registered_devices, all_songs=library, playlist_metadata=playlists, playlists=playlist_contents, uploaded_songs=uploaded_songs, purchased_songs=purchased_songs) def get_streamed_song(self, id): logger.info("Downloading streamed song id {}".format(id)) stream_url = self.mobile.get_stream_url(id) response = urllib.request.urlopen(stream_url) return response.read() def get_uploaded_song(self, id): logger.info("Downloading uploaded song id {}".format(id)) suggested_filename, data = self.manager.download_song(id) return data
from gmusicapi import Musicmanager import os.path storage_filepath = '/home/alex/.local/share/gmusicapi/oauth.cred' mm = Musicmanager() if os.path.isfile(storage_filepath): mm.login() else: Musicmanager.perform_oauth(storage_filepath, open_browser=True) songs = mm.get_uploaded_songs(incremental=False) print(songs) song_id = [] for x in songs: song_id.append(x.get('id')) print(song_id) for an_id in song_id: filename, audio = mm.download_song(an_id) with open(filename, 'wb') as f: f.write(audio) input("Enter: ") mm.logout(revoke_oauth=False)
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 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 method has 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 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.getmaxyx()[0] - 4 else: limit = 50 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 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
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)
if __name__ == '__main__': # load settings inifile = configparser.SafeConfigParser() inifile.read("./settings.ini") pickle_filename = inifile.get("settings", "picklefile") music_root = inifile.get("settings", "musicroot") # # login mm = Musicmanager() # mm.perform_oauth() # once mm.login() # # get music dict mymusics = mm.get_uploaded_songs() # with open("newsonglist.json","r") as f: # mymusics = json.load(f)# for test # get id list all_ids = set([el["id"] for el in mymusics]) # convert list to dict music_dict = {el["id"]: el for el in mymusics} # get downloaded id list if os.path.isfile(pickle_filename): with open(pickle_filename, "rb") as f: downloaded_ids = pickle.load(f) else: downloaded_ids = set([])
from os import system from gmusicapi import Musicmanager # API Documentation https://unofficial-google-music-api.readthedocs.io/en/latest/reference/musicmanager.html if __name__ == "__main__": print("Start > " + datetime.datetime.now().isoformat()) mm = Musicmanager() # mm.perform_oauth() mm.login() # Get list of uploaded songs upl_song_list = mm.get_uploaded_songs() print upl_song_list # Upload a song to the library #resp = mm.upload( # "/tmp/Unconditionally - Katy Perry Piano Cover - Music Video.mp3", enable_matching=True) # Download a song from Library filename, audio = mm.download_song(u'db0c6360-73a9-341f-a794-b627742748b6') # if open() throws a UnicodeEncodeError, either use # filename.encode('utf-8') # or change your default encoding to something sane =) with open(filename, 'wb') as f: f.write(audio)
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()]