2015-07-29 02:26:16 +06:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								from __future__ import division, unicode_literals
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import os
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import time
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-19 18:34:25 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								import json
							 | 
						
					
						
							
								
									
										
										
										
											2015-07-29 02:26:16 +06:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								from .common import FileDownloader
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								from .http import HttpFD
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								from ..utils import (
							 | 
						
					
						
							
								
									
										
										
										
											2016-08-27 04:57:59 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    error_to_compat_str,
							 | 
						
					
						
							
								
									
										
										
										
											2015-07-29 02:26:16 +06:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    encodeFilename,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    sanitize_open,
							 | 
						
					
						
							
								
									
										
										
										
											2016-11-13 22:06:16 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    sanitized_Request,
							 | 
						
					
						
							
								
									
										
										
										
											2015-07-29 02:26:16 +06:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								class HttpQuietDownloader(HttpFD):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def to_screen(self, *args, **kargs):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        pass
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								class FragmentFD(FileDownloader):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    """
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    A base file downloader class for fragmented media (e.g. f4m/m3u8 manifests).
							 | 
						
					
						
							
								
									
										
										
										
											2016-03-19 20:54:21 +06:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    Available options:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2016-08-27 04:52:18 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    fragment_retries:   Number of times to retry a fragment for HTTP error (DASH
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                        and hlsnative only)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    skip_unavailable_fragments:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                        Skip unavailable fragments (DASH and hlsnative only)
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-24 03:09:08 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    keep_fragments:     Keep downloaded fragments on disk after downloading is
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                        finished
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-24 23:50:20 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    For each incomplete fragment download youtube-dl keeps on disk a special
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    bookkeeping file with download state and metadata (in future such files will
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    be used for any incomplete download handled by youtube-dl). This file is
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    used to properly handle resuming, check download file consistency and detect
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    potential errors. The file has a .ytdl extension and represents a standard
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    JSON file of the following format:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    extractor:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        Dictionary of extractor related data. TBD.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    downloader:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        Dictionary of downloader related data. May contain following data:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            current_fragment:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                Dictionary with current (being downloaded) fragment data:
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-25 23:33:35 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                index:  0-based index of current fragment among all fragments
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-24 23:50:20 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            fragment_count:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                Total count of fragments
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-30 22:04:01 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-25 23:33:35 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    This feature is experimental and file format may change in future.
							 | 
						
					
						
							
								
									
										
										
										
											2015-07-29 02:26:16 +06:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    """
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2016-06-28 18:07:50 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    def report_retry_fragment(self, err, frag_index, count, retries):
							 | 
						
					
						
							
								
									
										
										
										
											2016-03-19 20:41:24 +06:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        self.to_screen(
							 | 
						
					
						
							
								
									
										
										
										
											2016-06-28 18:07:50 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            '[download] Got server HTTP error: %s. Retrying fragment %d (attempt %d of %s)...'
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            % (error_to_compat_str(err), frag_index, count, self.format_retries(retries)))
							 | 
						
					
						
							
								
									
										
										
										
											2016-03-19 20:41:24 +06:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2016-06-28 18:07:50 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    def report_skip_fragment(self, frag_index):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.to_screen('[download] Skipping fragment %d...' % frag_index)
							 | 
						
					
						
							
								
									
										
										
										
											2016-08-27 04:52:18 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2016-11-13 22:06:16 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    def _prepare_url(self, info_dict, url):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        headers = info_dict.get('http_headers')
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return sanitized_Request(url, None, headers) if headers else url
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2015-07-29 02:26:16 +06:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def _prepare_and_start_frag_download(self, ctx):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self._prepare_frag_download(ctx)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self._start_frag_download(ctx)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-24 23:05:56 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    @staticmethod
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def __do_ytdl_file(ctx):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return not ctx['live'] and not ctx['tmpfilename'] == '-'
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-24 02:54:17 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    def _read_ytdl_file(self, ctx):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        stream, _ = sanitize_open(self.ytdl_filename(ctx['filename']), 'r')
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-24 23:50:20 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        ctx['fragment_index'] = json.loads(stream.read())['downloader']['current_fragment']['index']
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-24 02:54:17 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        stream.close()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def _write_ytdl_file(self, ctx):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        frag_index_stream, _ = sanitize_open(self.ytdl_filename(ctx['filename']), 'w')
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-24 23:50:20 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        downloader = {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            'current_fragment': {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                'index': ctx['fragment_index'],
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-24 02:54:17 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            },
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-24 23:50:20 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if ctx.get('fragment_count') is not None:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            downloader['fragment_count'] = ctx['fragment_count']
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        frag_index_stream.write(json.dumps({'downloader': downloader}))
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-24 02:54:17 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        frag_index_stream.close()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2016-06-28 18:07:50 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    def _download_fragment(self, ctx, frag_url, info_dict, headers=None):
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-24 02:54:17 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        fragment_filename = '%s-Frag%d' % (ctx['tmpfilename'], ctx['fragment_index'])
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        success = ctx['dl'].download(fragment_filename, {
							 | 
						
					
						
							
								
									
										
										
										
											2016-06-28 18:07:50 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            'url': frag_url,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            'http_headers': headers or info_dict.get('http_headers'),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        })
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if not success:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            return False, None
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-24 02:54:17 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        down, frag_sanitized = sanitize_open(fragment_filename, 'rb')
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ctx['fragment_filename_sanitized'] = frag_sanitized
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        frag_content = down.read()
							 | 
						
					
						
							
								
									
										
										
										
											2016-06-28 18:07:50 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        down.close()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return True, frag_content
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def _append_fragment(self, ctx, frag_content):
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-24 02:54:17 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        try:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            ctx['dest_stream'].write(frag_content)
							 | 
						
					
						
							
								
									
										
										
										
											2017-12-02 21:15:45 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            ctx['dest_stream'].flush()
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-24 02:54:17 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        finally:
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-24 23:05:56 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if self.__do_ytdl_file(ctx):
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-24 02:54:17 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                self._write_ytdl_file(ctx)
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-24 03:09:08 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if not self.params.get('keep_fragments', False):
							 | 
						
					
						
							
								
									
										
										
										
											2017-12-18 03:31:53 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                os.remove(encodeFilename(ctx['fragment_filename_sanitized']))
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-24 02:54:17 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            del ctx['fragment_filename_sanitized']
							 | 
						
					
						
							
								
									
										
										
										
											2016-06-28 18:07:50 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2015-07-29 02:26:16 +06:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def _prepare_frag_download(self, ctx):
							 | 
						
					
						
							
								
									
										
										
										
											2016-01-30 19:20:52 +06:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if 'live' not in ctx:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            ctx['live'] = False
							 | 
						
					
						
							
								
									
										
										
										
											2017-10-15 06:13:07 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if not ctx['live']:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            total_frags_str = '%d' % ctx['total_frags']
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            ad_frags = ctx.get('ad_frags', 0)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if ad_frags:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                total_frags_str += ' (not including %d ad)' % ad_frags
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            total_frags_str = 'unknown (live)'
							 | 
						
					
						
							
								
									
										
										
										
											2016-01-30 19:20:52 +06:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        self.to_screen(
							 | 
						
					
						
							
								
									
										
										
										
											2017-10-15 06:13:07 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            '[%s] Total fragments: %s' % (self.FD_NAME, total_frags_str))
							 | 
						
					
						
							
								
									
										
										
										
											2015-07-29 02:26:16 +06:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.report_destination(ctx['filename'])
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        dl = HttpQuietDownloader(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            self.ydl,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                'continuedl': True,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                'quiet': True,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                'noprogress': True,
							 | 
						
					
						
							
								
									
										
										
										
											2016-02-14 14:25:04 +06:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                'ratelimit': self.params.get('ratelimit'),
							 | 
						
					
						
							
								
									
										
										
										
											2015-08-13 21:07:14 +06:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                'retries': self.params.get('retries', 0),
							 | 
						
					
						
							
								
									
										
										
										
											2017-02-06 23:07:59 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                'nopart': self.params.get('nopart', False),
							 | 
						
					
						
							
								
									
										
										
										
											2015-07-29 02:26:16 +06:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                'test': self.params.get('test', False),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        )
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        tmpfilename = self.temp_name(ctx['filename'])
							 | 
						
					
						
							
								
									
										
										
										
											2016-06-28 18:07:50 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        open_mode = 'wb'
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        resume_len = 0
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-24 02:54:17 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2016-06-28 18:07:50 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        # Establish possible resume length
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if os.path.isfile(encodeFilename(tmpfilename)):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            open_mode = 'ab'
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            resume_len = os.path.getsize(encodeFilename(tmpfilename))
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-24 02:54:17 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-24 23:05:56 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        # Should be initialized before ytdl file check
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ctx.update({
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            'tmpfilename': tmpfilename,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            'fragment_index': 0,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        })
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-24 02:54:17 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-24 23:05:56 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if self.__do_ytdl_file(ctx):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if os.path.isfile(encodeFilename(self.ytdl_filename(ctx['filename']))):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                self._read_ytdl_file(ctx)
							 | 
						
					
						
							
								
									
										
										
										
											2017-09-14 23:19:53 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                if ctx['fragment_index'] > 0 and resume_len == 0:
							 | 
						
					
						
							
								
									
										
										
										
											2017-10-17 22:53:34 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                    self.report_warning(
							 | 
						
					
						
							
								
									
										
										
										
											2017-09-14 23:19:53 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                        'Inconsistent state of incomplete fragment download. '
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                        'Restarting from the beginning...')
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    ctx['fragment_index'] = resume_len = 0
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    self._write_ytdl_file(ctx)
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-24 23:05:56 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            else:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                self._write_ytdl_file(ctx)
							 | 
						
					
						
							
								
									
										
										
										
											2017-09-14 23:19:53 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                assert ctx['fragment_index'] == 0
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-24 02:54:17 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2016-06-28 18:07:50 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        dest_stream, tmpfilename = sanitize_open(tmpfilename, open_mode)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2015-07-29 02:26:16 +06:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ctx.update({
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            'dl': dl,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            'dest_stream': dest_stream,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            'tmpfilename': tmpfilename,
							 | 
						
					
						
							
								
									
										
										
										
											2016-06-28 18:07:50 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            # Total complete fragments downloaded so far in bytes
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            'complete_frags_downloaded_bytes': resume_len,
							 | 
						
					
						
							
								
									
										
										
										
											2015-07-29 02:26:16 +06:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        })
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def _start_frag_download(self, ctx):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        total_frags = ctx['total_frags']
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        # This dict stores the download progress, it's updated by the progress
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        # hook
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        state = {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            'status': 'downloading',
							 | 
						
					
						
							
								
									
										
										
										
											2016-06-28 18:07:50 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            'downloaded_bytes': ctx['complete_frags_downloaded_bytes'],
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-22 16:42:24 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            'fragment_index': ctx['fragment_index'],
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            'fragment_count': total_frags,
							 | 
						
					
						
							
								
									
										
										
										
											2015-07-29 02:26:16 +06:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            'filename': ctx['filename'],
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            'tmpfilename': ctx['tmpfilename'],
							 | 
						
					
						
							
								
									
										
										
										
											2016-01-13 00:00:31 +06:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        start = time.time()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ctx.update({
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            'started': start,
							 | 
						
					
						
							
								
									
										
										
										
											2016-01-12 23:18:38 +06:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            # Amount of fragment's bytes downloaded by the time of the previous
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            # frag progress hook invocation
							 | 
						
					
						
							
								
									
										
										
										
											2016-01-13 00:00:31 +06:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            'prev_frag_downloaded_bytes': 0,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        })
							 | 
						
					
						
							
								
									
										
										
										
											2015-07-29 02:26:16 +06:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        def frag_progress_hook(s):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if s['status'] not in ('downloading', 'finished'):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                return
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2016-01-30 19:20:52 +06:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            time_now = time.time()
							 | 
						
					
						
							
								
									
										
										
										
											2016-01-30 19:30:31 +06:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            state['elapsed'] = time_now - start
							 | 
						
					
						
							
								
									
										
										
										
											2016-01-10 14:32:53 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            frag_total_bytes = s.get('total_bytes') or 0
							 | 
						
					
						
							
								
									
										
										
										
											2016-01-30 19:20:52 +06:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if not ctx['live']:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                estimated_size = (
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    (ctx['complete_frags_downloaded_bytes'] + frag_total_bytes) /
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-22 16:42:24 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                    (state['fragment_index'] + 1) * total_frags)
							 | 
						
					
						
							
								
									
										
										
										
											2016-01-30 19:20:52 +06:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                state['total_bytes_estimate'] = estimated_size
							 | 
						
					
						
							
								
									
										
										
										
											2015-07-29 02:26:16 +06:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2016-01-12 23:18:38 +06:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if s['status'] == 'finished':
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-22 16:42:24 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                state['fragment_index'] += 1
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                ctx['fragment_index'] = state['fragment_index']
							 | 
						
					
						
							
								
									
										
										
										
											2016-01-13 00:00:31 +06:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                state['downloaded_bytes'] += frag_total_bytes - ctx['prev_frag_downloaded_bytes']
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                ctx['complete_frags_downloaded_bytes'] = state['downloaded_bytes']
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                ctx['prev_frag_downloaded_bytes'] = 0
							 | 
						
					
						
							
								
									
										
										
										
											2016-01-12 23:18:38 +06:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            else:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                frag_downloaded_bytes = s['downloaded_bytes']
							 | 
						
					
						
							
								
									
										
										
										
											2016-01-13 00:00:31 +06:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                state['downloaded_bytes'] += frag_downloaded_bytes - ctx['prev_frag_downloaded_bytes']
							 | 
						
					
						
							
								
									
										
										
										
											2016-01-30 19:20:52 +06:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                if not ctx['live']:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    state['eta'] = self.calc_eta(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                        start, time_now, estimated_size,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                        state['downloaded_bytes'])
							 | 
						
					
						
							
								
									
										
										
										
											2016-03-06 05:36:52 +06:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                state['speed'] = s.get('speed') or ctx.get('speed')
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                ctx['speed'] = state['speed']
							 | 
						
					
						
							
								
									
										
										
										
											2016-01-13 00:00:31 +06:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                ctx['prev_frag_downloaded_bytes'] = frag_downloaded_bytes
							 | 
						
					
						
							
								
									
										
										
										
											2015-07-29 02:26:16 +06:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            self._hook_progress(state)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ctx['dl'].add_progress_hook(frag_progress_hook)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return start
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def _finish_frag_download(self, ctx):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ctx['dest_stream'].close()
							 | 
						
					
						
							
								
									
										
										
										
											2017-04-24 23:05:56 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if self.__do_ytdl_file(ctx):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            ytdl_filename = encodeFilename(self.ytdl_filename(ctx['filename']))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if os.path.isfile(ytdl_filename):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                os.remove(ytdl_filename)
							 | 
						
					
						
							
								
									
										
										
										
											2015-07-29 02:26:16 +06:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        elapsed = time.time() - ctx['started']
							 | 
						
					
						
							
								
									
										
										
										
											2018-03-24 15:59:48 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if ctx['tmpfilename'] == '-':
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            downloaded_bytes = ctx['complete_frags_downloaded_bytes']
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            self.try_rename(ctx['tmpfilename'], ctx['filename'])
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            downloaded_bytes = os.path.getsize(encodeFilename(ctx['filename']))
							 | 
						
					
						
							
								
									
										
										
										
											2015-07-29 02:26:16 +06:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self._hook_progress({
							 | 
						
					
						
							
								
									
										
										
										
											2018-03-24 15:59:48 +07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            'downloaded_bytes': downloaded_bytes,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            'total_bytes': downloaded_bytes,
							 | 
						
					
						
							
								
									
										
										
										
											2015-07-29 02:26:16 +06:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            'filename': ctx['filename'],
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            'status': 'finished',
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            'elapsed': elapsed,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        })
							 |