]>
Raphaƫl G. Git Repositories - youtubedl/blob - youtube_dl/downloader/hls.py
   1 from __future__ 
import unicode_literals
 
   8 from .common 
import FileDownloader
 
   9 from .fragment 
import FragmentFD
 
  11 from ..compat 
import compat_urlparse
 
  12 from ..postprocessor
.ffmpeg 
import FFmpegPostProcessor
 
  17     handle_youtubedl_headers
, 
  21 class HlsFD(FileDownloader
): 
  22     def real_download(self
, filename
, info_dict
): 
  23         url 
= info_dict
['url'] 
  24         self
.report_destination(filename
) 
  25         tmpfilename 
= self
.temp_name(filename
) 
  27         ffpp 
= FFmpegPostProcessor(downloader
=self
) 
  28         if not ffpp
.available
: 
  29             self
.report_error('m3u8 download detected but ffmpeg or avconv could not be found. Please install one.') 
  33         args 
= [ffpp
.executable
, '-y'] 
  35         if info_dict
['http_headers'] and re
.match(r
'^https?://', url
): 
  36             # Trailing \r\n after each HTTP header is important to prevent warning from ffmpeg/avconv: 
  37             # [http @ 00000000003d2fa0] No trailing CRLF found in HTTP header. 
  38             headers 
= handle_youtubedl_headers(info_dict
['http_headers']) 
  41                 ''.join('%s: %s\r\n' % (key
, val
) for key
, val 
in headers
.items())] 
  43         args 
+= ['-i', url
, '-c', 'copy'] 
  44         if self
.params
.get('hls_use_mpegts', False): 
  45             args 
+= ['-f', 'mpegts'] 
  47             args 
+= ['-f', 'mp4', '-bsf:a', 'aac_adtstoasc'] 
  49         args 
= [encodeArgument(opt
) for opt 
in args
] 
  50         args
.append(encodeFilename(ffpp
._ffmpeg
_filename
_argument
(tmpfilename
), True)) 
  54         proc 
= subprocess
.Popen(args
, stdin
=subprocess
.PIPE
) 
  57         except KeyboardInterrupt: 
  58             # subprocces.run would send the SIGKILL signal to ffmpeg and the 
  59             # mp4 file couldn't be played, but if we ask ffmpeg to quit it 
  60             # produces a file that is playable (this is mostly useful for live 
  61             # streams). Note that Windows is not affected and produces playable 
  62             # files (see https://github.com/rg3/youtube-dl/issues/8300). 
  63             if sys
.platform 
!= 'win32': 
  64                 proc
.communicate(b
'q') 
  67             fsize 
= os
.path
.getsize(encodeFilename(tmpfilename
)) 
  68             self
.to_screen('\r[%s] %s bytes' % (args
[0], fsize
)) 
  69             self
.try_rename(tmpfilename
, filename
) 
  71                 'downloaded_bytes': fsize
, 
  79             self
.report_error('%s exited with code %d' % (ffpp
.basename
, retval
)) 
  83 class NativeHlsFD(FragmentFD
): 
  84     """ A more limited implementation that does not require ffmpeg """ 
  88     def real_download(self
, filename
, info_dict
): 
  89         man_url 
= info_dict
['url'] 
  90         self
.to_screen('[%s] Downloading m3u8 manifest' % self
.FD_NAME
) 
  91         manifest 
= self
.ydl
.urlopen(man_url
).read() 
  93         s 
= manifest
.decode('utf-8', 'ignore') 
  95         for line 
in s
.splitlines(): 
  97             if line 
and not line
.startswith('#'): 
 100                     if re
.match(r
'^https?://', line
) 
 101                     else compat_urlparse
.urljoin(man_url
, line
)) 
 102                 fragment_urls
.append(segment_url
) 
 103                 # We only download the first fragment during the test 
 104                 if self
.params
.get('test', False): 
 108             'filename': filename
, 
 109             'total_frags': len(fragment_urls
), 
 112         self
._prepare
_and
_start
_frag
_download
(ctx
) 
 115         for i
, frag_url 
in enumerate(fragment_urls
): 
 116             frag_filename 
= '%s-Frag%d' % (ctx
['tmpfilename'], i
) 
 117             success 
= ctx
['dl'].download(frag_filename
, {'url': frag_url
}) 
 120             down
, frag_sanitized 
= sanitize_open(frag_filename
, 'rb') 
 121             ctx
['dest_stream'].write(down
.read()) 
 123             frags_filenames
.append(frag_sanitized
) 
 125         self
._finish
_frag
_download
(ctx
) 
 127         for frag_file 
in frags_filenames
: 
 128             os
.remove(encodeFilename(frag_file
))