Exemple #1
0
async def lastfm(event):
    if event.fwd_from:
        return
    username = event.pattern_match.group(1)
    if Config.LAST_FM_API_KEY is None:
        await event.edit("`Setup LAST_FM_API_KEY first.`")
        return
    if username is None and Config.LAST_FM_USERNAME is None:
        await event.edit("`Setup LAST_FM_USERNAME or Provide username first.`")
        return
    if not username:
        username = Config.LAST_FM_USERNAME
    network = LastFMNetwork(api_key=Config.LAST_FM_API_KEY)
    user = network.get_user(username)
    current_track = user.get_now_playing()
    if current_track:
        try:
            track_cover = current_track.get_cover_image()
        except IndexError:
            track_cover = None
            pass
        msg = "**{}** is currently listening to:\n [🎧]({}) `{}`".format(
            user, track_cover, current_track)
    else:
        msg = "**{}** was listening to:\n".format(username)
        recent_tracks = user.get_recent_tracks(limit=3)
        for played_track in recent_tracks:
            msg += "🎧 `{}`\n".format(played_track.track)
    await event.delete()
    await borg.send_message(event.chat_id, msg, link_preview=True)
Exemple #2
0
def authenticate():
    """Authenticate to use LastFM API."""
    try:
        API_KEY = os.environ['LASTFM_API_KEY']
        API_SECRET = os.environ['LASTFM_API_SECRET']
        LASTFM_USERNAME = os.environ['LASTFM_USERNAME']
        LASTFM_PASSWORD_HASH = os.environ['LASTFM_PASSWORD_HASH']
        LASTFM_NETWORK = LastFMNetwork(api_key=API_KEY,
                                       api_secret=API_SECRET,
                                       username=LASTFM_USERNAME,
                                       password_hash=LASTFM_PASSWORD_HASH)
        user = LASTFM_NETWORK.get_user(LASTFM_USERNAME)
    except KeyError:
        print("Run setup.sh before trying this!")
        exit(1)
    return user
class LastFM:
    def __init__(self, username=''):
        self._username = username
        self._api = LastFMNetwork(api_key=get_last_fm_api_key())
        self._user = self._api.get_user(self._username)

    def try_download_cover(self, performer, title, path):
        title = self._api.get_album(performer, title)
        try:
            cover = title.get_cover_image()
        except WSError:
            return False
        cover_data = urlopen(cover).read()
        with open(path.joinpath('cover.png'), 'wb') as f:
            f.write(cover_data)
        return True

    def get_weekly_top_albums(self):
        return self._user.get_weekly_album_charts()

    def search_album(self, performer, title):
        suitable = []
        for album in self._api.search_for_album(title).get_next_page():
            if album.artist.name.lower() == performer.lower():
                suitable.append(album)
        if len(suitable) > 0:
            return max(*suitable, key=lambda a: len(a.get_tracks()))

    def get_recommended_albums(self, library, max=20) -> List[Album]:
        result = []
        top_albums = self.get_weekly_top_albums()
        existed_albums = {performer: set(alb.name.lower() for alb in albums) for performer, albums in library.library}
        for album, weight in top_albums:
            if len(result) >= max:
                break

            performer = album.artist.get_name().lower()
            title = album.get_name().lower()

            if title not in existed_albums.get(performer, set()):
                result.append(album)
        return result
Exemple #4
0
class LastFm:
    # You have to have your own unique two values for API_KEY and API_SECRET
    # Obtain yours from http://www.last.fm/api/account for Last.fm
    # API_KEY = '2b532992c84242d372f5c0044d6883e5'
    # API_SECRET = '3c6688ac84deda063a697f5662a93eb0'
    API_KEY = '8fc05a68240dadf4c2430392768053fe'
    API_SECRET = 'bc2d48b14f3e864c6a07bbb6f9a0b690'
    URL_AUTH = 'http://www.last.fm/api/auth/?api_key={}'.format(API_KEY)
    URL_CALLBACK = 'http%3A%2F%2F127.0.0.1%3A5656%2Flastfm%2Fcallback'

    network = None
    LOVE_CUTOFF = 0.97

    def __init__(self, token=''):
        """Always create network"""
        with shelve.open('lastfm') as db:
            session_key = db.get('session_key')

            self.network = LastFMNetwork(
                api_key=self.API_KEY,
                api_secret=self.API_SECRET,
                session_key=session_key,
                token=token
            )

            if token:
                app.logger.info('saving session key: {}'.format(self.network.session_key))
                db['session_key'] = self.network.session_key

    def scrobble(self, history):
        """Scrobble song to lastfm"""
        params = {
            'artist': history.song.artist.name,
            'album': history.song.album.name,
            'title': history.song.name,
            'track_number': history.song.track_number,
            'timestamp': int(history.played_at.timestamp()),
        }
        app.logger.info('scrobbling: {}'.format(params))
        self.network.scrobble(**params)

    def show_some_love(self, songs):
        """Sets track to love or not"""
        app.logger.info('showing some love for {} songs'.format(len(songs)))
        for song in songs:
            db.session.refresh(song)
            network_track = self.network.get_track(song.artist.name, song.name)
            is_loved = song.rating >= self.LOVE_CUTOFF
            app.logger.debug('[{:.0f}%] {} loving {}'.format(
                song.rating * 100, is_loved, network_track))
            if is_loved:
                network_track.love()
            else:
                network_track.unlove()
            # is_loved = network_track.get_userloved()
            # app.logger.debug('found network track {} loved {}'.format(network_track, is_loved))
            # if is_loved:
            #     if song.rating < self.LOVE_CUTOFF:
            #         app.logger.info('lost love {} [{:.0f}%]'.format(network_track, song.rating *
            #                                                        100))
            #         res = network_track.unlove()
            #         app.logger.debug(res)
            #     else:
            #         app.logger.info('still loving {} [{:.0f}%]'.format(network_track, song.rating *
            #                                                          100))
            # else:
            #     res = network_track.unlove()
            #     app.logger.debug(res)
            #     if song.rating >= self.LOVE_CUTOFF:
            #         app.logger.info('new love {} [{:.0f}%]'.format(network_track, song.rating *
            #                                                        100))
            #         res = network_track.love()
            #         app.logger.debug(res)
            #     else:
            #         app.logger.info('still no love for {} [{:.0f}%]'.format(network_track,
            #                                                              song.rating * 100))

    def get_user_top_albums(self, user_name, period=None):
        """Get top albums for user"""
        period = period or PERIOD_12MONTHS
        user = self.network.get_user(user_name)
        return user.get_top_albums(period)

    def get_user_playcount(self, user):
        """Get playcount of user"""

    def get_similar_tracks(self, artist, title):
        """Get similar tracks to this song"""
        track = self.network.get_track(artist, title)
        similar = track.get_similar()
        app.logger.info('Found {} similar tracks for {} {}'.format(len(similar), artist, title))
        return similar
Exemple #5
0
class NowplayingBot(PineappleBot):
    def init(self):
        self.last_posted_track = None

    def start(self):
        for k in [
                'lastfm_api_key', 'lastfm_api_secret', 'lastfm_username',
                'lastfm_password_hash', 'youtube_key', 'use_last_played'
        ]:
            if k not in self.config:
                raise ConfigurationError(f"NowplayingBot requires a '{k}'")

        self.lastfm = LastFMNetwork(
            api_key=self.config.lastfm_api_key,
            api_secret=self.config.lastfm_api_secret,
            username=self.config.lastfm_username,
            password_hash=self.config.lastfm_password_hash)

        self.post_np()

    @interval(30)
    def post_np(self):
        # grab the track from the last.fm api
        if self.config.use_last_played == 'yes':
            currently_playing = self.lastfm.get_user(
                self.config.lastfm_username).get_recent_tracks(1)[0][0]
        else:
            currently_playing = self.lastfm.get_user(
                self.config.lastfm_username).get_now_playing()

        # don't try to post if nothing is being played
        if currently_playing is None:
            return

        # don't repost if we've already posted about this track
        if currently_playing.__hash__() == self.last_posted_track:
            return
        else:
            self.last_posted_track = currently_playing.__hash__()

        # make a best-effort guess at the youtube link for this track
        yt_search = search_youtube(str(currently_playing),
                                   key=self.config.youtube_key)
        if len(yt_search) > 0:
            yt_link = f"https://www.youtube.com/watch?v={yt_search[0]['id']}"
        else:
            yt_link = '🎇 no youtube link, sorry 🎇'

        # template the post
        post_template = '''\
#np #nowplaying #fediplay {artist} - {track}

{yt_link}'''

        post = post_template.format(
            artist=currently_playing.get_artist().get_name(
                properly_capitalized=True),
            track=currently_playing.get_title(),
            yt_link=yt_link)

        # do the thing
        self.mastodon.status_post(post, visibility='unlisted')
Exemple #6
0
class LastFm:
    # You have to have your own unique two values for API_KEY and API_SECRET
    # Obtain yours from http://www.last.fm/api/account for Last.fm
    # API_KEY = '2b532992c84242d372f5c0044d6883e5'
    # API_SECRET = '3c6688ac84deda063a697f5662a93eb0'
    API_KEY = '8fc05a68240dadf4c2430392768053fe'
    API_SECRET = 'bc2d48b14f3e864c6a07bbb6f9a0b690'
    URL_AUTH = 'http://www.last.fm/api/auth/?api_key={}'.format(API_KEY)
    URL_CALLBACK = 'http%3A%2F%2F127.0.0.1%3A5656%2Flastfm%2Fcallback'

    network = None
    LOVE_CUTOFF = 0.97

    def __init__(self, token=''):
        """Always create network"""
        with shelve.open('lastfm') as db:
            session_key = db.get('session_key')

            self.network = LastFMNetwork(api_key=self.API_KEY,
                                         api_secret=self.API_SECRET,
                                         session_key=session_key,
                                         token=token)

            if token:
                app.logger.info('saving session key: {}'.format(
                    self.network.session_key))
                db['session_key'] = self.network.session_key

    def scrobble(self, history):
        """Scrobble song to lastfm"""
        params = {
            'artist': history.song.artist.name,
            'album': history.song.album.name,
            'title': history.song.name,
            'track_number': history.song.track_number,
            'timestamp': int(history.played_at.timestamp()),
        }
        app.logger.info('scrobbling: {}'.format(params))
        self.network.scrobble(**params)

    def show_some_love(self, songs):
        """Sets track to love or not"""
        app.logger.info('showing some love for {} songs'.format(len(songs)))
        for song in songs:
            db.session.refresh(song)
            network_track = self.network.get_track(song.artist.name, song.name)
            is_loved = song.rating >= self.LOVE_CUTOFF
            app.logger.debug('[{:.0f}%] {} loving {}'.format(
                song.rating * 100, is_loved, network_track))
            if is_loved:
                network_track.love()
            else:
                network_track.unlove()
            # is_loved = network_track.get_userloved()
            # app.logger.debug('found network track {} loved {}'.format(network_track, is_loved))
            # if is_loved:
            #     if song.rating < self.LOVE_CUTOFF:
            #         app.logger.info('lost love {} [{:.0f}%]'.format(network_track, song.rating *
            #                                                        100))
            #         res = network_track.unlove()
            #         app.logger.debug(res)
            #     else:
            #         app.logger.info('still loving {} [{:.0f}%]'.format(network_track, song.rating *
            #                                                          100))
            # else:
            #     res = network_track.unlove()
            #     app.logger.debug(res)
            #     if song.rating >= self.LOVE_CUTOFF:
            #         app.logger.info('new love {} [{:.0f}%]'.format(network_track, song.rating *
            #                                                        100))
            #         res = network_track.love()
            #         app.logger.debug(res)
            #     else:
            #         app.logger.info('still no love for {} [{:.0f}%]'.format(network_track,
            #                                                              song.rating * 100))

    def get_user_top_albums(self, user_name, period=None):
        """Get top albums for user"""
        period = period or PERIOD_12MONTHS
        user = self.network.get_user(user_name)
        return user.get_top_albums(period)

    def get_user_playcount(self, user):
        """Get playcount of user"""

    def get_similar_tracks(self, artist, title):
        """Get similar tracks to this song"""
        track = self.network.get_track(artist, title)
        similar = track.get_similar()
        app.logger.info('Found {} similar tracks for {} {}'.format(
            len(similar), artist, title))
        return similar