1 from __future__
import unicode_literals
5 from .fragment
import FragmentFD
6 from ..compat
import compat_urllib_error
13 class DashSegmentsFD(FragmentFD
):
15 Download segments in a DASH manifest
18 FD_NAME
= 'dashsegments'
20 def real_download(self
, filename
, info_dict
):
21 segments
= info_dict
['fragments'][:1] if self
.params
.get(
22 'test', False) else info_dict
['fragments']
26 'total_frags': len(segments
),
29 self
._prepare
_and
_start
_frag
_download
(ctx
)
31 segments_filenames
= []
33 fragment_retries
= self
.params
.get('fragment_retries', 0)
34 skip_unavailable_fragments
= self
.params
.get('skip_unavailable_fragments', True)
36 def process_segment(segment
, tmp_filename
, num
):
37 segment_url
= segment
['url']
38 segment_name
= 'Frag%d' % num
39 target_filename
= '%s-%s' % (tmp_filename
, segment_name
)
40 # In DASH, the first segment contains necessary headers to
41 # generate a valid MP4 file, so always abort for the first segment
42 fatal
= num
== 0 or not skip_unavailable_fragments
44 while count
<= fragment_retries
:
46 success
= ctx
['dl'].download(target_filename
, {'url': segment_url
})
49 down
, target_sanitized
= sanitize_open(target_filename
, 'rb')
50 ctx
['dest_stream'].write(down
.read())
52 segments_filenames
.append(target_sanitized
)
54 except compat_urllib_error
.HTTPError
as err
:
55 # YouTube may often return 404 HTTP error for a fragment causing the
56 # whole download to fail. However if the same fragment is immediately
57 # retried with the same request data this usually succeeds (1-2 attemps
58 # is usually enough) thus allowing to download the whole file successfully.
59 # To be future-proof we will retry all fragments that fail with any
62 if count
<= fragment_retries
:
63 self
.report_retry_fragment(err
, segment_name
, count
, fragment_retries
)
64 if count
> fragment_retries
:
66 self
.report_skip_fragment(segment_name
)
68 self
.report_error('giving up after %s fragment retries' % fragment_retries
)
72 for i
, segment
in enumerate(segments
):
73 if not process_segment(segment
, ctx
['tmpfilename'], i
):
76 self
._finish
_frag
_download
(ctx
)
78 for segment_file
in segments_filenames
:
79 os
.remove(encodeFilename(segment_file
))