nficano commited on
Commit
0e36a98
·
1 Parent(s): fc07806

add-trailing-comma

Browse files
.pre-commit-config.yaml CHANGED
@@ -20,3 +20,7 @@
20
  sha: v1.1.0
21
  hooks:
22
  - id: python-safety-dependencies-check
 
 
 
 
 
20
  sha: v1.1.0
21
  hooks:
22
  - id: python-safety-dependencies-check
23
+ - repo: https://github.com/asottile/add-trailing-comma
24
+ sha: v0.6.4
25
+ hooks:
26
+ - id: add-trailing-comma
pytube/__main__.py CHANGED
@@ -17,19 +17,19 @@ def main():
17
  parser = argparse.ArgumentParser(description='YouTube video downloader')
18
  parser.add_argument(
19
  'url',
20
- help='The URL of the Video to be downloaded'
21
  )
22
  parser.add_argument(
23
  '--extension',
24
  '-e',
25
  dest='ext',
26
- help='The requested format of the video'
27
  )
28
  parser.add_argument(
29
  '--resolution',
30
  '-r',
31
  dest='res',
32
- help='The requested resolution'
33
  )
34
  parser.add_argument(
35
  '--path',
@@ -37,7 +37,7 @@ def main():
37
  action=FullPaths,
38
  default=os.getcwd(),
39
  dest='path',
40
- help='The path to save the video to.'
41
  )
42
  parser.add_argument(
43
  '--filename',
@@ -50,7 +50,7 @@ def main():
50
  '-s',
51
  action='store_true',
52
  dest='show_available',
53
- help='Prints a list of available formats for download.'
54
  )
55
 
56
  args = parser.parse_args()
@@ -75,8 +75,10 @@ def main():
75
 
76
  if args.ext or args.res:
77
  if not all([args.ext, args.res]):
78
- print('Make sure you give either of the below specified '
79
- 'format/resolution combination.')
 
 
80
  print_available_vids(videos)
81
  sys.exit(1)
82
 
@@ -85,8 +87,10 @@ def main():
85
  vid = yt.get(args.ext, args.res)
86
  # Check if there's a video returned
87
  if not vid:
88
- print("There's no video with the specified format/resolution "
89
- 'combination.')
 
 
90
  pprint(videos)
91
  sys.exit(1)
92
 
@@ -104,8 +108,10 @@ def main():
104
  videos = yt.filter(resolution=args.res)
105
  # Check if we have a video
106
  if not videos:
107
- print('There are no videos in the specified in the specified '
108
- 'resolution.')
 
 
109
  sys.exit(1)
110
  # Select the highest resolution one
111
  vid = max(videos)
@@ -134,8 +140,10 @@ def print_available_vids(videos):
134
  formatString = '{:<2} {:<15} {:<15}'
135
  print(formatString.format('', 'Resolution', 'Extension'))
136
  print('-' * 28)
137
- print('\n'.join([formatString.format(index, *formatTuple)
138
- for index, formatTuple in enumerate(videos)]))
 
 
139
 
140
 
141
  if __name__ == '__main__':
 
17
  parser = argparse.ArgumentParser(description='YouTube video downloader')
18
  parser.add_argument(
19
  'url',
20
+ help='The URL of the Video to be downloaded',
21
  )
22
  parser.add_argument(
23
  '--extension',
24
  '-e',
25
  dest='ext',
26
+ help='The requested format of the video',
27
  )
28
  parser.add_argument(
29
  '--resolution',
30
  '-r',
31
  dest='res',
32
+ help='The requested resolution',
33
  )
34
  parser.add_argument(
35
  '--path',
 
37
  action=FullPaths,
38
  default=os.getcwd(),
39
  dest='path',
40
+ help='The path to save the video to.',
41
  )
42
  parser.add_argument(
43
  '--filename',
 
50
  '-s',
51
  action='store_true',
52
  dest='show_available',
53
+ help='Prints a list of available formats for download.',
54
  )
55
 
56
  args = parser.parse_args()
 
75
 
76
  if args.ext or args.res:
77
  if not all([args.ext, args.res]):
78
+ print(
79
+ 'Make sure you give either of the below specified '
80
+ 'format/resolution combination.',
81
+ )
82
  print_available_vids(videos)
83
  sys.exit(1)
84
 
 
87
  vid = yt.get(args.ext, args.res)
88
  # Check if there's a video returned
89
  if not vid:
90
+ print(
91
+ "There's no video with the specified format/resolution "
92
+ 'combination.',
93
+ )
94
  pprint(videos)
95
  sys.exit(1)
96
 
 
108
  videos = yt.filter(resolution=args.res)
109
  # Check if we have a video
110
  if not videos:
111
+ print(
112
+ 'There are no videos in the specified in the specified '
113
+ 'resolution.',
114
+ )
115
  sys.exit(1)
116
  # Select the highest resolution one
117
  vid = max(videos)
 
140
  formatString = '{:<2} {:<15} {:<15}'
141
  print(formatString.format('', 'Resolution', 'Extension'))
142
  print('-' * 28)
143
+ print('\n'.join([
144
+ formatString.format(index, *formatTuple)
145
+ for index, formatTuple in enumerate(videos)
146
+ ]))
147
 
148
 
149
  if __name__ == '__main__':
pytube/api.py CHANGED
@@ -67,7 +67,7 @@ QUALITY_PROFILES = {
67
  303: ('webm', '1080p HFR', 'vp9', 'n/a', '5', '', ''),
68
  308: ('webm', '1440p HFR', 'vp9', 'n/a', '10', '', ''),
69
  313: ('webm', '2160p', 'vp9', 'n/a', '13-15', '', ''),
70
- 315: ('webm', '2160p HFR', 'vp9', 'n/a', '20-25', '', '')
71
  }
72
 
73
  # The keys corresponding to the quality/codec map above.
@@ -78,7 +78,7 @@ QUALITY_PROFILE_KEYS = (
78
  'profile',
79
  'video_bitrate',
80
  'audio_codec',
81
- 'audio_bitrate'
82
  )
83
 
84
 
@@ -112,8 +112,10 @@ class YouTube(object):
112
  :param str url:
113
  The url to the YouTube video.
114
  """
115
- warnings.warn('url setter deprecated, use `from_url()` '
116
- 'instead.', DeprecationWarning)
 
 
117
  self.from_url(url)
118
 
119
  @property
@@ -144,8 +146,10 @@ class YouTube(object):
144
  :param str filename:
145
  The filename of the video.
146
  """
147
- warnings.warn('filename setter deprecated. Use `set_filename()` '
148
- 'instead.', DeprecationWarning)
 
 
149
  self.set_filename(filename)
150
 
151
  def set_filename(self, filename):
@@ -171,8 +175,10 @@ class YouTube(object):
171
  """Gets all videos. (This method is deprecated. Use `get_videos()`
172
  instead.
173
  """
174
- warnings.warn('videos property deprecated. Use `get_videos()` '
175
- 'instead.', DeprecationWarning)
 
 
176
  return self._videos
177
 
178
  def from_url(self, url):
@@ -222,8 +228,10 @@ class YouTube(object):
222
  # Check if we have the signature, otherwise we'll need to get the
223
  # cipher from the js.
224
  if 'signature=' not in url:
225
- log.debug('signature not in url, attempting to resolve the '
226
- 'cipher.')
 
 
227
  signature = self._get_cipher(stream_map['s'][i], js_url)
228
  url = '{0}&signature={1}'.format(url, signature)
229
  self._add_video(url, self.filename, **quality_profile)
@@ -300,8 +308,10 @@ class YouTube(object):
300
  restriction_pattern = bytes('og:restrictions:age', 'utf-8')
301
 
302
  if restriction_pattern in html:
303
- raise AgeRestricted('Age restricted video. Unable to download '
304
- 'without being signed in.')
 
 
305
 
306
  # Extract out the json data from the html response body.
307
  json_object = self._get_json_data(html)
@@ -309,9 +319,11 @@ class YouTube(object):
309
  # Here we decode the stream map and bundle it into the json object. We
310
  # do this just so we just can return one object for the video data.
311
  encoded_stream_map = json_object.get('args', {}).get(
312
- 'url_encoded_fmt_stream_map')
 
313
  json_object['args']['stream_map'] = self._parse_stream_map(
314
- encoded_stream_map)
 
315
  return json_object
316
 
317
  def _parse_stream_map(self, blob):
@@ -441,8 +453,10 @@ class YouTube(object):
441
  raise PytubeError('Unable to get encoding profile, no itag found.')
442
  elif len(itag) > 1:
443
  log.warn('Multiple itags found: %s', itag)
444
- raise PytubeError('Unable to get encoding profile, multiple itags '
445
- 'found.')
 
 
446
  return False
447
 
448
  def _add_video(self, url, filename, **kwargs):
 
67
  303: ('webm', '1080p HFR', 'vp9', 'n/a', '5', '', ''),
68
  308: ('webm', '1440p HFR', 'vp9', 'n/a', '10', '', ''),
69
  313: ('webm', '2160p', 'vp9', 'n/a', '13-15', '', ''),
70
+ 315: ('webm', '2160p HFR', 'vp9', 'n/a', '20-25', '', ''),
71
  }
72
 
73
  # The keys corresponding to the quality/codec map above.
 
78
  'profile',
79
  'video_bitrate',
80
  'audio_codec',
81
+ 'audio_bitrate',
82
  )
83
 
84
 
 
112
  :param str url:
113
  The url to the YouTube video.
114
  """
115
+ warnings.warn(
116
+ 'url setter deprecated, use `from_url()` '
117
+ 'instead.', DeprecationWarning,
118
+ )
119
  self.from_url(url)
120
 
121
  @property
 
146
  :param str filename:
147
  The filename of the video.
148
  """
149
+ warnings.warn(
150
+ 'filename setter deprecated. Use `set_filename()` '
151
+ 'instead.', DeprecationWarning,
152
+ )
153
  self.set_filename(filename)
154
 
155
  def set_filename(self, filename):
 
175
  """Gets all videos. (This method is deprecated. Use `get_videos()`
176
  instead.
177
  """
178
+ warnings.warn(
179
+ 'videos property deprecated. Use `get_videos()` '
180
+ 'instead.', DeprecationWarning,
181
+ )
182
  return self._videos
183
 
184
  def from_url(self, url):
 
228
  # Check if we have the signature, otherwise we'll need to get the
229
  # cipher from the js.
230
  if 'signature=' not in url:
231
+ log.debug(
232
+ 'signature not in url, attempting to resolve the '
233
+ 'cipher.',
234
+ )
235
  signature = self._get_cipher(stream_map['s'][i], js_url)
236
  url = '{0}&signature={1}'.format(url, signature)
237
  self._add_video(url, self.filename, **quality_profile)
 
308
  restriction_pattern = bytes('og:restrictions:age', 'utf-8')
309
 
310
  if restriction_pattern in html:
311
+ raise AgeRestricted(
312
+ 'Age restricted video. Unable to download '
313
+ 'without being signed in.',
314
+ )
315
 
316
  # Extract out the json data from the html response body.
317
  json_object = self._get_json_data(html)
 
319
  # Here we decode the stream map and bundle it into the json object. We
320
  # do this just so we just can return one object for the video data.
321
  encoded_stream_map = json_object.get('args', {}).get(
322
+ 'url_encoded_fmt_stream_map',
323
+ )
324
  json_object['args']['stream_map'] = self._parse_stream_map(
325
+ encoded_stream_map,
326
+ )
327
  return json_object
328
 
329
  def _parse_stream_map(self, blob):
 
453
  raise PytubeError('Unable to get encoding profile, no itag found.')
454
  elif len(itag) > 1:
455
  log.warn('Multiple itags found: %s', itag)
456
+ raise PytubeError(
457
+ 'Unable to get encoding profile, multiple itags '
458
+ 'found.',
459
+ )
460
  return False
461
 
462
  def _add_video(self, url, filename, **kwargs):
pytube/jsinterp.py CHANGED
@@ -71,7 +71,8 @@ class JSInterpreter(object):
71
  if parens_count == 0:
72
  sub_expr = expr[1:m.start()]
73
  sub_result = self.interpret_expression(
74
- sub_expr, local_vars, allow_recursion)
 
75
  remaining_expr = expr[m.end():].strip()
76
  if not remaining_expr:
77
  return sub_result
@@ -82,19 +83,23 @@ class JSInterpreter(object):
82
  raise ExtractorError('Premature end of parens in %r' % expr)
83
 
84
  for op, opfunc in _ASSIGN_OPERATORS:
85
- m = re.match(r'''(?x)
 
86
  (?P<out>%s)(?:\[(?P<index>[^\]]+?)\])?
87
  \s*%s
88
- (?P<expr>.*)$''' % (_NAME_RE, re.escape(op)), expr)
 
89
  if not m:
90
  continue
91
  right_val = self.interpret_expression(
92
- m.group('expr'), local_vars, allow_recursion - 1)
 
93
 
94
  if m.groupdict().get('index'):
95
  lvar = local_vars[m.group('out')]
96
  idx = self.interpret_expression(
97
- m.group('index'), local_vars, allow_recursion)
 
98
  assert isinstance(idx, int)
99
  cur = lvar[idx]
100
  val = opfunc(cur, right_val)
@@ -111,7 +116,8 @@ class JSInterpreter(object):
111
 
112
  var_m = re.match(
113
  r'(?!if|return|true|false)(?P<name>%s)$' % _NAME_RE,
114
- expr)
 
115
  if var_m:
116
  return local_vars[var_m.group('name')]
117
 
@@ -123,7 +129,8 @@ class JSInterpreter(object):
123
  m = re.match(
124
  r'(?P<var>%s)\.(?P<member>[^(]+)'
125
  '(?:\(+(?P<args>[^()]*)\))?$' % _NAME_RE,
126
- expr)
 
127
  if m:
128
  variable = m.group('var')
129
  member = m.group('member')
@@ -149,7 +156,8 @@ class JSInterpreter(object):
149
  else:
150
  argvals = tuple([
151
  self.interpret_expression(v, local_vars, allow_recursion)
152
- for v in arg_str.split(',')])
 
153
 
154
  if member == 'split':
155
  assert argvals == ('',)
@@ -175,11 +183,13 @@ class JSInterpreter(object):
175
  return obj[member](argvals)
176
 
177
  m = re.match(
178
- r'(?P<in>%s)\[(?P<idx>.+)\]$' % _NAME_RE, expr)
 
179
  if m:
180
  val = local_vars[m.group('in')]
181
  idx = self.interpret_expression(
182
- m.group('idx'), local_vars, allow_recursion - 1)
 
183
  return val[idx]
184
 
185
  for op, opfunc in _OPERATORS:
@@ -187,24 +197,30 @@ class JSInterpreter(object):
187
  if not m:
188
  continue
189
  x, abort = self.interpret_statement(
190
- m.group('x'), local_vars, allow_recursion - 1)
 
191
  if abort:
192
  raise ExtractorError(
193
- 'Premature left-side return of %s in %r' % (op, expr))
 
194
  y, abort = self.interpret_statement(
195
- m.group('y'), local_vars, allow_recursion - 1)
 
196
  if abort:
197
  raise ExtractorError(
198
- 'Premature right-side return of %s in %r' % (op, expr))
 
199
  return opfunc(x, y)
200
 
201
  m = re.match(
202
- r'^(?P<func>%s)\((?P<args>[a-zA-Z0-9_$,]+)\)$' % _NAME_RE, expr)
 
203
  if m:
204
  fname = m.group('func')
205
  argvals = tuple([
206
  int(v) if v.isdigit() else local_vars[v]
207
- for v in m.group('args').split(',')])
 
208
  if fname not in self._functions:
209
  self._functions[fname] = self.extract_function(fname)
210
  return self._functions[fname](argvals)
@@ -217,17 +233,20 @@ class JSInterpreter(object):
217
  (r'(?:var\s+)?%s\s*=\s*\{' % re.escape(objname)) +
218
  r'\s*(?P<fields>([a-zA-Z$0-9]+\s*:\s*function\(.*?\)\s*\{.*?\}'
219
  r'(?:,\s*)?)*)' + r'\}\s*;',
220
- self.code)
 
221
  fields = obj_m.group('fields')
222
  # Currently, it only supports function definitions
223
  fields_m = re.finditer(
224
  r'(?P<key>[a-zA-Z$0-9]+)\s*:\s*function'
225
  r'\((?P<args>[a-z,]+)\){(?P<code>[^}]+)}',
226
- fields)
 
227
  for f in fields_m:
228
  argnames = f.group('args').split(',')
229
  obj[f.group('key')] = self.build_function(
230
- argnames, f.group('code'))
 
231
 
232
  return obj
233
 
@@ -237,8 +256,10 @@ class JSInterpreter(object):
237
  (?:function\s+%s|[{;,]\s*%s\s*=\s*function|var\s+%s\s*=\s*function)\s*
238
  \((?P<args>[^)]*)\)\s*
239
  \{(?P<code>[^}]+)\}''' % (
240
- re.escape(funcname), re.escape(funcname), re.escape(funcname)),
241
- self.code)
 
 
242
  if func_m is None:
243
  raise ExtractorError('Could not find JS function %r' % funcname)
244
  argnames = func_m.group('args').split(',')
 
71
  if parens_count == 0:
72
  sub_expr = expr[1:m.start()]
73
  sub_result = self.interpret_expression(
74
+ sub_expr, local_vars, allow_recursion,
75
+ )
76
  remaining_expr = expr[m.end():].strip()
77
  if not remaining_expr:
78
  return sub_result
 
83
  raise ExtractorError('Premature end of parens in %r' % expr)
84
 
85
  for op, opfunc in _ASSIGN_OPERATORS:
86
+ m = re.match(
87
+ r'''(?x)
88
  (?P<out>%s)(?:\[(?P<index>[^\]]+?)\])?
89
  \s*%s
90
+ (?P<expr>.*)$''' % (_NAME_RE, re.escape(op)), expr,
91
+ )
92
  if not m:
93
  continue
94
  right_val = self.interpret_expression(
95
+ m.group('expr'), local_vars, allow_recursion - 1,
96
+ )
97
 
98
  if m.groupdict().get('index'):
99
  lvar = local_vars[m.group('out')]
100
  idx = self.interpret_expression(
101
+ m.group('index'), local_vars, allow_recursion,
102
+ )
103
  assert isinstance(idx, int)
104
  cur = lvar[idx]
105
  val = opfunc(cur, right_val)
 
116
 
117
  var_m = re.match(
118
  r'(?!if|return|true|false)(?P<name>%s)$' % _NAME_RE,
119
+ expr,
120
+ )
121
  if var_m:
122
  return local_vars[var_m.group('name')]
123
 
 
129
  m = re.match(
130
  r'(?P<var>%s)\.(?P<member>[^(]+)'
131
  '(?:\(+(?P<args>[^()]*)\))?$' % _NAME_RE,
132
+ expr,
133
+ )
134
  if m:
135
  variable = m.group('var')
136
  member = m.group('member')
 
156
  else:
157
  argvals = tuple([
158
  self.interpret_expression(v, local_vars, allow_recursion)
159
+ for v in arg_str.split(',')
160
+ ])
161
 
162
  if member == 'split':
163
  assert argvals == ('',)
 
183
  return obj[member](argvals)
184
 
185
  m = re.match(
186
+ r'(?P<in>%s)\[(?P<idx>.+)\]$' % _NAME_RE, expr,
187
+ )
188
  if m:
189
  val = local_vars[m.group('in')]
190
  idx = self.interpret_expression(
191
+ m.group('idx'), local_vars, allow_recursion - 1,
192
+ )
193
  return val[idx]
194
 
195
  for op, opfunc in _OPERATORS:
 
197
  if not m:
198
  continue
199
  x, abort = self.interpret_statement(
200
+ m.group('x'), local_vars, allow_recursion - 1,
201
+ )
202
  if abort:
203
  raise ExtractorError(
204
+ 'Premature left-side return of %s in %r' % (op, expr),
205
+ )
206
  y, abort = self.interpret_statement(
207
+ m.group('y'), local_vars, allow_recursion - 1,
208
+ )
209
  if abort:
210
  raise ExtractorError(
211
+ 'Premature right-side return of %s in %r' % (op, expr),
212
+ )
213
  return opfunc(x, y)
214
 
215
  m = re.match(
216
+ r'^(?P<func>%s)\((?P<args>[a-zA-Z0-9_$,]+)\)$' % _NAME_RE, expr,
217
+ )
218
  if m:
219
  fname = m.group('func')
220
  argvals = tuple([
221
  int(v) if v.isdigit() else local_vars[v]
222
+ for v in m.group('args').split(',')
223
+ ])
224
  if fname not in self._functions:
225
  self._functions[fname] = self.extract_function(fname)
226
  return self._functions[fname](argvals)
 
233
  (r'(?:var\s+)?%s\s*=\s*\{' % re.escape(objname)) +
234
  r'\s*(?P<fields>([a-zA-Z$0-9]+\s*:\s*function\(.*?\)\s*\{.*?\}'
235
  r'(?:,\s*)?)*)' + r'\}\s*;',
236
+ self.code,
237
+ )
238
  fields = obj_m.group('fields')
239
  # Currently, it only supports function definitions
240
  fields_m = re.finditer(
241
  r'(?P<key>[a-zA-Z$0-9]+)\s*:\s*function'
242
  r'\((?P<args>[a-z,]+)\){(?P<code>[^}]+)}',
243
+ fields,
244
+ )
245
  for f in fields_m:
246
  argnames = f.group('args').split(',')
247
  obj[f.group('key')] = self.build_function(
248
+ argnames, f.group('code'),
249
+ )
250
 
251
  return obj
252
 
 
256
  (?:function\s+%s|[{;,]\s*%s\s*=\s*function|var\s+%s\s*=\s*function)\s*
257
  \((?P<args>[^)]*)\)\s*
258
  \{(?P<code>[^}]+)\}''' % (
259
+ re.escape(funcname), re.escape(funcname), re.escape(funcname),
260
+ ),
261
+ self.code,
262
+ )
263
  if func_m is None:
264
  raise ExtractorError('Could not find JS function %r' % funcname)
265
  argnames = func_m.group('args').split(',')
pytube/models.py CHANGED
@@ -15,9 +15,11 @@ class Video(object):
15
  """Class representation of a single instance of a YouTube video.
16
  """
17
 
18
- def __init__(self, url, filename, extension, resolution=None,
19
- video_codec=None, profile=None, video_bitrate=None,
20
- audio_codec=None, audio_bitrate=None):
 
 
21
  """Sets-up the video object.
22
 
23
  :param str url:
@@ -49,8 +51,10 @@ class Video(object):
49
  self.audio_codec = audio_codec
50
  self.audio_bitrate = audio_bitrate
51
 
52
- def download(self, path, chunk_size=8 * 1024, on_progress=None,
53
- on_finish=None, force_overwrite=False):
 
 
54
  """Downloads the video.
55
 
56
  :param str path:
@@ -110,7 +114,8 @@ class Video(object):
110
  # to disable this.
111
  os.remove(path)
112
  raise KeyboardInterrupt(
113
- 'Interrupt signal given. Deleting incomplete video.')
 
114
 
115
  def file_size(self, response):
116
  """Gets the file size from the response
@@ -125,7 +130,8 @@ class Video(object):
125
  def __repr__(self):
126
  """A clean representation of the class instance."""
127
  return '<Video: {0} (.{1}) - {2} - {3}>'.format(
128
- self.video_codec, self.extension, self.resolution, self.profile)
 
129
 
130
  def __lt__(self, other):
131
  """The "less than" (lt) method is used for comparing video object to
 
15
  """Class representation of a single instance of a YouTube video.
16
  """
17
 
18
+ def __init__(
19
+ self, url, filename, extension, resolution=None,
20
+ video_codec=None, profile=None, video_bitrate=None,
21
+ audio_codec=None, audio_bitrate=None,
22
+ ):
23
  """Sets-up the video object.
24
 
25
  :param str url:
 
51
  self.audio_codec = audio_codec
52
  self.audio_bitrate = audio_bitrate
53
 
54
+ def download(
55
+ self, path, chunk_size=8 * 1024, on_progress=None,
56
+ on_finish=None, force_overwrite=False,
57
+ ):
58
  """Downloads the video.
59
 
60
  :param str path:
 
114
  # to disable this.
115
  os.remove(path)
116
  raise KeyboardInterrupt(
117
+ 'Interrupt signal given. Deleting incomplete video.',
118
+ )
119
 
120
  def file_size(self, response):
121
  """Gets the file size from the response
 
130
  def __repr__(self):
131
  """A clean representation of the class instance."""
132
  return '<Video: {0} (.{1}) - {2} - {3}>'.format(
133
+ self.video_codec, self.extension, self.resolution, self.profile,
134
+ )
135
 
136
  def __lt__(self, other):
137
  """The "less than" (lt) method is used for comparing video object to
pytube/utils.py CHANGED
@@ -34,8 +34,10 @@ def safe_filename(text, max_length=200):
34
 
35
  # Removing these SHOULD make most filename safe for a wide range of
36
  # operating systems.
37
- paranoid = ['\"', '\#', '\$', '\%', '\'', '\*', '\,', '\.', '\/', '\:',
38
- '\;', '\<', '\>', '\?', '\\', '\^', '\|', '\~', '\\\\']
 
 
39
 
40
  blacklist = re.compile('|'.join(ntfs + paranoid), re.UNICODE)
41
  filename = blacklist.sub('', text)
@@ -73,6 +75,8 @@ def print_status(progress, file_size, start):
73
  dt = (clock() - start)
74
  if dt > 0:
75
  stdout.write('\r [%s%s][%3.2f%%] %s at %s/s ' %
76
- ('=' * done, ' ' * (50 - done), percent_done,
77
- sizeof(file_size), sizeof(progress // dt)))
 
 
78
  stdout.flush()
 
34
 
35
  # Removing these SHOULD make most filename safe for a wide range of
36
  # operating systems.
37
+ paranoid = [
38
+ '\"', '\#', '\$', '\%', '\'', '\*', '\,', '\.', '\/', '\:',
39
+ '\;', '\<', '\>', '\?', '\\', '\^', '\|', '\~', '\\\\',
40
+ ]
41
 
42
  blacklist = re.compile('|'.join(ntfs + paranoid), re.UNICODE)
43
  filename = blacklist.sub('', text)
 
75
  dt = (clock() - start)
76
  if dt > 0:
77
  stdout.write('\r [%s%s][%3.2f%%] %s at %s/s ' %
78
+ (
79
+ '=' * done, ' ' * (50 - done), percent_done,
80
+ sizeof(file_size), sizeof(progress // dt),
81
+ ))
82
  stdout.flush()