示例#1
0
class NowPlaying(Plugin):

    edit_toggle = False
    SONG_THRESHOLD = 1
    snipr_cache = SniprSongLRU(20)
    inited = False

    def setup(self):
        self.links = []
        self.timer = RepeatTimer(5, lambda: wx.CallAfter(self.on_timer))
        self.song = (None, 0)
        self.status = None
        self.on_before_status_change(profile.status)

    def link(self):
        self.links.append(profile.prefs.link('plugins.nowplaying.format', self.format_string_change, callnow=False))
        self.links.append(profile.prefs.link('plugins.nowplaying.backup_format', self.format_string_change, callnow=False))

    def unlink(self):
        while self.links:
            link = self.links.pop(0)
            link.unlink()

    def format_string_change(self, value):
        log.info('Format string changed to %r', value)
        self.check_song(force=True)

    def on_before_status_change(self, status):
        '''
        Invoked when the profile's status message changes.
        '''
        log.info('on_status_change')

        is_music_status = isinstance(status, NowPlayingStatus)
        timer           = getattr(self, 'timer', None)
        timer_alive     = timer is not None and self.timer.isAlive()

        # If the status is a "music status" and our timer isn't running, start it.
        if is_music_status and not timer_alive:
            self.link()
            log.debug('starting now playing timer')
            if timer is None:
                self.timer = timer = RepeatTimer(5, lambda: wx.CallAfter(self.on_timer))
            timer.start()
            # call it now to look responsive! yay
        # Otherwise if the status is not a "music status" and the timer IS running, stop it.
        elif not is_music_status and timer_alive:
            log.debug('stopping now playing timer')
            self.song = (None, 0)
            self.unlink()
            self.timer.stop()
            releaseAll()
        if is_music_status:
            s = status.status
            if pref(NOWPLAYING_STATUS_PREF, type = str, default = 'available') != s:
                profile.prefs.__setitem__(NOWPLAYING_STATUS_PREF, s.lower())

        if not is_music_status:
            return status

        try:
            if status is not self.status:
                self.check_song(force=True, status=status)
            return self.status
        except Exception:
            traceback.print_exc()
            return status

    def on_timer(self):
        'Invoked when the song check timer goes off. Which happens a lot.'
        status = profile.status
        if not isinstance(status, NowPlayingStatus):
            # early exit for when the status message is not a music status
            if hasattr(self, 'timer'):
                self.timer.stop()
            return

        self.check_song()
        try:
            new_message = self.status.message
        except Exception:
            traceback.print_exc()
            return

        if new_message != profile.status.message:
            log.info('current message: %r', profile.status.message)
            log.info('setting new now playing status: message=%r, cursong=%r', new_message, profile.status.message)
            profile.set_status(self.status)

    def check_song(self, force=False, status=None):
        cursong = currentSong()
        song = cursong.format_string % cursong.format_args
        new_message = ' '.join([NOTES_SYMBOL, song])

        oldsong, songcount = self.song

        def got_new_song():
            # on a new song, store the name, and the "count" of times we've
            # seen it
            self.snipr_cache[amazon_format(cursong.format_args)]
            self.song = (cursong, 0)

        def set_new_song(status = status):
            if status is None:
                status = profile.status
            self.status = status.copy(message = new_message, **cursong)

        if oldsong is None:
            got_new_song()
            set_new_song()

        elif cursong != oldsong:
            got_new_song()
            if force:
                set_new_song()
        else:
            # only set the profile status after a certain period of time passed
            # with the same song present
            songcount += 1
            self.song = (cursong, songcount)

            # only set the song after (N * five) seconds of play time
            if force or (songcount >= self.SONG_THRESHOLD):
                set_new_song()