def __init__(self, main_url, download_url, dlhash, config, multihandler,
              fileinfo, resumedata, vodeventcallback, set_error_func,
              finished_func, failed_func):
     self.main_url = main_url
     self.download_url = download_url
     self.dlhash = dlhash
     self.config = config
     self.dlmode = config['mode']
     self.fileinfo = fileinfo
     self.vodeventcallback = vodeventcallback
     self.set_error_func = set_error_func
     self.finished_func = finished_func
     self.failed_func = failed_func
     self.download_id = binascii.hexlify(self.dlhash) + '-' + str(
         long(time.time())) + '-' + str(random.randint(0, 100000))
     self.dldoneflag = Event()
     self.rawserver = multihandler.newRawServer(dlhash, self.dldoneflag)
     if download_url is not None:
         url = download_url
     else:
         url = main_url
     self.downloader = Downloader(url, dlhash, self.rawserver, self.failed)
     self.voddownload = None
     self.storage = None
     self.log_prefix = 'dd::' + binascii.hexlify(self.dlhash) + ':'
     predownload = self.config.get('predownload', False)
     if DEBUG:
         log(self.log_prefix + '__init__: predownload', predownload)
     if resumedata is None and predownload:
         self.downloader.predownload(self.init_predownloaded)
     else:
         callback = lambda content_length, mimetype: self.init(
             resumedata, content_length, mimetype)
         self.downloader.init(callback)
Exemple #2
0
 def __init__(self, main_url, download_url, dlhash, config, multihandler,
              fileinfo, resumedata, vodeventcallback, set_error_func,
              finished_func, failed_func):
     self.main_url = main_url
     self.download_url = download_url
     self.dlhash = dlhash
     self.config = config
     self.dlmode = config['mode']
     self.fileinfo = fileinfo
     self.vodeventcallback = vodeventcallback
     self.set_error_func = set_error_func
     self.finished_func = finished_func
     self.failed_func = failed_func
     self.download_id = binascii.hexlify(self.dlhash) + '-' + str(
         long(time.time())) + '-' + str(random.randint(0, 100000))
     self.dldoneflag = Event()
     self.rawserver = multihandler.newRawServer(dlhash, self.dldoneflag)
     if download_url is not None:
         url = download_url
     else:
         url = main_url
     self.downloader = Downloader(url, dlhash, self.rawserver, self.failed)
     self.voddownload = None
     self.storage = None
     self.log_prefix = 'dd::' + binascii.hexlify(self.dlhash) + ':'
     predownload = self.config.get('predownload', False)
     if DEBUG:
         log(self.log_prefix + '__init__: predownload', predownload)
     if resumedata is None and predownload:
         self.downloader.predownload(self.init_predownloaded)
     else:
         callback = lambda content_length, mimetype: self.init(resumedata, content_length, mimetype)
         self.downloader.init(callback)
Exemple #3
0
class DirectDownload:
    def __init__(self, main_url, download_url, dlhash, config, multihandler,
                 fileinfo, resumedata, vodeventcallback, set_error_func,
                 finished_func, failed_func):
        self.main_url = main_url
        self.download_url = download_url
        self.dlhash = dlhash
        self.config = config
        self.dlmode = config['mode']
        self.fileinfo = fileinfo
        self.vodeventcallback = vodeventcallback
        self.set_error_func = set_error_func
        self.finished_func = finished_func
        self.failed_func = failed_func
        self.download_id = binascii.hexlify(self.dlhash) + '-' + str(
            long(time.time())) + '-' + str(random.randint(0, 100000))
        self.dldoneflag = Event()
        self.rawserver = multihandler.newRawServer(dlhash, self.dldoneflag)
        if download_url is not None:
            url = download_url
        else:
            url = main_url
        self.downloader = Downloader(url, dlhash, self.rawserver, self.failed)
        self.voddownload = None
        self.storage = None
        self.log_prefix = 'dd::' + binascii.hexlify(self.dlhash) + ':'
        predownload = self.config.get('predownload', False)
        if DEBUG:
            log(self.log_prefix + '__init__: predownload', predownload)
        if resumedata is None and predownload:
            self.downloader.predownload(self.init_predownloaded)
        else:
            callback = lambda content_length, mimetype: self.init(resumedata, content_length, mimetype)
            self.downloader.init(callback)

    def init_predownloaded(self, mimetype, filedata):
        if DEBUG:
            log(self.log_prefix + 'init_predownloaded: mimetype', mimetype,
                'len', len(filedata))
        if self.dldoneflag.is_set():
            if DEBUG:
                log(self.log_prefix +
                    'init_predownloaded: done flag is set, exit')
            return
        ext = self.guess_extension_from_mimetype(mimetype)
        filename = binascii.hexlify(self.dlhash)
        if len(ext):
            filename += '.' + ext
        content_length = len(filedata)
        self.fileinfo['filename'] = filename
        self.fileinfo['size'] = content_length
        self.fileinfo['mimetype'] = mimetype
        temp_dir = os.path.join(self.config['buffer_dir'],
                                binascii.hexlify(self.dlhash))
        if not os.path.isdir(temp_dir):
            os.mkdir(temp_dir)
        self.storage = Storage(
            self.dlhash,
            self.config,
            self.fileinfo,
            temp_dir,
            None,
            self.finished_callback,
            filedata=filedata)
        self.downloader.set_storage(self.storage)
        self.finished_callback()
        if self.dlmode == DLMODE_VOD:
            if DEBUG:
                log(
                    self.log_prefix +
                    'init_predownloaded: starting in vod mode, but download is finished: fileinfo',
                    self.fileinfo)
            self.vodeventcallback(
                self.fileinfo, VODEVENT_START, {
                    'complete': True,
                    'filename': self.storage.get_dest_path(),
                    'mimetype': self.fileinfo['mimetype'],
                    'stream': None,
                    'length': self.storage.get_content_length(),
                    'bitrate': self.fileinfo['bitrate']
                })

    def init(self, resumedata=None, content_length=None, mimetype=None):
        if DEBUG:
            log(self.log_prefix + 'init: resumedata', resumedata,
                'content_length', content_length, 'mimetype', mimetype)
        if self.dldoneflag.is_set():
            if DEBUG:
                log(self.log_prefix + 'init: done flag is set, exit')
            return
        if content_length is None:
            content_length, mimetype = self.downloader.init()
        if resumedata is not None:
            if content_length != resumedata['size']:
                raise Exception('content length differs from resumedata')
            if mimetype != resumedata['mimetype']:
                raise Exception('mime type differs from resumedata')
            filename = resumedata['filename']
            duration = resumedata.get('duration', None)
            if duration:
                bitrate = content_length / duration
                self.fileinfo['duration'] = duration
                self.fileinfo['bitrate'] = bitrate
                if DEBUG:
                    log(
                        self.log_prefix +
                        '__init__: got duration from resumedata: main_url',
                        self.main_url, 'duration', duration, 'bitrate',
                        bitrate)
        else:
            ext = self.guess_extension_from_mimetype(mimetype)
            filename = binascii.hexlify(self.dlhash)
            if len(ext):
                filename += '.' + ext
        self.fileinfo['filename'] = filename
        self.fileinfo['size'] = content_length
        self.fileinfo['mimetype'] = mimetype
        temp_dir = os.path.join(self.config['buffer_dir'],
                                binascii.hexlify(self.dlhash))
        if not os.path.isdir(temp_dir):
            os.mkdir(temp_dir)
        self.storage = Storage(self.dlhash, self.config, self.fileinfo,
                               temp_dir, resumedata, self.finished_callback)
        self.downloader.set_storage(self.storage)
        completed = self.storage.is_finished()
        if completed:
            self.finished_callback()
        if self.dlmode == DLMODE_VOD:
            if completed:
                if DEBUG:
                    log(
                        self.log_prefix +
                        '__init__: starting in vod mode, but download is finished: fileinfo',
                        self.fileinfo)
                self.vodeventcallback(
                    self.fileinfo, VODEVENT_START, {
                        'complete': True,
                        'filename': self.storage.get_dest_path(),
                        'mimetype': self.fileinfo['mimetype'],
                        'stream': None,
                        'length': self.storage.get_content_length(),
                        'bitrate': self.fileinfo['bitrate']
                    })
            else:
                if DEBUG:
                    log(
                        self.log_prefix +
                        '__init__: starting in vod mode: fileinfo',
                        self.fileinfo)
                self.voddownload = VODTransporter(
                    self, self.dlhash, self.fileinfo, self.vodeventcallback)
                self.storage.add_got_data_observer(
                    self.voddownload.got_data_observer)
        if not completed:
            self.downloader.start()

    def get_download_id(self):
        return self.download_id

    def guess_extension_from_mimetype(self, mimetype):
        if mimetype is None:
            mimetype = ''
        if mimetype == 'video/x-msvideo':
            ext = 'avi'
        elif mimetype == 'video/mp4':
            ext = 'mp4'
        elif mimetype == 'video/x-matroska':
            ext = 'mkv'
        elif mimetype == 'video/x-m4v':
            ext = 'm4v'
        elif mimetype == 'video/quicktime':
            ext = 'mov'
        elif mimetype == 'video/x-sgi-movie':
            ext = 'movie'
        elif mimetype == 'video/mpeg':
            ext = 'mpg'
        elif mimetype == 'application/ogg' or mimetype == 'video/ogg':
            ext = 'ogg'
        elif mimetype == 'video/x-flv':
            ext = 'flv'
        elif mimetype == 'video/webm':
            ext = 'webm'
        elif mimetype == 'video/x-ms-wmv':
            ext = 'wmv'
        else:
            if DEBUG:
                log(
                    self.log_prefix +
                    'guess_extension_from_mimetype: unknown mimetype',
                    mimetype)
            ext = 'mpg'
        if DEBUG:
            log(self.log_prefix + 'guess_extension_from_mimetype: mimetype',
                mimetype, 'ext', ext)
        return ext

    def finished_callback(self):
        if DEBUG:
            log(self.log_prefix + 'finished_callback: url', self.main_url)

        def _finished():
            if self.voddownload is not None:
                self.voddownload.complete()
            if self.finished_func is not None:
                self.finished_func(self.main_url, self.download_url,
                                   self.dlhash, self.fileinfo)

        self.rawserver.add_task(_finished, 0.0)

    def failed(self, err):
        if DEBUG:
            log(self.log_prefix + 'failed: url', self.main_url, 'err', err)
        if self.voddownload is not None:
            self.voddownload.shutdown()
            self.voddownload = None
        self.set_error_func(err)

        def _failed():
            if self.failed_func is not None:
                try:
                    self.failed_func(err)
                except:
                    if DEBUG:
                        print_exc()

        self.rawserver.add_task(_failed, 0.0)

    def got_duration(self, duration, from_player=True):
        if DEBUG:
            log(self.log_prefix + 'got_duration: main_url', self.main_url,
                'duration', duration, 'fileinfo', self.fileinfo)
        if duration <= 0:
            if DEBUG:
                log(self.log_prefix + 'got_duration: bad duration')
            return
        cur_duration = self.fileinfo.get('duration', None)
        if cur_duration is not None:
            if cur_duration != duration:
                if DEBUG:
                    log(
                        self.log_prefix +
                        'got_duration: duration does not match with metadata: main_url',
                        self.main_url, 'cur_duration', cur_duration,
                        'duration', duration)
        else:
            bitrate = self.fileinfo['size'] / duration
            self.fileinfo['duration'] = duration
            self.fileinfo['bitrate'] = bitrate
            if self.voddownload is not None:
                self.voddownload.set_bitrate(bitrate)

    def get_stats(self):
        status = None
        stats = {}
        s = Statistics_Response()
        s.numSeeds = 0
        s.numPeers = 0
        s.httpSeeds = 0
        s.upTotal = 0
        s.downTotal = self.downloader.measure.get_total()
        s.httpDownTotal = s.downTotal
        stats['stats'] = s
        stats['up'] = 0
        if self.storage is None:
            stats['frac'] = 0
            finished = False
        else:
            stats['frac'] = self.storage.get_progress()
            finished = self.storage.is_finished()
        if finished:
            stats['vod_prebuf_frac'] = 1.0
            stats['vod_playable'] = True
            stats['vod_playable_after'] = 0.0
            stats['vod'] = False
            stats['down'] = 0
            stats['httpdown'] = 0
        else:
            s.numSeeds = 1
            s.httpSeeds = 1
            stats['down'] = self.downloader.measure.get_rate()
            stats['httpdown'] = stats['down']
            if self.voddownload is not None:
                stats[
                    'vod_prebuf_frac'] = self.voddownload.get_prebuffering_progress(
                    )
                stats['vod_playable'] = self.voddownload.is_playable()
                stats[
                    'vod_playable_after'] = self.voddownload.get_playable_after(
                    )
                stats['vod'] = True
            else:
                stats['vod_prebuf_frac'] = 0.0
                stats['vod_playable'] = False
                stats['vod_playable_after'] = float(2147483648L)
                stats['vod'] = False
        return (status, stats)

    def shutdown(self):
        if self.voddownload is not None:
            self.voddownload.shutdown()
            self.voddownload = None
        self.downloader.shutdown()
        if self.storage is not None:
            self.storage.close()
            self.storage = None
        self.dldoneflag.set()
        self.rawserver.shutdown()
        return self.checkpoint()

    def restart(self, dlmode, vodeventfunc, finished_func, failed_func):
        self.dlmode = dlmode
        self.fileinfo['usercallback'] = vodeventfunc
        self.finished_func = finished_func
        self.failed_func = failed_func
        if self.storage is None:
            try:
                self.init()
            except Exception as e:
                if DEBUG:
                    print_exc()
                self.failed(e)
                return

        if dlmode == DLMODE_VOD:
            if self.storage.is_finished():
                if DEBUG:
                    log(
                        self.log_prefix +
                        'restart: restart in vod mode requested, but download is finished: fileinfo',
                        self.fileinfo)
                self.vodeventcallback(
                    self.fileinfo, VODEVENT_START, {
                        'complete': True,
                        'filename': self.storage.get_dest_path(),
                        'mimetype': self.fileinfo['mimetype'],
                        'stream': None,
                        'length': self.storage.get_content_length(),
                        'bitrate': self.fileinfo['bitrate']
                    })
            else:
                if self.voddownload is not None:
                    self.storage.remove_got_data_observer(
                        self.voddownload.got_data_observer)
                    self.voddownload.shutdown()
                    self.voddownload = None
                    if DEBUG:
                        log(self.log_prefix +
                            'restart: voddownload is not None, stop current download'
                            )
                self.voddownload = VODTransporter(
                    self, self.dlhash, self.fileinfo, self.vodeventcallback)
                self.storage.add_got_data_observer(
                    self.voddownload.got_data_observer)
                if not self.downloader.is_running():
                    if DEBUG:
                        log(self.log_prefix +
                            'restart: downloader is not running, start it')
                    self.downloader.start()

    def checkpoint(self):
        if self.storage is None:
            return
        resumedata = self.storage.checkpoint()
        resumedata['mimetype'] = self.fileinfo['mimetype']
        resumedata['filename'] = self.fileinfo['filename']
        resumedata['duration'] = self.fileinfo['duration']
        return resumedata

    def get_dest_path(self):
        if self.storage is None:
            return
        return self.storage.get_dest_path()

    def get_content_length(self):
        if self.storage is None:
            return
        return self.storage.get_content_length()

    def set_wait_sufficient_speed(self, value):
        if self.voddownload is not None:
            self.voddownload.set_wait_sufficient_speed(value)

    def set_player_buffer_time(self, value):
        if self.voddownload is not None:
            self.voddownload.set_player_buffer_time(value)

    def set_live_buffer_time(self, value):
        if self.voddownload is not None:
            self.voddownload.set_live_buffer_time(value)
class DirectDownload:
    def __init__(self, main_url, download_url, dlhash, config, multihandler,
                 fileinfo, resumedata, vodeventcallback, set_error_func,
                 finished_func, failed_func):
        self.main_url = main_url
        self.download_url = download_url
        self.dlhash = dlhash
        self.config = config
        self.dlmode = config['mode']
        self.fileinfo = fileinfo
        self.vodeventcallback = vodeventcallback
        self.set_error_func = set_error_func
        self.finished_func = finished_func
        self.failed_func = failed_func
        self.download_id = binascii.hexlify(self.dlhash) + '-' + str(
            long(time.time())) + '-' + str(random.randint(0, 100000))
        self.dldoneflag = Event()
        self.rawserver = multihandler.newRawServer(dlhash, self.dldoneflag)
        if download_url is not None:
            url = download_url
        else:
            url = main_url
        self.downloader = Downloader(url, dlhash, self.rawserver, self.failed)
        self.voddownload = None
        self.storage = None
        self.log_prefix = 'dd::' + binascii.hexlify(self.dlhash) + ':'
        predownload = self.config.get('predownload', False)
        if DEBUG:
            log(self.log_prefix + '__init__: predownload', predownload)
        if resumedata is None and predownload:
            self.downloader.predownload(self.init_predownloaded)
        else:
            callback = lambda content_length, mimetype: self.init(
                resumedata, content_length, mimetype)
            self.downloader.init(callback)

    def init_predownloaded(self, mimetype, filedata):
        if DEBUG:
            log(self.log_prefix + 'init_predownloaded: mimetype', mimetype,
                'len', len(filedata))
        if self.dldoneflag.is_set():
            if DEBUG:
                log(self.log_prefix +
                    'init_predownloaded: done flag is set, exit')
            return
        ext = self.guess_extension_from_mimetype(mimetype)
        filename = binascii.hexlify(self.dlhash)
        if len(ext):
            filename += '.' + ext
        content_length = len(filedata)
        self.fileinfo['filename'] = filename
        self.fileinfo['size'] = content_length
        self.fileinfo['mimetype'] = mimetype
        temp_dir = os.path.join(self.config['buffer_dir'],
                                binascii.hexlify(self.dlhash))
        if not os.path.isdir(temp_dir):
            os.mkdir(temp_dir)
        self.storage = Storage(self.dlhash,
                               self.config,
                               self.fileinfo,
                               temp_dir,
                               None,
                               self.finished_callback,
                               filedata=filedata)
        self.downloader.set_storage(self.storage)
        self.finished_callback()
        if self.dlmode == DLMODE_VOD:
            if DEBUG:
                log(
                    self.log_prefix +
                    'init_predownloaded: starting in vod mode, but download is finished: fileinfo',
                    self.fileinfo)
            self.vodeventcallback(
                self.fileinfo, VODEVENT_START, {
                    'complete': True,
                    'filename': self.storage.get_dest_path(),
                    'mimetype': self.fileinfo['mimetype'],
                    'stream': None,
                    'length': self.storage.get_content_length(),
                    'bitrate': self.fileinfo['bitrate']
                })

    def init(self, resumedata=None, content_length=None, mimetype=None):
        if DEBUG:
            log(self.log_prefix + 'init: resumedata', resumedata,
                'content_length', content_length, 'mimetype', mimetype)
        if self.dldoneflag.is_set():
            if DEBUG:
                log(self.log_prefix + 'init: done flag is set, exit')
            return
        if content_length is None:
            content_length, mimetype = self.downloader.init()
        if resumedata is not None:
            if content_length != resumedata['size']:
                raise Exception('content length differs from resumedata')
            if mimetype != resumedata['mimetype']:
                raise Exception('mime type differs from resumedata')
            filename = resumedata['filename']
            duration = resumedata.get('duration', None)
            if duration:
                bitrate = content_length / duration
                self.fileinfo['duration'] = duration
                self.fileinfo['bitrate'] = bitrate
                if DEBUG:
                    log(
                        self.log_prefix +
                        '__init__: got duration from resumedata: main_url',
                        self.main_url, 'duration', duration, 'bitrate',
                        bitrate)
        else:
            ext = self.guess_extension_from_mimetype(mimetype)
            filename = binascii.hexlify(self.dlhash)
            if len(ext):
                filename += '.' + ext
        self.fileinfo['filename'] = filename
        self.fileinfo['size'] = content_length
        self.fileinfo['mimetype'] = mimetype
        temp_dir = os.path.join(self.config['buffer_dir'],
                                binascii.hexlify(self.dlhash))
        if not os.path.isdir(temp_dir):
            os.mkdir(temp_dir)
        self.storage = Storage(self.dlhash, self.config, self.fileinfo,
                               temp_dir, resumedata, self.finished_callback)
        self.downloader.set_storage(self.storage)
        completed = self.storage.is_finished()
        if completed:
            self.finished_callback()
        if self.dlmode == DLMODE_VOD:
            if completed:
                if DEBUG:
                    log(
                        self.log_prefix +
                        '__init__: starting in vod mode, but download is finished: fileinfo',
                        self.fileinfo)
                self.vodeventcallback(
                    self.fileinfo, VODEVENT_START, {
                        'complete': True,
                        'filename': self.storage.get_dest_path(),
                        'mimetype': self.fileinfo['mimetype'],
                        'stream': None,
                        'length': self.storage.get_content_length(),
                        'bitrate': self.fileinfo['bitrate']
                    })
            else:
                if DEBUG:
                    log(
                        self.log_prefix +
                        '__init__: starting in vod mode: fileinfo',
                        self.fileinfo)
                self.voddownload = VODTransporter(self, self.dlhash,
                                                  self.fileinfo,
                                                  self.vodeventcallback)
                self.storage.add_got_data_observer(
                    self.voddownload.got_data_observer)
        if not completed:
            self.downloader.start()

    def get_download_id(self):
        return self.download_id

    def guess_extension_from_mimetype(self, mimetype):
        if mimetype is None:
            mimetype = ''
        if mimetype == 'video/x-msvideo':
            ext = 'avi'
        elif mimetype == 'video/mp4':
            ext = 'mp4'
        elif mimetype == 'video/x-matroska':
            ext = 'mkv'
        elif mimetype == 'video/x-m4v':
            ext = 'm4v'
        elif mimetype == 'video/quicktime':
            ext = 'mov'
        elif mimetype == 'video/x-sgi-movie':
            ext = 'movie'
        elif mimetype == 'video/mpeg':
            ext = 'mpg'
        elif mimetype == 'application/ogg' or mimetype == 'video/ogg':
            ext = 'ogg'
        elif mimetype == 'video/x-flv':
            ext = 'flv'
        elif mimetype == 'video/webm':
            ext = 'webm'
        elif mimetype == 'video/x-ms-wmv':
            ext = 'wmv'
        else:
            if DEBUG:
                log(
                    self.log_prefix +
                    'guess_extension_from_mimetype: unknown mimetype',
                    mimetype)
            ext = 'mpg'
        if DEBUG:
            log(self.log_prefix + 'guess_extension_from_mimetype: mimetype',
                mimetype, 'ext', ext)
        return ext

    def finished_callback(self):
        if DEBUG:
            log(self.log_prefix + 'finished_callback: url', self.main_url)

        def _finished():
            if self.voddownload is not None:
                self.voddownload.complete()
            if self.finished_func is not None:
                self.finished_func(self.main_url, self.download_url,
                                   self.dlhash, self.fileinfo)

        self.rawserver.add_task(_finished, 0.0)

    def failed(self, err):
        if DEBUG:
            log(self.log_prefix + 'failed: url', self.main_url, 'err', err)
        if self.voddownload is not None:
            self.voddownload.shutdown()
            self.voddownload = None
        self.set_error_func(err)

        def _failed():
            if self.failed_func is not None:
                try:
                    self.failed_func(err)
                except:
                    if DEBUG:
                        print_exc()

        self.rawserver.add_task(_failed, 0.0)

    def got_duration(self, duration, from_player=True):
        if DEBUG:
            log(self.log_prefix + 'got_duration: main_url', self.main_url,
                'duration', duration, 'fileinfo', self.fileinfo)
        if duration <= 0:
            if DEBUG:
                log(self.log_prefix + 'got_duration: bad duration')
            return
        cur_duration = self.fileinfo.get('duration', None)
        if cur_duration is not None:
            if cur_duration != duration:
                if DEBUG:
                    log(
                        self.log_prefix +
                        'got_duration: duration does not match with metadata: main_url',
                        self.main_url, 'cur_duration', cur_duration,
                        'duration', duration)
        else:
            bitrate = self.fileinfo['size'] / duration
            self.fileinfo['duration'] = duration
            self.fileinfo['bitrate'] = bitrate
            if self.voddownload is not None:
                self.voddownload.set_bitrate(bitrate)

    def get_stats(self):
        status = None
        stats = {}
        s = Statistics_Response()
        s.numSeeds = 0
        s.numPeers = 0
        s.httpSeeds = 0
        s.upTotal = 0
        s.downTotal = self.downloader.measure.get_total()
        s.httpDownTotal = s.downTotal
        stats['stats'] = s
        stats['up'] = 0
        if self.storage is None:
            stats['frac'] = 0
            finished = False
        else:
            stats['frac'] = self.storage.get_progress()
            finished = self.storage.is_finished()
        if finished:
            stats['vod_prebuf_frac'] = 1.0
            stats['vod_playable'] = True
            stats['vod_playable_after'] = 0.0
            stats['vod'] = False
            stats['down'] = 0
            stats['httpdown'] = 0
        else:
            s.numSeeds = 1
            s.httpSeeds = 1
            stats['down'] = self.downloader.measure.get_rate()
            stats['httpdown'] = stats['down']
            if self.voddownload is not None:
                stats[
                    'vod_prebuf_frac'] = self.voddownload.get_prebuffering_progress(
                    )
                stats['vod_playable'] = self.voddownload.is_playable()
                stats[
                    'vod_playable_after'] = self.voddownload.get_playable_after(
                    )
                stats['vod'] = True
            else:
                stats['vod_prebuf_frac'] = 0.0
                stats['vod_playable'] = False
                stats['vod_playable_after'] = float(2147483648L)
                stats['vod'] = False
        return (status, stats)

    def shutdown(self):
        if self.voddownload is not None:
            self.voddownload.shutdown()
            self.voddownload = None
        self.downloader.shutdown()
        if self.storage is not None:
            self.storage.close()
            self.storage = None
        self.dldoneflag.set()
        self.rawserver.shutdown()
        return self.checkpoint()

    def restart(self, dlmode, vodeventfunc, finished_func, failed_func):
        self.dlmode = dlmode
        self.fileinfo['usercallback'] = vodeventfunc
        self.finished_func = finished_func
        self.failed_func = failed_func
        if self.storage is None:
            try:
                self.init()
            except Exception as e:
                if DEBUG:
                    print_exc()
                self.failed(e)
                return

        if dlmode == DLMODE_VOD:
            if self.storage.is_finished():
                if DEBUG:
                    log(
                        self.log_prefix +
                        'restart: restart in vod mode requested, but download is finished: fileinfo',
                        self.fileinfo)
                self.vodeventcallback(
                    self.fileinfo, VODEVENT_START, {
                        'complete': True,
                        'filename': self.storage.get_dest_path(),
                        'mimetype': self.fileinfo['mimetype'],
                        'stream': None,
                        'length': self.storage.get_content_length(),
                        'bitrate': self.fileinfo['bitrate']
                    })
            else:
                if self.voddownload is not None:
                    self.storage.remove_got_data_observer(
                        self.voddownload.got_data_observer)
                    self.voddownload.shutdown()
                    self.voddownload = None
                    if DEBUG:
                        log(self.log_prefix +
                            'restart: voddownload is not None, stop current download'
                            )
                self.voddownload = VODTransporter(self, self.dlhash,
                                                  self.fileinfo,
                                                  self.vodeventcallback)
                self.storage.add_got_data_observer(
                    self.voddownload.got_data_observer)
                if not self.downloader.is_running():
                    if DEBUG:
                        log(self.log_prefix +
                            'restart: downloader is not running, start it')
                    self.downloader.start()

    def checkpoint(self):
        if self.storage is None:
            return
        resumedata = self.storage.checkpoint()
        resumedata['mimetype'] = self.fileinfo['mimetype']
        resumedata['filename'] = self.fileinfo['filename']
        resumedata['duration'] = self.fileinfo['duration']
        return resumedata

    def get_dest_path(self):
        if self.storage is None:
            return
        return self.storage.get_dest_path()

    def get_content_length(self):
        if self.storage is None:
            return
        return self.storage.get_content_length()

    def set_wait_sufficient_speed(self, value):
        if self.voddownload is not None:
            self.voddownload.set_wait_sufficient_speed(value)

    def set_player_buffer_time(self, value):
        if self.voddownload is not None:
            self.voddownload.set_player_buffer_time(value)

    def set_live_buffer_time(self, value):
        if self.voddownload is not None:
            self.voddownload.set_live_buffer_time(value)