]> gitweb @ CieloNegro.org - youtube-dl.git/blob - youtube_dl/__init__.py
[configuration] Undo code breakage
[youtube-dl.git] / youtube_dl / __init__.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 __authors__  = (
5     'Ricardo Garcia Gonzalez',
6     'Danny Colligan',
7     'Benjamin Johnson',
8     'Vasyl\' Vavrychuk',
9     'Witold Baryluk',
10     'Paweł Paprota',
11     'Gergely Imreh',
12     'Rogério Brito',
13     'Philipp Hagemeister',
14     'Sören Schulze',
15     'Kevin Ngo',
16     'Ori Avtalion',
17     'shizeeg',
18     'Filippo Valsorda',
19     'Christian Albrecht',
20     'Dave Vasilevsky',
21     'Jaime Marquínez Ferrándiz',
22     'Jeff Crouse',
23     'Osama Khalid',
24     'Michael Walter',
25     'M. Yasoob Ullah Khalid',
26     'Julien Fraichard',
27     'Johny Mo Swag',
28     'Axel Noack',
29     'Albert Kim',
30     'Pierre Rudloff',
31     'Huarong Huo',
32     'Ismael Mejía',
33     'Steffan \'Ruirize\' James',
34     'Andras Elso',
35     'Jelle van der Waa',
36     'Marcin Cieślak',
37     'Anton Larionov',
38     'Takuya Tsuchida',
39     'Sergey M.',
40 )
41
42 __license__ = 'Public Domain'
43
44 import codecs
45 import getpass
46 import optparse
47 import os
48 import random
49 import re
50 import shlex
51 import subprocess
52 import sys
53
54
55 from .utils import (
56     compat_print,
57     DateRange,
58     decodeOption,
59     determine_ext,
60     DownloadError,
61     get_cachedir,
62     MaxDownloadsReached,
63     preferredencoding,
64     SameFileError,
65     std_headers,
66     write_string,
67 )
68 from .update import update_self
69 from .FileDownloader import (
70     FileDownloader,
71 )
72 from .extractor import gen_extractors
73 from .version import __version__
74 from .YoutubeDL import YoutubeDL
75 from .PostProcessor import (
76     FFmpegMetadataPP,
77     FFmpegVideoConvertor,
78     FFmpegExtractAudioPP,
79     FFmpegEmbedSubtitlePP,
80 )
81
82
83 def parseOpts(overrideArguments=None):
84     def _readOptions(filename_bytes, default=[]):
85         try:
86             optionf = open(filename_bytes)
87         except IOError:
88             return default  # silently skip if file is not present
89         try:
90             res = []
91             for l in optionf:
92                 res += shlex.split(l, comments=True)
93         finally:
94             optionf.close()
95         return res
96
97     def _format_option_string(option):
98         ''' ('-o', '--option') -> -o, --format METAVAR'''
99
100         opts = []
101
102         if option._short_opts:
103             opts.append(option._short_opts[0])
104         if option._long_opts:
105             opts.append(option._long_opts[0])
106         if len(opts) > 1:
107             opts.insert(1, ', ')
108
109         if option.takes_value(): opts.append(' %s' % option.metavar)
110
111         return "".join(opts)
112
113     def _comma_separated_values_options_callback(option, opt_str, value, parser):
114         setattr(parser.values, option.dest, value.split(','))
115
116     def _find_term_columns():
117         columns = os.environ.get('COLUMNS', None)
118         if columns:
119             return int(columns)
120
121         try:
122             sp = subprocess.Popen(['stty', 'size'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
123             out,err = sp.communicate()
124             return int(out.split()[1])
125         except:
126             pass
127         return None
128
129     def _hide_login_info(opts):
130         opts = list(opts)
131         for private_opt in ['-p', '--password', '-u', '--username', '--video-password']:
132             try:
133                 i = opts.index(private_opt)
134                 opts[i+1] = '<PRIVATE>'
135             except ValueError:
136                 pass
137         return opts
138
139     max_width = 80
140     max_help_position = 80
141
142     # No need to wrap help messages if we're on a wide console
143     columns = _find_term_columns()
144     if columns: max_width = columns
145
146     fmt = optparse.IndentedHelpFormatter(width=max_width, max_help_position=max_help_position)
147     fmt.format_option_strings = _format_option_string
148
149     kw = {
150         'version'   : __version__,
151         'formatter' : fmt,
152         'usage' : '%prog [options] url [url...]',
153         'conflict_handler' : 'resolve',
154     }
155
156     parser = optparse.OptionParser(**kw)
157
158     # option groups
159     general        = optparse.OptionGroup(parser, 'General Options')
160     selection      = optparse.OptionGroup(parser, 'Video Selection')
161     authentication = optparse.OptionGroup(parser, 'Authentication Options')
162     video_format   = optparse.OptionGroup(parser, 'Video Format Options')
163     subtitles      = optparse.OptionGroup(parser, 'Subtitle Options')
164     downloader     = optparse.OptionGroup(parser, 'Download Options')
165     postproc       = optparse.OptionGroup(parser, 'Post-processing Options')
166     filesystem     = optparse.OptionGroup(parser, 'Filesystem Options')
167     verbosity      = optparse.OptionGroup(parser, 'Verbosity / Simulation Options')
168
169     general.add_option('-h', '--help',
170             action='help', help='print this help text and exit')
171     general.add_option('-v', '--version',
172             action='version', help='print program version and exit')
173     general.add_option('-U', '--update',
174             action='store_true', dest='update_self', help='update this program to latest version. Make sure that you have sufficient permissions (run with sudo if needed)')
175     general.add_option('-i', '--ignore-errors',
176             action='store_true', dest='ignoreerrors', help='continue on download errors, for example to to skip unavailable videos in a playlist', default=False)
177     general.add_option('--abort-on-error',
178             action='store_false', dest='ignoreerrors',
179             help='Abort downloading of further videos (in the playlist or the command line) if an error occurs')
180     general.add_option('--dump-user-agent',
181             action='store_true', dest='dump_user_agent',
182             help='display the current browser identification', default=False)
183     general.add_option('--user-agent',
184             dest='user_agent', help='specify a custom user agent', metavar='UA')
185     general.add_option('--referer',
186             dest='referer', help='specify a custom referer, use if the video access is restricted to one domain',
187             metavar='REF', default=None)
188     general.add_option('--list-extractors',
189             action='store_true', dest='list_extractors',
190             help='List all supported extractors and the URLs they would handle', default=False)
191     general.add_option('--extractor-descriptions',
192             action='store_true', dest='list_extractor_descriptions',
193             help='Output descriptions of all supported extractors', default=False)
194     general.add_option('--proxy', dest='proxy', default=None, help='Use the specified HTTP/HTTPS proxy', metavar='URL')
195     general.add_option('--no-check-certificate', action='store_true', dest='no_check_certificate', default=False, help='Suppress HTTPS certificate validation.')
196     general.add_option(
197         '--cache-dir', dest='cachedir', default=get_cachedir(), metavar='DIR',
198         help='Location in the filesystem where youtube-dl can store downloaded information permanently. By default $XDG_CACHE_HOME/youtube-dl or ~/.cache/youtube-dl .')
199     general.add_option(
200         '--no-cache-dir', action='store_const', const=None, dest='cachedir',
201         help='Disable filesystem caching')
202     general.add_option(
203         '--socket-timeout', dest='socket_timeout',
204         type=float, default=None, help=optparse.SUPPRESS_HELP)
205
206
207     selection.add_option('--playlist-start',
208             dest='playliststart', metavar='NUMBER', help='playlist video to start at (default is %default)', default=1)
209     selection.add_option('--playlist-end',
210             dest='playlistend', metavar='NUMBER', help='playlist video to end at (default is last)', default=-1)
211     selection.add_option('--match-title', dest='matchtitle', metavar='REGEX',help='download only matching titles (regex or caseless sub-string)')
212     selection.add_option('--reject-title', dest='rejecttitle', metavar='REGEX',help='skip download for matching titles (regex or caseless sub-string)')
213     selection.add_option('--max-downloads', metavar='NUMBER',
214                          dest='max_downloads', type=int, default=None,
215                          help='Abort after downloading NUMBER files')
216     selection.add_option('--min-filesize', metavar='SIZE', dest='min_filesize', help="Do not download any videos smaller than SIZE (e.g. 50k or 44.6m)", default=None)
217     selection.add_option('--max-filesize', metavar='SIZE', dest='max_filesize', help="Do not download any videos larger than SIZE (e.g. 50k or 44.6m)", default=None)
218     selection.add_option('--date', metavar='DATE', dest='date', help='download only videos uploaded in this date', default=None)
219     selection.add_option('--datebefore', metavar='DATE', dest='datebefore', help='download only videos uploaded before this date', default=None)
220     selection.add_option('--dateafter', metavar='DATE', dest='dateafter', help='download only videos uploaded after this date', default=None)
221     selection.add_option('--no-playlist', action='store_true', dest='noplaylist', help='download only the currently playing video', default=False)
222     selection.add_option('--age-limit', metavar='YEARS', dest='age_limit',
223                          help='download only videos suitable for the given age',
224                          default=None, type=int)
225     selection.add_option('--download-archive', metavar='FILE',
226                          dest='download_archive',
227                          help='Download only videos not listed in the archive file. Record the IDs of all downloaded videos in it.')
228
229
230     authentication.add_option('-u', '--username',
231             dest='username', metavar='USERNAME', help='account username')
232     authentication.add_option('-p', '--password',
233             dest='password', metavar='PASSWORD', help='account password')
234     authentication.add_option('-n', '--netrc',
235             action='store_true', dest='usenetrc', help='use .netrc authentication data', default=False)
236     authentication.add_option('--video-password',
237             dest='videopassword', metavar='PASSWORD', help='video password (vimeo only)')
238
239
240     video_format.add_option('-f', '--format',
241             action='store', dest='format', metavar='FORMAT', default='best',
242             help='video format code, specify the order of preference using slashes: "-f 22/17/18". "-f mp4" and "-f flv" are also supported')
243     video_format.add_option('--all-formats',
244             action='store_const', dest='format', help='download all available video formats', const='all')
245     video_format.add_option('--prefer-free-formats',
246             action='store_true', dest='prefer_free_formats', default=False, help='prefer free video formats unless a specific one is requested')
247     video_format.add_option('--max-quality',
248             action='store', dest='format_limit', metavar='FORMAT', help='highest quality format to download')
249     video_format.add_option('-F', '--list-formats',
250             action='store_true', dest='listformats', help='list all available formats (currently youtube only)')
251
252     subtitles.add_option('--write-sub', '--write-srt',
253             action='store_true', dest='writesubtitles',
254             help='write subtitle file', default=False)
255     subtitles.add_option('--write-auto-sub', '--write-automatic-sub',
256             action='store_true', dest='writeautomaticsub',
257             help='write automatic subtitle file (youtube only)', default=False)
258     subtitles.add_option('--all-subs',
259             action='store_true', dest='allsubtitles',
260             help='downloads all the available subtitles of the video', default=False)
261     subtitles.add_option('--list-subs',
262             action='store_true', dest='listsubtitles',
263             help='lists all available subtitles for the video', default=False)
264     subtitles.add_option('--sub-format',
265             action='store', dest='subtitlesformat', metavar='FORMAT',
266             help='subtitle format (default=srt) ([sbv/vtt] youtube only)', default='srt')
267     subtitles.add_option('--sub-lang', '--sub-langs', '--srt-lang',
268             action='callback', dest='subtitleslangs', metavar='LANGS', type='str',
269             default=[], callback=_comma_separated_values_options_callback,
270             help='languages of the subtitles to download (optional) separated by commas, use IETF language tags like \'en,pt\'')
271
272     downloader.add_option('-r', '--rate-limit',
273             dest='ratelimit', metavar='LIMIT', help='maximum download rate in bytes per second (e.g. 50K or 4.2M)')
274     downloader.add_option('-R', '--retries',
275             dest='retries', metavar='RETRIES', help='number of retries (default is %default)', default=10)
276     downloader.add_option('--buffer-size',
277             dest='buffersize', metavar='SIZE', help='size of download buffer (e.g. 1024 or 16K) (default is %default)', default="1024")
278     downloader.add_option('--no-resize-buffer',
279             action='store_true', dest='noresizebuffer',
280             help='do not automatically adjust the buffer size. By default, the buffer size is automatically resized from an initial value of SIZE.', default=False)
281     downloader.add_option('--test', action='store_true', dest='test', default=False, help=optparse.SUPPRESS_HELP)
282
283     verbosity.add_option('-q', '--quiet',
284             action='store_true', dest='quiet', help='activates quiet mode', default=False)
285     verbosity.add_option('-s', '--simulate',
286             action='store_true', dest='simulate', help='do not download the video and do not write anything to disk', default=False)
287     verbosity.add_option('--skip-download',
288             action='store_true', dest='skip_download', help='do not download the video', default=False)
289     verbosity.add_option('-g', '--get-url',
290             action='store_true', dest='geturl', help='simulate, quiet but print URL', default=False)
291     verbosity.add_option('-e', '--get-title',
292             action='store_true', dest='gettitle', help='simulate, quiet but print title', default=False)
293     verbosity.add_option('--get-id',
294             action='store_true', dest='getid', help='simulate, quiet but print id', default=False)
295     verbosity.add_option('--get-thumbnail',
296             action='store_true', dest='getthumbnail',
297             help='simulate, quiet but print thumbnail URL', default=False)
298     verbosity.add_option('--get-description',
299             action='store_true', dest='getdescription',
300             help='simulate, quiet but print video description', default=False)
301     verbosity.add_option('--get-filename',
302             action='store_true', dest='getfilename',
303             help='simulate, quiet but print output filename', default=False)
304     verbosity.add_option('--get-format',
305             action='store_true', dest='getformat',
306             help='simulate, quiet but print output format', default=False)
307     verbosity.add_option('-j', '--dump-json',
308             action='store_true', dest='dumpjson',
309             help='simulate, quiet but print JSON information', default=False)
310     verbosity.add_option('--newline',
311             action='store_true', dest='progress_with_newline', help='output progress bar as new lines', default=False)
312     verbosity.add_option('--no-progress',
313             action='store_true', dest='noprogress', help='do not print progress bar', default=False)
314     verbosity.add_option('--console-title',
315             action='store_true', dest='consoletitle',
316             help='display progress in console titlebar', default=False)
317     verbosity.add_option('-v', '--verbose',
318             action='store_true', dest='verbose', help='print various debugging information', default=False)
319     verbosity.add_option('--dump-intermediate-pages',
320             action='store_true', dest='dump_intermediate_pages', default=False,
321             help='print downloaded pages to debug problems(very verbose)')
322     verbosity.add_option('--write-pages',
323             action='store_true', dest='write_pages', default=False,
324             help='Write downloaded intermediary pages to files in the current directory to debug problems')
325     verbosity.add_option('--youtube-print-sig-code',
326             action='store_true', dest='youtube_print_sig_code', default=False,
327             help=optparse.SUPPRESS_HELP)
328
329
330     filesystem.add_option('-t', '--title',
331             action='store_true', dest='usetitle', help='use title in file name (default)', default=False)
332     filesystem.add_option('--id',
333             action='store_true', dest='useid', help='use only video ID in file name', default=False)
334     filesystem.add_option('-l', '--literal',
335             action='store_true', dest='usetitle', help='[deprecated] alias of --title', default=False)
336     filesystem.add_option('-A', '--auto-number',
337             action='store_true', dest='autonumber',
338             help='number downloaded files starting from 00000', default=False)
339     filesystem.add_option('-o', '--output',
340             dest='outtmpl', metavar='TEMPLATE',
341             help=('output filename template. Use %(title)s to get the title, '
342                   '%(uploader)s for the uploader name, %(uploader_id)s for the uploader nickname if different, '
343                   '%(autonumber)s to get an automatically incremented number, '
344                   '%(ext)s for the filename extension, '
345                   '%(format)s for the format description (like "22 - 1280x720" or "HD"),'
346                   '%(format_id)s for the unique id of the format (like Youtube\'s itags: "137"),'
347                   '%(upload_date)s for the upload date (YYYYMMDD), '
348                   '%(extractor)s for the provider (youtube, metacafe, etc), '
349                   '%(id)s for the video id , %(playlist)s for the playlist the video is in, '
350                   '%(playlist_index)s for the position in the playlist and %% for a literal percent. '
351                   'Use - to output to stdout. Can also be used to download to a different directory, '
352                   'for example with -o \'/my/downloads/%(uploader)s/%(title)s-%(id)s.%(ext)s\' .'))
353     filesystem.add_option('--autonumber-size',
354             dest='autonumber_size', metavar='NUMBER',
355             help='Specifies the number of digits in %(autonumber)s when it is present in output filename template or --auto-number option is given')
356     filesystem.add_option('--restrict-filenames',
357             action='store_true', dest='restrictfilenames',
358             help='Restrict filenames to only ASCII characters, and avoid "&" and spaces in filenames', default=False)
359     filesystem.add_option('-a', '--batch-file',
360             dest='batchfile', metavar='FILE', help='file containing URLs to download (\'-\' for stdin)')
361     filesystem.add_option('-w', '--no-overwrites',
362             action='store_true', dest='nooverwrites', help='do not overwrite files', default=False)
363     filesystem.add_option('-c', '--continue',
364             action='store_true', dest='continue_dl', help='force resume of partially downloaded files. By default, youtube-dl will resume downloads if possible.', default=True)
365     filesystem.add_option('--no-continue',
366             action='store_false', dest='continue_dl',
367             help='do not resume partially downloaded files (restart from beginning)')
368     filesystem.add_option('--cookies',
369             dest='cookiefile', metavar='FILE', help='file to read cookies from and dump cookie jar in')
370     filesystem.add_option('--no-part',
371             action='store_true', dest='nopart', help='do not use .part files', default=False)
372     filesystem.add_option('--no-mtime',
373             action='store_false', dest='updatetime',
374             help='do not use the Last-modified header to set the file modification time', default=True)
375     filesystem.add_option('--write-description',
376             action='store_true', dest='writedescription',
377             help='write video description to a .description file', default=False)
378     filesystem.add_option('--write-info-json',
379             action='store_true', dest='writeinfojson',
380             help='write video metadata to a .info.json file', default=False)
381     filesystem.add_option('--write-annotations',
382             action='store_true', dest='writeannotations',
383             help='write video annotations to a .annotation file', default=False)
384     filesystem.add_option('--write-thumbnail',
385             action='store_true', dest='writethumbnail',
386             help='write thumbnail image to disk', default=False)
387
388
389     postproc.add_option('-x', '--extract-audio', action='store_true', dest='extractaudio', default=False,
390             help='convert video files to audio-only files (requires ffmpeg or avconv and ffprobe or avprobe)')
391     postproc.add_option('--audio-format', metavar='FORMAT', dest='audioformat', default='best',
392             help='"best", "aac", "vorbis", "mp3", "m4a", "opus", or "wav"; best by default')
393     postproc.add_option('--audio-quality', metavar='QUALITY', dest='audioquality', default='5',
394             help='ffmpeg/avconv audio quality specification, insert a value between 0 (better) and 9 (worse) for VBR or a specific bitrate like 128K (default 5)')
395     postproc.add_option('--recode-video', metavar='FORMAT', dest='recodevideo', default=None,
396             help='Encode the video to another format if necessary (currently supported: mp4|flv|ogg|webm)')
397     postproc.add_option('-k', '--keep-video', action='store_true', dest='keepvideo', default=False,
398             help='keeps the video file on disk after the post-processing; the video is erased by default')
399     postproc.add_option('--no-post-overwrites', action='store_true', dest='nopostoverwrites', default=False,
400             help='do not overwrite post-processed files; the post-processed files are overwritten by default')
401     postproc.add_option('--embed-subs', action='store_true', dest='embedsubtitles', default=False,
402             help='embed subtitles in the video (only for mp4 videos)')
403     postproc.add_option('--add-metadata', action='store_true', dest='addmetadata', default=False,
404             help='add metadata to the files')
405
406
407     parser.add_option_group(general)
408     parser.add_option_group(selection)
409     parser.add_option_group(downloader)
410     parser.add_option_group(filesystem)
411     parser.add_option_group(verbosity)
412     parser.add_option_group(video_format)
413     parser.add_option_group(subtitles)
414     parser.add_option_group(authentication)
415     parser.add_option_group(postproc)
416
417     if overrideArguments is not None:
418         opts, args = parser.parse_args(overrideArguments)
419         if opts.verbose:
420             write_string(u'[debug] Override config: ' + repr(overrideArguments) + '\n')
421     else:
422         systemConf = _readOptions('/etc/youtube-dl.conf')
423
424         xdg_config_home = os.environ.get('XDG_CONFIG_HOME')
425         if xdg_config_home:
426             userConfFile = os.path.join(xdg_config_home, 'youtube-dl', 'config')
427             if not os.path.isfile(userConfFile):
428                 userConfFile = os.path.join(xdg_config_home, 'youtube-dl.conf')
429         else:
430             userConfFile = os.path.join(os.path.expanduser('~'), '.config', 'youtube-dl', 'config')
431             if not os.path.isfile(userConfFile):
432                 userConfFile = os.path.join(os.path.expanduser('~'), '.config', 'youtube-dl.conf')
433         userConf = _readOptions(userConfFile, None)
434
435         if userConf is None:
436             appdata_dir = os.environ.get('appdata')
437             if appdata_dir:
438                 userConf = _readOptions(
439                     os.path.join(appdata_dir, 'youtube-dl', 'config'),
440                     default=None)
441                 if userConf is None:
442                     userConf = _readOptions(
443                         os.path.join(appdata_dir, 'youtube-dl', 'config.txt'),
444                         default=None)
445
446         if userConf is None:
447             userConf = _readOptions(
448                 os.path.join(os.path.expanduser('~'), 'youtube-dl.conf'),
449                 default=None)
450         if userConf is None:
451             userConf = _readOptions(
452                 os.path.join(os.path.expanduser('~'), 'youtube-dl.conf.txt'),
453                 default=None)
454
455         if userConf is None:
456             userConf = []
457
458         commandLineConf = sys.argv[1:]
459         argv = systemConf + userConf + commandLineConf
460         opts, args = parser.parse_args(argv)
461         if opts.verbose:
462             write_string(u'[debug] System config: ' + repr(_hide_login_info(systemConf)) + '\n')
463             write_string(u'[debug] User config: ' + repr(_hide_login_info(userConf)) + '\n')
464             write_string(u'[debug] Command-line args: ' + repr(_hide_login_info(commandLineConf)) + '\n')
465
466     return parser, opts, args
467
468 def _real_main(argv=None):
469     # Compatibility fixes for Windows
470     if sys.platform == 'win32':
471         # https://github.com/rg3/youtube-dl/issues/820
472         codecs.register(lambda name: codecs.lookup('utf-8') if name == 'cp65001' else None)
473
474     parser, opts, args = parseOpts(argv)
475
476     # Set user agent
477     if opts.user_agent is not None:
478         std_headers['User-Agent'] = opts.user_agent
479
480     # Set referer
481     if opts.referer is not None:
482         std_headers['Referer'] = opts.referer
483
484     # Dump user agent
485     if opts.dump_user_agent:
486         compat_print(std_headers['User-Agent'])
487         sys.exit(0)
488
489     # Batch file verification
490     batchurls = []
491     if opts.batchfile is not None:
492         try:
493             if opts.batchfile == '-':
494                 batchfd = sys.stdin
495             else:
496                 batchfd = open(opts.batchfile, 'r')
497             batchurls = batchfd.readlines()
498             batchurls = [x.strip() for x in batchurls]
499             batchurls = [x for x in batchurls if len(x) > 0 and not re.search(r'^[#/;]', x)]
500             if opts.verbose:
501                 write_string(u'[debug] Batch file urls: ' + repr(batchurls) + u'\n')
502         except IOError:
503             sys.exit(u'ERROR: batch file could not be read')
504     all_urls = batchurls + args
505     all_urls = [url.strip() for url in all_urls]
506
507     extractors = gen_extractors()
508
509     if opts.list_extractors:
510         for ie in sorted(extractors, key=lambda ie: ie.IE_NAME.lower()):
511             compat_print(ie.IE_NAME + (' (CURRENTLY BROKEN)' if not ie._WORKING else ''))
512             matchedUrls = [url for url in all_urls if ie.suitable(url)]
513             all_urls = [url for url in all_urls if url not in matchedUrls]
514             for mu in matchedUrls:
515                 compat_print(u'  ' + mu)
516         sys.exit(0)
517     if opts.list_extractor_descriptions:
518         for ie in sorted(extractors, key=lambda ie: ie.IE_NAME.lower()):
519             if not ie._WORKING:
520                 continue
521             desc = getattr(ie, 'IE_DESC', ie.IE_NAME)
522             if desc is False:
523                 continue
524             if hasattr(ie, 'SEARCH_KEY'):
525                 _SEARCHES = (u'cute kittens', u'slithering pythons', u'falling cat', u'angry poodle', u'purple fish', u'running tortoise')
526                 _COUNTS = (u'', u'5', u'10', u'all')
527                 desc += u' (Example: "%s%s:%s" )' % (ie.SEARCH_KEY, random.choice(_COUNTS), random.choice(_SEARCHES))
528             compat_print(desc)
529         sys.exit(0)
530
531
532     # Conflicting, missing and erroneous options
533     if opts.usenetrc and (opts.username is not None or opts.password is not None):
534         parser.error(u'using .netrc conflicts with giving username/password')
535     if opts.password is not None and opts.username is None:
536         parser.error(u' account username missing\n')
537     if opts.outtmpl is not None and (opts.usetitle or opts.autonumber or opts.useid):
538         parser.error(u'using output template conflicts with using title, video ID or auto number')
539     if opts.usetitle and opts.useid:
540         parser.error(u'using title conflicts with using video ID')
541     if opts.username is not None and opts.password is None:
542         opts.password = getpass.getpass(u'Type account password and press return:')
543     if opts.ratelimit is not None:
544         numeric_limit = FileDownloader.parse_bytes(opts.ratelimit)
545         if numeric_limit is None:
546             parser.error(u'invalid rate limit specified')
547         opts.ratelimit = numeric_limit
548     if opts.min_filesize is not None:
549         numeric_limit = FileDownloader.parse_bytes(opts.min_filesize)
550         if numeric_limit is None:
551             parser.error(u'invalid min_filesize specified')
552         opts.min_filesize = numeric_limit
553     if opts.max_filesize is not None:
554         numeric_limit = FileDownloader.parse_bytes(opts.max_filesize)
555         if numeric_limit is None:
556             parser.error(u'invalid max_filesize specified')
557         opts.max_filesize = numeric_limit
558     if opts.retries is not None:
559         try:
560             opts.retries = int(opts.retries)
561         except (TypeError, ValueError):
562             parser.error(u'invalid retry count specified')
563     if opts.buffersize is not None:
564         numeric_buffersize = FileDownloader.parse_bytes(opts.buffersize)
565         if numeric_buffersize is None:
566             parser.error(u'invalid buffer size specified')
567         opts.buffersize = numeric_buffersize
568     try:
569         opts.playliststart = int(opts.playliststart)
570         if opts.playliststart <= 0:
571             raise ValueError(u'Playlist start must be positive')
572     except (TypeError, ValueError):
573         parser.error(u'invalid playlist start number specified')
574     try:
575         opts.playlistend = int(opts.playlistend)
576         if opts.playlistend != -1 and (opts.playlistend <= 0 or opts.playlistend < opts.playliststart):
577             raise ValueError(u'Playlist end must be greater than playlist start')
578     except (TypeError, ValueError):
579         parser.error(u'invalid playlist end number specified')
580     if opts.extractaudio:
581         if opts.audioformat not in ['best', 'aac', 'mp3', 'm4a', 'opus', 'vorbis', 'wav']:
582             parser.error(u'invalid audio format specified')
583     if opts.audioquality:
584         opts.audioquality = opts.audioquality.strip('k').strip('K')
585         if not opts.audioquality.isdigit():
586             parser.error(u'invalid audio quality specified')
587     if opts.recodevideo is not None:
588         if opts.recodevideo not in ['mp4', 'flv', 'webm', 'ogg']:
589             parser.error(u'invalid video recode format specified')
590     if opts.date is not None:
591         date = DateRange.day(opts.date)
592     else:
593         date = DateRange(opts.dateafter, opts.datebefore)
594
595     # --all-sub automatically sets --write-sub if --write-auto-sub is not given
596     # this was the old behaviour if only --all-sub was given.
597     if opts.allsubtitles and (opts.writeautomaticsub == False):
598         opts.writesubtitles = True
599
600     if sys.version_info < (3,):
601         # In Python 2, sys.argv is a bytestring (also note http://bugs.python.org/issue2128 for Windows systems)
602         if opts.outtmpl is not None:
603             opts.outtmpl = opts.outtmpl.decode(preferredencoding())
604     outtmpl =((opts.outtmpl is not None and opts.outtmpl)
605             or (opts.format == '-1' and opts.usetitle and u'%(title)s-%(id)s-%(format)s.%(ext)s')
606             or (opts.format == '-1' and u'%(id)s-%(format)s.%(ext)s')
607             or (opts.usetitle and opts.autonumber and u'%(autonumber)s-%(title)s-%(id)s.%(ext)s')
608             or (opts.usetitle and u'%(title)s-%(id)s.%(ext)s')
609             or (opts.useid and u'%(id)s.%(ext)s')
610             or (opts.autonumber and u'%(autonumber)s-%(id)s.%(ext)s')
611             or u'%(title)s-%(id)s.%(ext)s')
612     if '%(ext)s' not in outtmpl and opts.extractaudio:
613         parser.error(u'Cannot download a video and extract audio into the same'
614                      u' file! Use "%%(ext)s" instead of %r' %
615                      determine_ext(outtmpl, u''))
616
617     ydl_opts = {
618         'usenetrc': opts.usenetrc,
619         'username': opts.username,
620         'password': opts.password,
621         'videopassword': opts.videopassword,
622         'quiet': (opts.quiet or opts.geturl or opts.gettitle or opts.getid or opts.getthumbnail or opts.getdescription or opts.getfilename or opts.getformat or opts.dumpjson),
623         'forceurl': opts.geturl,
624         'forcetitle': opts.gettitle,
625         'forceid': opts.getid,
626         'forcethumbnail': opts.getthumbnail,
627         'forcedescription': opts.getdescription,
628         'forcefilename': opts.getfilename,
629         'forceformat': opts.getformat,
630         'forcejson': opts.dumpjson,
631         'simulate': opts.simulate,
632         'skip_download': (opts.skip_download or opts.simulate or opts.geturl or opts.gettitle or opts.getid or opts.getthumbnail or opts.getdescription or opts.getfilename or opts.getformat or opts.dumpjson),
633         'format': opts.format,
634         'format_limit': opts.format_limit,
635         'listformats': opts.listformats,
636         'outtmpl': outtmpl,
637         'autonumber_size': opts.autonumber_size,
638         'restrictfilenames': opts.restrictfilenames,
639         'ignoreerrors': opts.ignoreerrors,
640         'ratelimit': opts.ratelimit,
641         'nooverwrites': opts.nooverwrites,
642         'retries': opts.retries,
643         'buffersize': opts.buffersize,
644         'noresizebuffer': opts.noresizebuffer,
645         'continuedl': opts.continue_dl,
646         'noprogress': opts.noprogress,
647         'progress_with_newline': opts.progress_with_newline,
648         'playliststart': opts.playliststart,
649         'playlistend': opts.playlistend,
650         'noplaylist': opts.noplaylist,
651         'logtostderr': opts.outtmpl == '-',
652         'consoletitle': opts.consoletitle,
653         'nopart': opts.nopart,
654         'updatetime': opts.updatetime,
655         'writedescription': opts.writedescription,
656         'writeannotations': opts.writeannotations,
657         'writeinfojson': opts.writeinfojson,
658         'writethumbnail': opts.writethumbnail,
659         'writesubtitles': opts.writesubtitles,
660         'writeautomaticsub': opts.writeautomaticsub,
661         'allsubtitles': opts.allsubtitles,
662         'listsubtitles': opts.listsubtitles,
663         'subtitlesformat': opts.subtitlesformat,
664         'subtitleslangs': opts.subtitleslangs,
665         'matchtitle': decodeOption(opts.matchtitle),
666         'rejecttitle': decodeOption(opts.rejecttitle),
667         'max_downloads': opts.max_downloads,
668         'prefer_free_formats': opts.prefer_free_formats,
669         'verbose': opts.verbose,
670         'dump_intermediate_pages': opts.dump_intermediate_pages,
671         'write_pages': opts.write_pages,
672         'test': opts.test,
673         'keepvideo': opts.keepvideo,
674         'min_filesize': opts.min_filesize,
675         'max_filesize': opts.max_filesize,
676         'daterange': date,
677         'cachedir': opts.cachedir,
678         'youtube_print_sig_code': opts.youtube_print_sig_code,
679         'age_limit': opts.age_limit,
680         'download_archive': opts.download_archive,
681         'cookiefile': opts.cookiefile,
682         'nocheckcertificate': opts.no_check_certificate,
683         'proxy': opts.proxy,
684         'socket_timeout': opts.socket_timeout,
685     }
686
687     with YoutubeDL(ydl_opts) as ydl:
688         ydl.print_debug_header()
689         ydl.add_default_info_extractors()
690
691         # PostProcessors
692         # Add the metadata pp first, the other pps will copy it
693         if opts.addmetadata:
694             ydl.add_post_processor(FFmpegMetadataPP())
695         if opts.extractaudio:
696             ydl.add_post_processor(FFmpegExtractAudioPP(preferredcodec=opts.audioformat, preferredquality=opts.audioquality, nopostoverwrites=opts.nopostoverwrites))
697         if opts.recodevideo:
698             ydl.add_post_processor(FFmpegVideoConvertor(preferedformat=opts.recodevideo))
699         if opts.embedsubtitles:
700             ydl.add_post_processor(FFmpegEmbedSubtitlePP(subtitlesformat=opts.subtitlesformat))
701
702         # Update version
703         if opts.update_self:
704             update_self(ydl.to_screen, opts.verbose)
705
706         # Maybe do nothing
707         if len(all_urls) < 1:
708             if not opts.update_self:
709                 parser.error(u'you must provide at least one URL')
710             else:
711                 sys.exit()
712
713         try:
714             retcode = ydl.download(all_urls)
715         except MaxDownloadsReached:
716             ydl.to_screen(u'--max-download limit reached, aborting.')
717             retcode = 101
718
719     sys.exit(retcode)
720
721
722 def main(argv=None):
723     try:
724         _real_main(argv)
725     except DownloadError:
726         sys.exit(1)
727     except SameFileError:
728         sys.exit(u'ERROR: fixed output name but more than one file to download')
729     except KeyboardInterrupt:
730         sys.exit(u'\nERROR: Interrupted by user')