Ejemplo n.º 1
0
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)
Ejemplo n.º 2
0
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)
Ejemplo n.º 3
0
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)
Ejemplo n.º 4
0
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)
Ejemplo n.º 6
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)
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)

Ejemplo n.º 8
0
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)
Ejemplo n.º 9
0
        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
Ejemplo n.º 10
0
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
Ejemplo n.º 11
0
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
Ejemplo n.º 12
0
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)
Ejemplo n.º 13
0
        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)
Ejemplo n.º 14
0
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
Ejemplo n.º 15
0
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