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)
Beispiel #2
0
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")
Beispiel #5
0
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
Beispiel #6
0
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])
Beispiel #7
0
                        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)
Beispiel #8
0
    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 )
Beispiel #9
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
Beispiel #10
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)
Beispiel #11
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
Beispiel #12
0
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)
Beispiel #13
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
Beispiel #14
0
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)
Beispiel #15
0
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)
Beispiel #17
0
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()]