1 from __future__ 
import unicode_literals
 
   8 from .common 
import FileDownloader
 
   9 from ..compat 
import compat_str
 
  18 def rtmpdump_version(): 
  19     return get_exe_version( 
  20         'rtmpdump', ['--help'], r
'(?i)RTMPDump\s*v?([0-9a-zA-Z._-]+)') 
  23 class RtmpFD(FileDownloader
): 
  24     def real_download(self
, filename
, info_dict
): 
  25         def run_rtmpdump(args
): 
  28             resume_downloaded_data_len 
= None 
  29             proc 
= subprocess
.Popen(args
, stderr
=subprocess
.PIPE
) 
  30             cursor_in_new_line 
= True 
  31             proc_stderr_closed 
= False 
  32             while not proc_stderr_closed
: 
  33                 # read line from stderr 
  36                     char 
= proc
.stderr
.read(1) 
  38                         proc_stderr_closed 
= True 
  40                     if char 
in [b
'\r', b
'\n']: 
  42                     line 
+= char
.decode('ascii', 'replace') 
  44                     # proc_stderr_closed is True 
  46                 mobj 
= re
.search(r
'([0-9]+\.[0-9]{3}) kB / [0-9]+\.[0-9]{2} sec \(([0-9]{1,2}\.[0-9])%\)', line
) 
  48                     downloaded_data_len 
= int(float(mobj
.group(1)) * 1024) 
  49                     percent 
= float(mobj
.group(2)) 
  50                     if not resume_percent
: 
  51                         resume_percent 
= percent
 
  52                         resume_downloaded_data_len 
= downloaded_data_len
 
  53                     time_now 
= time
.time() 
  54                     eta 
= self
.calc_eta(start
, time_now
, 100 - resume_percent
, percent 
- resume_percent
) 
  55                     speed 
= self
.calc_speed(start
, time_now
, downloaded_data_len 
- resume_downloaded_data_len
) 
  58                         data_len 
= int(downloaded_data_len 
* 100 / percent
) 
  60                         'status': 'downloading', 
  61                         'downloaded_bytes': downloaded_data_len
, 
  62                         'total_bytes_estimate': data_len
, 
  63                         'tmpfilename': tmpfilename
, 
  66                         'elapsed': time_now 
- start
, 
  69                     cursor_in_new_line 
= False 
  71                     # no percent for live streams 
  72                     mobj 
= re
.search(r
'([0-9]+\.[0-9]{3}) kB / [0-9]+\.[0-9]{2} sec', line
) 
  74                         downloaded_data_len 
= int(float(mobj
.group(1)) * 1024) 
  75                         time_now 
= time
.time() 
  76                         speed 
= self
.calc_speed(start
, time_now
, downloaded_data_len
) 
  78                             'downloaded_bytes': downloaded_data_len
, 
  79                             'tmpfilename': tmpfilename
, 
  81                             'status': 'downloading', 
  82                             'elapsed': time_now 
- start
, 
  85                         cursor_in_new_line 
= False 
  86                     elif self
.params
.get('verbose', False): 
  87                         if not cursor_in_new_line
: 
  89                         cursor_in_new_line 
= True 
  90                         self
.to_screen('[rtmpdump] ' + line
) 
  92             if not cursor_in_new_line
: 
  94             return proc
.returncode
 
  96         url 
= info_dict
['url'] 
  97         player_url 
= info_dict
.get('player_url', None) 
  98         page_url 
= info_dict
.get('page_url', None) 
  99         app 
= info_dict
.get('app', None) 
 100         play_path 
= info_dict
.get('play_path', None) 
 101         tc_url 
= info_dict
.get('tc_url', None) 
 102         flash_version 
= info_dict
.get('flash_version', None) 
 103         live 
= info_dict
.get('rtmp_live', False) 
 104         conn 
= info_dict
.get('rtmp_conn', None) 
 105         protocol 
= info_dict
.get('rtmp_protocol', None) 
 106         real_time 
= info_dict
.get('rtmp_real_time', False) 
 107         no_resume 
= info_dict
.get('no_resume', False) 
 108         continue_dl 
= info_dict
.get('continuedl', True) 
 110         self
.report_destination(filename
) 
 111         tmpfilename 
= self
.temp_name(filename
) 
 112         test 
= self
.params
.get('test', False) 
 114         # Check for rtmpdump first 
 115         if not check_executable('rtmpdump', ['-h']): 
 116             self
.report_error('RTMP download detected but "rtmpdump" could not be run. Please install it.') 
 119         # Download using rtmpdump. rtmpdump returns exit code 2 when 
 120         # the connection was interrumpted and resuming appears to be 
 121         # possible. This is part of rtmpdump's normal usage, AFAIK. 
 123             'rtmpdump', '--verbose', '-r', url
, 
 125         if player_url 
is not None: 
 126             basic_args 
+= ['--swfVfy', player_url
] 
 127         if page_url 
is not None: 
 128             basic_args 
+= ['--pageUrl', page_url
] 
 130             basic_args 
+= ['--app', app
] 
 131         if play_path 
is not None: 
 132             basic_args 
+= ['--playpath', play_path
] 
 133         if tc_url 
is not None: 
 134             basic_args 
+= ['--tcUrl', tc_url
] 
 136             basic_args 
+= ['--stop', '1'] 
 137         if flash_version 
is not None: 
 138             basic_args 
+= ['--flashVer', flash_version
] 
 140             basic_args 
+= ['--live'] 
 141         if isinstance(conn
, list): 
 143                 basic_args 
+= ['--conn', entry
] 
 144         elif isinstance(conn
, compat_str
): 
 145             basic_args 
+= ['--conn', conn
] 
 146         if protocol 
is not None: 
 147             basic_args 
+= ['--protocol', protocol
] 
 149             basic_args 
+= ['--realtime'] 
 152         if not no_resume 
and continue_dl 
and not live
: 
 154         if not live 
and continue_dl
: 
 155             args 
+= ['--skip', '1'] 
 157         args 
= [encodeArgument(a
) for a 
in args
] 
 159         self
._debug
_cmd
(args
, exe
='rtmpdump') 
 166         retval 
= run_rtmpdump(args
) 
 168         if retval 
== RD_NO_CONNECT
: 
 169             self
.report_error('[rtmpdump] Could not connect to RTMP server.') 
 172         while (retval 
== RD_INCOMPLETE 
or retval 
== RD_FAILED
) and not test 
and not live
: 
 173             prevsize 
= os
.path
.getsize(encodeFilename(tmpfilename
)) 
 174             self
.to_screen('[rtmpdump] %s bytes' % prevsize
) 
 175             time
.sleep(5.0)  # This seems to be needed 
 176             args 
= basic_args 
+ ['--resume'] 
 177             if retval 
== RD_FAILED
: 
 178                 args 
+= ['--skip', '1'] 
 179             args 
= [encodeArgument(a
) for a 
in args
] 
 180             retval 
= run_rtmpdump(args
) 
 181             cursize 
= os
.path
.getsize(encodeFilename(tmpfilename
)) 
 182             if prevsize 
== cursize 
and retval 
== RD_FAILED
: 
 184             # Some rtmp streams seem abort after ~ 99.8%. Don't complain for those 
 185             if prevsize 
== cursize 
and retval 
== RD_INCOMPLETE 
and cursize 
> 1024: 
 186                 self
.to_screen('[rtmpdump] Could not download the whole video. This can happen for some advertisements.') 
 189         if retval 
== RD_SUCCESS 
or (test 
and retval 
== RD_INCOMPLETE
): 
 190             fsize 
= os
.path
.getsize(encodeFilename(tmpfilename
)) 
 191             self
.to_screen('[rtmpdump] %s bytes' % fsize
) 
 192             self
.try_rename(tmpfilename
, filename
) 
 193             self
._hook
_progress
({ 
 194                 'downloaded_bytes': fsize
, 
 195                 'total_bytes': fsize
, 
 196                 'filename': filename
, 
 197                 'status': 'finished', 
 202             self
.report_error('rtmpdump exited with code %d' % retval
)