| 
									
										
										
										
											2014-09-24 14:16:56 +02:00
										 |  |  | from __future__ import unicode_literals | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-23 17:59:27 +02:00
										 |  |  | import os | 
					
						
							| 
									
										
										
										
											2014-09-24 14:16:56 +02:00
										 |  |  | import re | 
					
						
							| 
									
										
										
										
											2013-09-23 17:59:27 +02:00
										 |  |  | import subprocess | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-06 12:14:26 +01:00
										 |  |  | from ..postprocessor.ffmpeg import FFmpegPostProcessor | 
					
						
							| 
									
										
										
										
											2013-09-23 17:59:27 +02:00
										 |  |  | from .common import FileDownloader | 
					
						
							| 
									
										
										
										
											2014-12-13 12:24:42 +01:00
										 |  |  | from ..compat import ( | 
					
						
							| 
									
										
										
										
											2014-09-24 14:16:56 +02:00
										 |  |  |     compat_urlparse, | 
					
						
							| 
									
										
										
										
											2014-09-24 14:38:40 +02:00
										 |  |  |     compat_urllib_request, | 
					
						
							| 
									
										
										
										
											2014-12-13 12:24:42 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | from ..utils import ( | 
					
						
							| 
									
										
										
										
											2013-09-23 17:59:27 +02:00
										 |  |  |     encodeFilename, | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class HlsFD(FileDownloader): | 
					
						
							|  |  |  |     def real_download(self, filename, info_dict): | 
					
						
							|  |  |  |         url = info_dict['url'] | 
					
						
							|  |  |  |         self.report_destination(filename) | 
					
						
							|  |  |  |         tmpfilename = self.temp_name(filename) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-24 21:23:05 +01:00
										 |  |  |         args = [ | 
					
						
							|  |  |  |             '-y', '-i', url, '-f', 'mp4', '-c', 'copy', | 
					
						
							|  |  |  |             '-bsf:a', 'aac_adtstoasc', | 
					
						
							|  |  |  |             encodeFilename(tmpfilename, for_subprocess=True)] | 
					
						
							| 
									
										
										
										
											2013-09-23 17:59:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-04 13:40:30 +01:00
										 |  |  |         ffpp = FFmpegPostProcessor(downloader=self) | 
					
						
							|  |  |  |         program = ffpp._executable | 
					
						
							|  |  |  |         if program is None: | 
					
						
							| 
									
										
										
										
											2014-11-26 12:26:21 +01:00
										 |  |  |             self.report_error('m3u8 download detected but ffmpeg or avconv could not be found. Please install one.') | 
					
						
							| 
									
										
										
										
											2014-08-27 15:50:03 +02:00
										 |  |  |             return False | 
					
						
							| 
									
										
										
										
											2014-12-06 12:14:26 +01:00
										 |  |  |         ffpp.check_version() | 
					
						
							| 
									
										
										
										
											2015-01-04 13:40:30 +01:00
										 |  |  |         cmd = [program] + args | 
					
						
							| 
									
										
										
										
											2014-12-06 12:14:26 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-23 17:59:27 +02:00
										 |  |  |         retval = subprocess.call(cmd) | 
					
						
							|  |  |  |         if retval == 0: | 
					
						
							|  |  |  |             fsize = os.path.getsize(encodeFilename(tmpfilename)) | 
					
						
							| 
									
										
										
										
											2014-11-26 12:26:21 +01:00
										 |  |  |             self.to_screen('\r[%s] %s bytes' % (cmd[0], fsize)) | 
					
						
							| 
									
										
										
										
											2013-09-23 17:59:27 +02:00
										 |  |  |             self.try_rename(tmpfilename, filename) | 
					
						
							|  |  |  |             self._hook_progress({ | 
					
						
							|  |  |  |                 'downloaded_bytes': fsize, | 
					
						
							|  |  |  |                 'total_bytes': fsize, | 
					
						
							|  |  |  |                 'filename': filename, | 
					
						
							|  |  |  |                 'status': 'finished', | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  |             return True | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2014-11-26 12:26:21 +01:00
										 |  |  |             self.to_stderr('\n') | 
					
						
							|  |  |  |             self.report_error('%s exited with code %d' % (program, retval)) | 
					
						
							| 
									
										
										
										
											2013-09-23 17:59:27 +02:00
										 |  |  |             return False | 
					
						
							| 
									
										
										
										
											2014-09-24 14:16:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class NativeHlsFD(FileDownloader): | 
					
						
							|  |  |  |     """ A more limited implementation that does not require ffmpeg """ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def real_download(self, filename, info_dict): | 
					
						
							|  |  |  |         url = info_dict['url'] | 
					
						
							|  |  |  |         self.report_destination(filename) | 
					
						
							|  |  |  |         tmpfilename = self.temp_name(filename) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.to_screen( | 
					
						
							|  |  |  |             '[hlsnative] %s: Downloading m3u8 manifest' % info_dict['id']) | 
					
						
							|  |  |  |         data = self.ydl.urlopen(url).read() | 
					
						
							|  |  |  |         s = data.decode('utf-8', 'ignore') | 
					
						
							|  |  |  |         segment_urls = [] | 
					
						
							|  |  |  |         for line in s.splitlines(): | 
					
						
							|  |  |  |             line = line.strip() | 
					
						
							|  |  |  |             if line and not line.startswith('#'): | 
					
						
							|  |  |  |                 segment_url = ( | 
					
						
							|  |  |  |                     line | 
					
						
							|  |  |  |                     if re.match(r'^https?://', line) | 
					
						
							|  |  |  |                     else compat_urlparse.urljoin(url, line)) | 
					
						
							|  |  |  |                 segment_urls.append(segment_url) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-24 14:38:40 +02:00
										 |  |  |         is_test = self.params.get('test', False) | 
					
						
							|  |  |  |         remaining_bytes = self._TEST_FILE_SIZE if is_test else None | 
					
						
							| 
									
										
										
										
											2014-09-24 14:16:56 +02:00
										 |  |  |         byte_counter = 0 | 
					
						
							|  |  |  |         with open(tmpfilename, 'wb') as outf: | 
					
						
							|  |  |  |             for i, segurl in enumerate(segment_urls): | 
					
						
							|  |  |  |                 self.to_screen( | 
					
						
							|  |  |  |                     '[hlsnative] %s: Downloading segment %d / %d' % | 
					
						
							|  |  |  |                     (info_dict['id'], i + 1, len(segment_urls))) | 
					
						
							| 
									
										
										
										
											2014-09-24 14:38:40 +02:00
										 |  |  |                 seg_req = compat_urllib_request.Request(segurl) | 
					
						
							| 
									
										
										
										
											2014-09-25 09:21:45 +02:00
										 |  |  |                 if remaining_bytes is not None: | 
					
						
							| 
									
										
										
										
											2014-09-24 14:38:40 +02:00
										 |  |  |                     seg_req.add_header('Range', 'bytes=0-%d' % (remaining_bytes - 1)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 segment = self.ydl.urlopen(seg_req).read() | 
					
						
							| 
									
										
										
										
											2014-09-25 09:21:45 +02:00
										 |  |  |                 if remaining_bytes is not None: | 
					
						
							| 
									
										
										
										
											2014-09-24 14:38:40 +02:00
										 |  |  |                     segment = segment[:remaining_bytes] | 
					
						
							|  |  |  |                     remaining_bytes -= len(segment) | 
					
						
							|  |  |  |                 outf.write(segment) | 
					
						
							|  |  |  |                 byte_counter += len(segment) | 
					
						
							| 
									
										
										
										
											2014-09-25 09:21:45 +02:00
										 |  |  |                 if remaining_bytes is not None and remaining_bytes <= 0: | 
					
						
							| 
									
										
										
										
											2014-09-24 14:38:40 +02:00
										 |  |  |                     break | 
					
						
							| 
									
										
										
										
											2014-09-24 14:16:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self._hook_progress({ | 
					
						
							|  |  |  |             'downloaded_bytes': byte_counter, | 
					
						
							|  |  |  |             'total_bytes': byte_counter, | 
					
						
							|  |  |  |             'filename': filename, | 
					
						
							|  |  |  |             'status': 'finished', | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |         self.try_rename(tmpfilename, filename) | 
					
						
							|  |  |  |         return True |