[vevo] Support 1080p videos (Fixes #3656)
[youtube-dl] / youtube_dl / downloader / hls.py
1 from __future__ import unicode_literals
2
3 import os
4 import re
5 import subprocess
6
7 from .common import FileDownloader
8 from ..utils import (
9     compat_urlparse,
10     check_executable,
11     encodeFilename,
12 )
13
14
15 class HlsFD(FileDownloader):
16     def real_download(self, filename, info_dict):
17         url = info_dict['url']
18         self.report_destination(filename)
19         tmpfilename = self.temp_name(filename)
20
21         args = [
22             '-y', '-i', url, '-f', 'mp4', '-c', 'copy',
23             '-bsf:a', 'aac_adtstoasc',
24             encodeFilename(tmpfilename, for_subprocess=True)]
25
26         for program in ['avconv', 'ffmpeg']:
27             if check_executable(program, ['-version']):
28                 break
29         else:
30             self.report_error(u'm3u8 download detected but ffmpeg or avconv could not be found. Please install one.')
31             return False
32         cmd = [program] + args
33
34         retval = subprocess.call(cmd)
35         if retval == 0:
36             fsize = os.path.getsize(encodeFilename(tmpfilename))
37             self.to_screen(u'\r[%s] %s bytes' % (cmd[0], fsize))
38             self.try_rename(tmpfilename, filename)
39             self._hook_progress({
40                 'downloaded_bytes': fsize,
41                 'total_bytes': fsize,
42                 'filename': filename,
43                 'status': 'finished',
44             })
45             return True
46         else:
47             self.to_stderr(u"\n")
48             self.report_error(u'%s exited with code %d' % (program, retval))
49             return False
50
51
52 class NativeHlsFD(FileDownloader):
53     """ A more limited implementation that does not require ffmpeg """
54
55     def real_download(self, filename, info_dict):
56         url = info_dict['url']
57         self.report_destination(filename)
58         tmpfilename = self.temp_name(filename)
59
60         self.to_screen(
61             '[hlsnative] %s: Downloading m3u8 manifest' % info_dict['id'])
62         data = self.ydl.urlopen(url).read()
63         s = data.decode('utf-8', 'ignore')
64         segment_urls = []
65         for line in s.splitlines():
66             line = line.strip()
67             if line and not line.startswith('#'):
68                 segment_url = (
69                     line
70                     if re.match(r'^https?://', line)
71                     else compat_urlparse.urljoin(url, line))
72                 segment_urls.append(segment_url)
73
74         byte_counter = 0
75         with open(tmpfilename, 'wb') as outf:
76             for i, segurl in enumerate(segment_urls):
77                 segment = self.ydl.urlopen(segurl).read()
78                 outf.write(segment)
79                 byte_counter += len(segment)
80                 self.to_screen(
81                     '[hlsnative] %s: Downloading segment %d / %d' %
82                     (info_dict['id'], i + 1, len(segment_urls)))
83
84         self._hook_progress({
85             'downloaded_bytes': byte_counter,
86             'total_bytes': byte_counter,
87             'filename': filename,
88             'status': 'finished',
89         })
90         self.try_rename(tmpfilename, filename)
91         return True
92