Beispiel #1
0
class Phoebe(Thread):
    def __init__(self, config_dir, logger=Null()):

        self.logger = logger
        self.log = self.logger.getLogger('phoebe.Phoebe')
        self.log.debug('Phoebe Thread initialized')
        self.log.debug('config_dir: %s' % config_dir)

        Thread.__init__(self)

        self.idx = 0
        self.playlist = []
        self.playing = False
        self.buffering = False

        if not path.isdir(config_dir):
            mkdir(config_dir)

        self.config_dir = config_dir

        self.log.debug('Loading history file')
        self.history = LocalStorage(path.join(config_dir, 'history.json'),
                                    logger=self.logger)

        self.log.debug('Loading settings file')
        self.settings = LocalStorage(path.join(config_dir, 'settings.json'),
                                     logger=self.logger)

        self.reddit = Reddit(logger=self.logger)
        if ('reddit_username' in self.settings.keys()) \
          and ('reddit_password' in self.settings.keys()):
            self.reddit.login(self.settings['reddit_username'],
                              self.settings['reddit_password'])

        if 'download_dir' not in self.settings.keys():
            self.settings['download_dir'] = path.join(path.expanduser('~'),
                                                      'Downloads', 'phoebe')

        if not path.isdir(self.settings['download_dir']):
            mkdir(self.settings['download_dir'])

        self.mpq = Queue()
        # TODO: vlc backend support. There should also be an auto-detected fallback
        if 'backend' not in self.settings.keys():
            self.settings['backend'] = 'mplayer'
        if self.settings['backend'] == 'mplayer':
            self.mp = MPlayerThread(queue=self.mpq, logger=self.logger)
        self.mp.daemon = True
        self.mp.start()

        self.playtime = 0

        self.dlq = Queue()
        self.dl = DLThread(self.dlq, logger=self.logger)
        self.dl.daemon = True
        self.dl.start()

    @property
    def has_next(self):
        return len(self.playlist) > self.idx + 1

    def run(self):
        self.log.debug('Running Phoebe thread')
        while True:
            sleep(1)
            if self.playing and self.has_next and (
                    self.mp.properties['time_left']
                    == 1) and not self.buffering:
                self.log.debug('End of file. Sleep 1')
                sleep(1)
                self.next()
            elif self.playing and not self.has_next and not (
                    self.mp_properties['filename'] or self.buffering):
                self.log.debug('End of playlist')
                self.playing = False

    def shuffle(self):
        self.log.debug('Shuffling playlist')
        current_id = self.playlist[self.idx]['id']
        random.shuffle(self.playlist)

        idx = 0
        for item in self.playlist:
            if item['id'] == current_id:
                self.idx = item
                break
            idx += 1
        self.idx = idx

    def download(self, idx):
        f_path = path.join(self.settings['download_dir'],
                           self.playlist[idx]['id'])
        if path.isfile(f_path):
            self.log.debug('Playlist item exists. Skipping download: %s' % idx)
        else:
            self.log.debug('Putting playlist item in download queue: %s' % idx)
            self.dlq.put({
                'id': self.playlist[idx]['id'],
                'url': self.playlist[idx]['url'].replace('&', '&'),
                'download_dir': self.settings['download_dir']
            })

    def play(self, idx):
        self.log.debug('Playing playlist item: %s' % idx)
        self.log.debug('Stopping first, before playing: %s' % idx)
        self.stop()

        self.playing = True
        # TODO: handle IndexError
        f_path = path.join(self.settings['download_dir'],
                           self.playlist[idx]['id'])
        if path.isfile(f_path):
            self.log.debug('File exists. Loading file to mplayer process: %s' %
                           idx)
            self.idx = idx
            self.buffering = False
            self.playtime = time()
            self.mpq.put('loadfile %s' % f_path)
            self.mpq.put('get_property filename')
            if self.playlist[idx]['id'] in self.history.keys():
                voted = self.history[self.playlist[idx]['id']]['voted']
            else:
                voted = 0
            self.history[self.playlist[idx]['id']] = {
                'playtime': self.playtime,
                'voted': voted,
                'subreddit': self.playlist[idx]['subreddit'],
            }
            self.download(idx + 1)
        else:
            self.log.debug(
                'File does not exist. Need to buffer/download first: %s' % idx)
            if self.playlist[idx]['id'] in self.dl.downloads.keys():
                status = self.dl.downloads[self.playlist[idx]['id']]
                if (status['process'].poll()
                        is not None) and (status['status'] is not 'complete'):
                    self.log.info(
                        'Previous download attempt failed. Skipping: %s' % idx)
                    self.log.info('Error from download process: %s' %
                                  status['error'])
                    self.playlist[idx]['filter'] = 'download_failed'
                    self.next()
                    return None
            print("Buffering...")
            self.buffering = True
            self.download(idx)
            while True:
                sleep(1)
                dlid = self.playlist[idx]['id']
                status = self.dl.downloads[dlid]
                if status['status'] == 'downloading': print(status['percent'])
                if (status['status'] == 'complete') or (status['status']
                                                        == 'idle'):
                    break
                if (status['process'].poll()
                        is not None) and (status['status'] is not 'complete'):
                    self.log.info('Download attempt failed. Skipping: %s' %
                                  idx)
                    self.log.info('Error from download process: %s' %
                                  status['error'])
                    self.playlist[idx]['filter'] = 'download_failed'
                    self.next()
                    return None
            self.log.debug(
                'Download finished. Running play function again: %s' % idx)
            self.play(idx)

    def next(self):
        self.log.debug('Next')
        if self.has_next:
            for idx in range(self.idx + 1, len(self.playlist)):
                self.idx = idx
                if not 'filter' in self.playlist[idx].keys():
                    self.play(idx)
                    break
                else:
                    reason = self.playlist[idx]['filter']
                    self.log.debug(
                        'Skipping playlist item %s due to filter: %s' %
                        (idx, reason))

    def previous(self):
        if time() - self.playtime > 10:
            self.log.debug('Seeking back to back to beginning')
            self.mpq.put('seek 0 2')
            self.playtime = time()
        elif self.idx != 0:
            self.log.debug('Previous')
            self.play(self.idx - 1)

    def pause(self):
        self.log.debug('Pause')
        self.mpq.put('pause')

    def stop(self):
        self.log.debug('Stop')
        self.mpq.put('stop')
        self.playing = False

    def upvote(self):
        if self.playlist[self.idx]['id'] in self.history.keys():
            self.log.debug('upvoting')
            hist = self.history[self.playlist[self.idx]['id']]
            hist['voted'] = 1
            self.history[self.playlist[self.idx]['id']] = hist
        if self.reddit.logged_in:
            self.reddit.upvote(self.playlist[self.idx]['id'])

    def downvote(self):
        if self.playlist[self.idx]['id'] in self.history.keys():
            self.log.debug('downvoting')
            hist = self.history[self.playlist[self.idx]['id']]
            hist['voted'] = -1
            self.history[self.playlist[self.idx]['id']] = hist
        if self.reddit.logged_in:
            self.reddit.downvote(self.playlist[self.idx]['id'])
        self.next()