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 
  33                 while not proc_stderr_closed
: 
  34                     # read line from stderr 
  37                         char 
= proc
.stderr
.read(1) 
  39                             proc_stderr_closed 
= True 
  41                         if char 
in [b
'\r', b
'\n']: 
  43                         line 
+= char
.decode('ascii', 'replace') 
  45                         # proc_stderr_closed is True 
  47                     mobj 
= re
.search(r
'([0-9]+\.[0-9]{3}) kB / [0-9]+\.[0-9]{2} sec \(([0-9]{1,2}\.[0-9])%\)', line
) 
  49                         downloaded_data_len 
= int(float(mobj
.group(1)) * 1024) 
  50                         percent 
= float(mobj
.group(2)) 
  51                         if not resume_percent
: 
  52                             resume_percent 
= percent
 
  53                             resume_downloaded_data_len 
= downloaded_data_len
 
  54                         time_now 
= time
.time() 
  55                         eta 
= self
.calc_eta(start
, time_now
, 100 - resume_percent
, percent 
- resume_percent
) 
  56                         speed 
= self
.calc_speed(start
, time_now
, downloaded_data_len 
- resume_downloaded_data_len
) 
  59                             data_len 
= int(downloaded_data_len 
* 100 / percent
) 
  61                             'status': 'downloading', 
  62                             'downloaded_bytes': downloaded_data_len
, 
  63                             'total_bytes_estimate': data_len
, 
  64                             'tmpfilename': tmpfilename
, 
  67                             'elapsed': time_now 
- start
, 
  70                         cursor_in_new_line 
= False 
  72                         # no percent for live streams 
  73                         mobj 
= re
.search(r
'([0-9]+\.[0-9]{3}) kB / [0-9]+\.[0-9]{2} sec', line
) 
  75                             downloaded_data_len 
= int(float(mobj
.group(1)) * 1024) 
  76                             time_now 
= time
.time() 
  77                             speed 
= self
.calc_speed(start
, time_now
, downloaded_data_len
) 
  79                                 'downloaded_bytes': downloaded_data_len
, 
  80                                 'tmpfilename': tmpfilename
, 
  82                                 'status': 'downloading', 
  83                                 'elapsed': time_now 
- start
, 
  86                             cursor_in_new_line 
= False 
  87                         elif self
.params
.get('verbose', False): 
  88                             if not cursor_in_new_line
: 
  90                             cursor_in_new_line 
= True 
  91                             self
.to_screen('[rtmpdump] ' + line
) 
  94             if not cursor_in_new_line
: 
  96             return proc
.returncode
 
  98         url 
= info_dict
['url'] 
  99         player_url 
= info_dict
.get('player_url') 
 100         page_url 
= info_dict
.get('page_url') 
 101         app 
= info_dict
.get('app') 
 102         play_path 
= info_dict
.get('play_path') 
 103         tc_url 
= info_dict
.get('tc_url') 
 104         flash_version 
= info_dict
.get('flash_version') 
 105         live 
= info_dict
.get('rtmp_live', False) 
 106         conn 
= info_dict
.get('rtmp_conn') 
 107         protocol 
= info_dict
.get('rtmp_protocol') 
 108         real_time 
= info_dict
.get('rtmp_real_time', False) 
 109         no_resume 
= info_dict
.get('no_resume', False) 
 110         continue_dl 
= self
.params
.get('continuedl', True) 
 112         self
.report_destination(filename
) 
 113         tmpfilename 
= self
.temp_name(filename
) 
 114         test 
= self
.params
.get('test', False) 
 116         # Check for rtmpdump first 
 117         if not check_executable('rtmpdump', ['-h']): 
 118             self
.report_error('RTMP download detected but "rtmpdump" could not be run. Please install it.') 
 121         # Download using rtmpdump. rtmpdump returns exit code 2 when 
 122         # the connection was interrupted and resuming appears to be 
 123         # possible. This is part of rtmpdump's normal usage, AFAIK. 
 125             'rtmpdump', '--verbose', '-r', url
, 
 127         if player_url 
is not None: 
 128             basic_args 
+= ['--swfVfy', player_url
] 
 129         if page_url 
is not None: 
 130             basic_args 
+= ['--pageUrl', page_url
] 
 132             basic_args 
+= ['--app', app
] 
 133         if play_path 
is not None: 
 134             basic_args 
+= ['--playpath', play_path
] 
 135         if tc_url 
is not None: 
 136             basic_args 
+= ['--tcUrl', tc_url
] 
 138             basic_args 
+= ['--stop', '1'] 
 139         if flash_version 
is not None: 
 140             basic_args 
+= ['--flashVer', flash_version
] 
 142             basic_args 
+= ['--live'] 
 143         if isinstance(conn
, list): 
 145                 basic_args 
+= ['--conn', entry
] 
 146         elif isinstance(conn
, compat_str
): 
 147             basic_args 
+= ['--conn', conn
] 
 148         if protocol 
is not None: 
 149             basic_args 
+= ['--protocol', protocol
] 
 151             basic_args 
+= ['--realtime'] 
 154         if not no_resume 
and continue_dl 
and not live
: 
 156         if not live 
and continue_dl
: 
 157             args 
+= ['--skip', '1'] 
 159         args 
= [encodeArgument(a
) for a 
in args
] 
 161         self
._debug
_cmd
(args
, exe
='rtmpdump') 
 168         started 
= time
.time() 
 171             retval 
= run_rtmpdump(args
) 
 172         except KeyboardInterrupt: 
 173             if not info_dict
.get('is_live'): 
 176             self
.to_screen('\n[rtmpdump] Interrupted by user') 
 178         if retval 
== RD_NO_CONNECT
: 
 179             self
.report_error('[rtmpdump] Could not connect to RTMP server.') 
 182         while retval 
in (RD_INCOMPLETE
, RD_FAILED
) and not test 
and not live
: 
 183             prevsize 
= os
.path
.getsize(encodeFilename(tmpfilename
)) 
 184             self
.to_screen('[rtmpdump] Downloaded %s bytes' % prevsize
) 
 185             time
.sleep(5.0)  # This seems to be needed 
 186             args 
= basic_args 
+ ['--resume'] 
 187             if retval 
== RD_FAILED
: 
 188                 args 
+= ['--skip', '1'] 
 189             args 
= [encodeArgument(a
) for a 
in args
] 
 190             retval 
= run_rtmpdump(args
) 
 191             cursize 
= os
.path
.getsize(encodeFilename(tmpfilename
)) 
 192             if prevsize 
== cursize 
and retval 
== RD_FAILED
: 
 194             # Some rtmp streams seem abort after ~ 99.8%. Don't complain for those 
 195             if prevsize 
== cursize 
and retval 
== RD_INCOMPLETE 
and cursize 
> 1024: 
 196                 self
.to_screen('[rtmpdump] Could not download the whole video. This can happen for some advertisements.') 
 199         if retval 
== RD_SUCCESS 
or (test 
and retval 
== RD_INCOMPLETE
): 
 200             fsize 
= os
.path
.getsize(encodeFilename(tmpfilename
)) 
 201             self
.to_screen('[rtmpdump] Downloaded %s bytes' % fsize
) 
 202             self
.try_rename(tmpfilename
, filename
) 
 203             self
._hook
_progress
({ 
 204                 'downloaded_bytes': fsize
, 
 205                 'total_bytes': fsize
, 
 206                 'filename': filename
, 
 207                 'status': 'finished', 
 208                 'elapsed': time
.time() - started
, 
 213             self
.report_error('rtmpdump exited with code %d' % retval
)