X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=youtube_dl%2Fdownloader%2Ff4m.py;h=b3be16ff15353ed057607064bba2faa3fcdc2fad;hb=f0b8e3607db6bc2e7cdfcf3175e85d9bccb22229;hp=9a6c03556a64ae5b052354e8973d7bc01546b392;hpb=6a7a38967976ea0d0b911c2965aaa74bed2976d7;p=youtube-dl diff --git a/youtube_dl/downloader/f4m.py b/youtube_dl/downloader/f4m.py index 9a6c03556..b3be16ff1 100644 --- a/youtube_dl/downloader/f4m.py +++ b/youtube_dl/downloader/f4m.py @@ -4,18 +4,19 @@ import base64 import io import itertools import os -from struct import unpack, pack import time import xml.etree.ElementTree as etree from .common import FileDownloader from .http import HttpFD from ..utils import ( - compat_urllib_request, + struct_pack, + struct_unpack, compat_urlparse, format_bytes, encodeFilename, sanitize_open, + xpath_text, ) @@ -27,13 +28,13 @@ class FlvReader(io.BytesIO): # Utility functions for reading numbers and strings def read_unsigned_long_long(self): - return unpack('!Q', self.read(8))[0] + return struct_unpack('!Q', self.read(8))[0] def read_unsigned_int(self): - return unpack('!I', self.read(4))[0] + return struct_unpack('!I', self.read(4))[0] def read_unsigned_char(self): - return unpack('!B', self.read(1))[0] + return struct_unpack('!B', self.read(1))[0] def read_string(self): res = b'' @@ -116,8 +117,8 @@ class FlvReader(io.BytesIO): self.read_unsigned_char() # flags self.read(3) - # BootstrapinfoVersion - bootstrap_info_version = self.read_unsigned_int() + + self.read_unsigned_int() # BootstrapinfoVersion # Profile,Live,Update,Reserved self.read(1) # time scale @@ -126,15 +127,15 @@ class FlvReader(io.BytesIO): self.read_unsigned_long_long() # SmpteTimeCodeOffset self.read_unsigned_long_long() - # MovieIdentifier - movie_identifier = self.read_string() + + self.read_string() # MovieIdentifier server_count = self.read_unsigned_char() # ServerEntryTable for i in range(server_count): self.read_string() quality_count = self.read_unsigned_char() # QualityEntryTable - for i in range(server_count): + for i in range(quality_count): self.read_string() # DrmData self.read_string() @@ -196,7 +197,7 @@ def write_flv_header(stream, metadata): # Script data stream.write(b'\x12') # Size of the metadata with 3 bytes - stream.write(pack('!L', len(metadata))[1:]) + stream.write(struct_pack('!L', len(metadata))[1:]) stream.write(b'\x00\x00\x00\x00\x00\x00\x00') stream.write(metadata) # Magic numbers extracted from the output files produced by AdobeHDS.php @@ -220,21 +221,39 @@ class F4mFD(FileDownloader): def real_download(self, filename, info_dict): man_url = info_dict['url'] + requested_bitrate = info_dict.get('tbr') self.to_screen('[download] Downloading f4m manifest') manifest = self.ydl.urlopen(man_url).read() self.report_destination(filename) - http_dl = HttpQuietDownloader(self.ydl, {'continuedl': True, 'quiet': True, 'noprogress': True}) + http_dl = HttpQuietDownloader(self.ydl, + { + 'continuedl': True, + 'quiet': True, + 'noprogress': True, + 'test': self.params.get('test', False), + }) doc = etree.fromstring(manifest) formats = [(int(f.attrib.get('bitrate', -1)), f) for f in doc.findall(_add_ns('media'))] - formats = sorted(formats, key=lambda f: f[0]) - rate, media = formats[-1] + if requested_bitrate is None: + # get the best format + formats = sorted(formats, key=lambda f: f[0]) + rate, media = formats[-1] + else: + rate, media = list(filter( + lambda f: int(f[0]) == requested_bitrate, formats))[0] + base_url = compat_urlparse.urljoin(man_url, media.attrib['url']) bootstrap = base64.b64decode(doc.find(_add_ns('bootstrapInfo')).text) metadata = base64.b64decode(media.find(_add_ns('metadata')).text) boot_info = read_bootstrap_info(bootstrap) fragments_list = build_fragments_list(boot_info) + if self.params.get('test', False): + # We only download the first fragment + fragments_list = fragments_list[:1] total_frags = len(fragments_list) + # For some akamai manifests we'll need to add a query to the fragment url + akamai_pv = xpath_text(doc, _add_ns('pv-2.0')) tmpfilename = self.temp_name(filename) (dest_stream, tmpfilename) = sanitize_open(tmpfilename, 'wb') @@ -274,6 +293,8 @@ class F4mFD(FileDownloader): for (seg_i, frag_i) in fragments_list: name = 'Seg%d-Frag%d' % (seg_i, frag_i) url = base_url + name + if akamai_pv: + url += '?' + akamai_pv.strip(';') frag_filename = '%s-%s' % (tmpfilename, name) success = http_dl.download(frag_filename, {'url': url}) if not success: @@ -288,6 +309,7 @@ class F4mFD(FileDownloader): break frags_filenames.append(frag_filename) + dest_stream.close() self.report_finish(format_bytes(state['downloaded_bytes']), time.time() - start) self.try_rename(tmpfilename, filename)