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(mm: Musicmanager, songid, pathfile=""): filename, audio = mm.download_song(songid) # if open() throws a UnicodeEncodeError, either use # filename.encode('utf-8') # or change your default encoding to something sane =) with open(os.path.join(pathfile, filename), 'wb') as f: f.write(audio)
def download_user_track(mgr: gmusicapi.Musicmanager, full_path, track): dirname = os.path.dirname(full_path) fp, temp_path = tempfile.mkstemp(dir=dirname) try: fname, audio = mgr.download_song(track['id']) fp.write(audio) os.rename(temp_path, full_path) finally: if os.path.exists(temp_path): os.unlink(temp_path)
def 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 _download(song: Song, api: Musicmanager, base_dir: str, thread_logger: logging.Logger = None) -> None: folder = os.path.join(base_dir, song.artist, song.album) file_path = os.path.join(folder, '%s - %s.mp3' % (song.track_number, song.title)) if not os.path.exists(file_path): if thread_logger: thread_logger.debug("Downloading song '%s'" % song.title) filename, audio = api.download_song(song.id) if not os.path.exists(folder): if thread_logger: thread_logger.debug("Creating folder '%s'" % folder) os.makedirs(folder) with open(file_path, 'wb') as file_handler: if thread_logger: thread_logger.debug("Writing file '%s'" % file_path) file_handler.write(audio)
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)
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)
def play_song_by_artist(song, artist): if Mobileclient.is_authenticated(gpm): mm = Musicmanager() mm.login('/home/pi/oauth.cred') if Musicmanager.is_authenticated(mm): song_dict = mm.get_purchased_songs() song_pattern = re.compile( r'(?:.)*\s?(' + re.escape(song) + r')\s?(?:.)*', re.IGNORECASE) artist_pattern = re.compile( r'(?:.)*\s?(' + re.escape(artist) + r')\s?(?:.)*', re.IGNORECASE) btn = OnButtonPress() btn.start() for song in song_dict: m = re.match(artist_pattern, song['artist']) print(m) if (re.match(song_pattern, song['title']) is not None and re.match(artist_pattern, song['artist']) is not None): print('Song found!') song_id = song['id'] (filename, audio) = mm.download_song(song_id) # get rid of non-ascii characters in file name filename = filename.encode('ascii', errors='ignore') # check if song is already downloaded # path will look something like: # /home/pi/Music/02 - Raindrop Prelude.mp3 # forces filename to be a string filename = filename.decode('ascii') path = song_location + filename try: if os.path.isfile(path): print('Song is already downloaded...') print(path) print('Playing song.') vlc_instance = vlc.Instance() p = vlc_instance.media_player_new() media = vlc_instance.media_new(path) p.set_media(media) events = p.event_manager() events.event_attach( vlc.EventType.MediaPlayerEndReached, SongFinished) p.play() p.audio_set_volume(58) while finish == 0: duration = p.get_time() / 1000 (m, s) = divmod(duration, 60) print('Current song is: ', path) print('Length:', '%02d:%02d' % (m, s)) time.sleep(5) p.stop() break else: with open(path, 'wb') as f: f.write(audio) print('Song has been added to: ' + path) print('Playing song.') vlc_instance = vlc.Instance() p = vlc_instance.media_player_new() media = vlc_instance.media_new(path) p.set_media(media) events = p.event_manager() events.event_attach( vlc.EventType.MediaPlayerEndReached, SongFinished) p.play() p.audio_set_volume(58) while finish == 0: duration = p.get_time() / 1000 m, s = divmod(duration, 60) print('Current song is: ', path) print('Length:', '%02d:%02d' % (m, s)) time.sleep(5) p.stop() break except (OSError, IOError): print('An error has occurred.') break else: print('Song not found yet.') else: print('Looks like you need to authenticate.') mm.perform_oauth('/home/pi/oauth.cred') print('Logging out.') Mobileclient.logout(gpm) mm.logout() else: print('Mobile client is not authenticated.') Mobileclient.logout(gpm)
else: artist = song_info["album_artist"] artist = trim_name(artist) # album name if song_info["album"] == "": album = "undefined" else: album = song_info["album"] album = trim_name(album) # gen folder os.makedirs("%s/%s/%s" % (music_root, artist, album), exist_ok=True) try: filename, audio_bytes = mm.download_song(el) base, ext = os.path.splitext(filename) filename = trim_name(base) + ext target = "%s/%s/%s/%s" % (music_root, artist, album, filename) print(" save %s" % target) with open(target, "wb") as f: f.write(audio_bytes) except KeyboardInterrupt: print("!!!!!KeyboardInterrupt!!!!!") with open(pickle_filename, "wb") as f: pickle.dump(downloaded_ids, f) sys.exit(-1) except: print(" ignore!") continue
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]) i += 1
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)
library[i]["title"] = library[i]["title"].replace(c, "") full_path = f'{library_path[i]}/{library[i]["title"]}' full_path.encode("utf-8") cont = False if not os.path.exists(full_path): for e in extensions: if os.path.exists(full_path + e): print(full_path + e + " already exists.") cont = True break if cont: continue filename, audio = mm.download_song(library[i]["id"]) r = library[i]["title"][library[i]["title"].rfind("."):] if r == -1 or r not in extensions: full_path += "." + fleep.get(audio).extension[0] else: print(full_path + " already exists.") continue print(f'[{i}]: {full_path}') try: with open(full_path, 'wb') as f: f.write(audio) except FileNotFoundError: print("PROBLEM WITH PATH: " + full_path)
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 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