コード例 #1
0
class Controller(object):
    # slavish adaptation of
    # http://stackoverflow.com/a/19655992/3380530
    def __init__(self, index=None, outdir=OUTDIR,
                 max_downloads=MAX_DOWNLOADS, max_priority=MAX_PRIORITY, max_watches=MAX_WATCHES,
                 live_rate=LIVE_RATE, schedule_ticks=SCHEDULE_TICKS, end_hour=END_HOUR, resume_hour=RESUME_HOUR,
                 new_index=True, index_loc=NEW_INDEX_LOC, logging=False, exit_behaviour='hard', noisy=False):
        self.session = WatchSession()

        if new_index:
            self.index = IndexerNew(index_loc)
        else:
            # TODO: convert this to IndexerOld
            self.index = index
        self.settings = {'outdir':         outdir,
                         'max_downloads':  max_downloads,
                         'max_watches':    max_watches,
                         'max_priority':   max_priority,
                         'live_rate':      live_rate,
                         'schedule_ticks':  schedule_ticks,
                         'logging':        logging,
                         'noisy':        noisy}
        
        self.end_time = datetime.time(hour=end_hour, minute=10, tzinfo=TOKYO_TZ)
        self.resume_time = datetime.time(hour=resume_hour-1, minute=50, tzinfo=TOKYO_TZ)

        self.live_rate = self.settings['live_rate']

        self.input_queue = InputQueue()

        self.scheduler = None
        self.watchers = None
        self.downloaders = None
        self.time = None

        if exit_behaviour == 'soft':
            self.soft_exit = True
        else:
            self.soft_exit = False

        self.quitting = False

        self._announcer = Announcer()

    def filter(self, names_filter):
        self.index.filter(names_filter)

    def run(self):
        # why are these defined here?
        self.scheduler = Scheduler(index=self.index, settings=self.settings)
        self.watchers = self.scheduler.watchmanager
        self.downloaders = self.watchers.downloads
        # self.downloaders
        # sleep_minutes = 20
        
        while True:
            self.time = datetime.datetime.now(tz=TOKYO_TZ)
            
            '''
            if self.resume_time > self.time.time() > self.end_time:
                sleep_seconds = (datetime.datetime.combine(self.time, self.resume_time)
                                 - self.time).total_seconds() + 1.0
                print('Time is {}, sleeping for {} seconds, until {}'.format(self.time.strftime('%H:%M'),
                                                                             sleep_seconds,
                                                                             self.resume_time.strftime('%H:%M')))
                self.scheduler.reset_ticks()
                time.sleep(sleep_seconds)
            
                
            else:'''
            self.scheduler.tick(self.time)  # Scheduler object
            self.watchers.tick(self.time)  # WatchManager object
            self.downloaders.tick(self.time)  # DownloadManager object

            while not self.input_queue.empty():
                try:
                    command = self.input_queue.get(block=False)
                except QueueEmpty:
                    break
                else:
                    try:
                        self.heed_command(command)
                    except ShowroomExitRequest:
                        return

            time.sleep(0.5)

    def quit(self):
        # TODO: Put the downloaders on a ThreadPool
        print("Exiting...")
        self.downloaders.quit()
        raise(ShowroomExitRequest)

    def heed_command(self, key):
        """Responds to (single) key presses:
        q/Q == Quit (asks for confirmation)
        s/S == Print full schedule (including current downloads)
        d/D == Print all current downloads
        l/L == Print all current downloads with rtmp and http links"""
        if self.quitting and key.lower() == 'y':
            self.quit()
        else:
            self.quitting = False

        if key.lower() == 'q':
            self.input_queue.clear()
            print('Are you sure you want to quit? (y/N)')
            if self.soft_exit:
                print('(Active downloads will continue until finished) ')
            else:
                print('(Active downloads will be stopped) ')
            self.quitting = True
        # TODO: encapsulate these more sanely so that other types of Announcer will work
        elif key.lower() == 's':
            self.input_queue.clear()
            self._announcer.send_message(('Current Schedule:',) + tuple(self.scheduler.list))
        elif key.lower() == 'd':
            self.input_queue.clear()
            self._announcer.send_message(('Current Downloads:',) + tuple(self.downloaders.list))
        elif key.lower() == 'l':
            self.input_queue.clear()
            self._announcer.send_message(('Current Downloads with Links:',) + tuple(self.downloaders.list_with_links))
コード例 #2
0
ファイル: showroom.py プロジェクト: lalomartins/showroom
class Downloader(object):
    def __init__(self, member, session, outdir, logging):
        self.session = session
        self._member = member
        self.process = None
        # self.failures = 0
        self.rootdir = outdir  # set by WatchManager
        self.destdir, self.tempdir, self.outfile = "", "", ""
        self._url = ""
        self._logging = logging
        self._announcer = Announcer()

    @property
    def name(self):
        return self._member['engName']

    @property
    def room_id(self):
        return self._member['showroom_id']

    @property
    def priority(self):
        return self._member['priority']

    @property
    def member(self):
        return self._member

    @property
    def logging(self):
        return self._logging

    @property
    def web_url(self):
        return self._member['web_url']

    def announce(self, msg):
        self._announcer.send_message(msg)

    def is_live(self):
        while True:
            try:
                status = self.session.get(
                    'https://www.showroom-live.com/room/is_live',
                    params={
                        "room_id": self.room_id
                    }).json()['ok']
            except JSONDecodeError:
                continue

            if status == 0:
                return False
            elif status == 1:
                return True

    def check(self):
        self.process.poll()
        if self.process.returncode == None:
            #_, err = self.process.communicate()
            #if b'already exists. Overwrite' in err:
            #    self.process.communicate(b'y\n')
            return False
        else:
            if self.outfile:
                self.move_to_dest()
            if self.is_live():
                time.sleep(2)  # give the stream some time to restart
                self.start()
                return False
            return True  # how to respond to failed exits?

    def kill(self):
        if not self.sent_quit:
            print('Quitting {}'.format(self.name))
            self.process.terminate()
            self.sent_quit = True
        else:
            self.process.kill()
            self.sent_quit = False

    def move_to_dest(self):
        srcpath = '{}/{}'.format(self.tempdir, self.outfile)
        destpath = '{}/{}'.format(self.destdir, self.outfile)
        if os.path.exists(destpath):
            # how? why? this should never happen
            raise FileExistsError
        else:
            try:
                os.replace(srcpath, destpath)
            except FileNotFoundError:
                # probably means srcpath not found, which means the download errored out
                # before creating a file. right now, do nothing
                # Most likely what's happening is the script is trying to access the stream
                # while it's down (but the site still reports it as live)
                # print('Download for {} failed'.format(self.name))
                pass
            else:
                print('Completed {}/{}'.format(self.destdir, self.outfile))
            self.destdir, self.tempdir, self.outfile = ("", "", "")

    def start(self):
        data = self.session.get(
            'https://www.showroom-live.com/room/get_live_data',
            params={
                'room_id': self.room_id
            }).json()
        stream_name = data['streaming_name_rtmp']
        stream_url = data["streaming_url_rtmp"]
        tokyo_time = datetime.datetime.now(tz=TOKYO_TZ)
        new_url = '{}/{}'.format(stream_url, stream_name)
        self.tempdir, self.destdir, self.outfile = format_name(
            self.rootdir, tokyo_time.strftime('%Y-%m-%d %H%M%S'), self.member)

        self.sent_quit = False

        if new_url != self.url:
            self._url = new_url
            print('Downloading {}\'s Showroom'.format(self.name, self.url))
            self.announce((self.web_url, self.url))

        if self.logging == True:
            log_file = os.path.normpath('{}/logs/{}.log'.format(
                self.destdir, self.outfile))
            ENV = {'FFREPORT': 'file={}:level=40'.format(log_file)}
        else:
            ENV = None

        normed_outpath = os.path.normpath('{}/{}'.format(
            self.tempdir, self.outfile))
        self.process = subprocess.Popen([
            'ffmpeg', '-loglevel', '16', '-copytb', '1', '-i', self.url, '-c',
            'copy', normed_outpath
        ],
                                        stdin=subprocess.PIPE,
                                        env=ENV)

    @property
    def url(self):
        return self._url