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