Merge remote-tracking branch 'saper/tvp'
[youtube-dl] / 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 )
37
38 __license__ = 'Public Domain'
39
40 import codecs
41 import collections
42 import getpass
43 import optparse
44 import os
45 import random
46 import re
47 import shlex
48 import socket
49 import subprocess
50 import sys
51 import traceback
52 import platform
53
54
55 from .utils import (
56     compat_cookiejar,
57     compat_print,
58     compat_str,
59     compat_urllib_request,
60     DateRange,
61     decodeOption,
62     determine_ext,
63     DownloadError,
64     get_cachedir,
65     make_HTTPS_handler,
66     MaxDownloadsReached,
67     platform_name,
68     preferredencoding,
69     SameFileError,
70     std_headers,
71     write_string,
72     YoutubeDLHandler,
73 )
74 from .update import update_self
75 from .version import __version__
76 from .FileDownloader import (
77     FileDownloader,
78 )
79 from .extractor import gen_extractors
80 from .YoutubeDL import YoutubeDL
81 from .PostProcessor import (
82     FFmpegMetadataPP,
83     FFmpegVideoConvertor,
84     FFmpegExtractAudioPP,
85     FFmpegEmbedSubtitlePP,
86 )
87
88
89 def parseOpts(overrideArguments=None):
90     def _readOptions(filename_bytes):
91         try:
92             optionf = open(filename_bytes)
93         except IOError:
94             return [] # silently skip if file is not present
95         try:
96             res = []
97             for l in optionf:
98                 res += shlex.split(l, comments=True)
99         finally:
100             optionf.close()
101         return res
102
103     def _format_option_string(option):
104         ''' ('-o', '--option') -> -o, --format METAVAR'''
105
106         opts = []
107
108         if option._short_opts:
109             opts.append(option._short_opts[0])
110         if option._long_opts:
111             opts.append(option._long_opts[0])
112         if len(opts) > 1:
113             opts.insert(1, ', ')
114
115         if option.takes_value(): opts.append(' %s' % option.metavar)
116
117         return "".join(opts)
118
119     def _comma_separated_values_options_callback(option, opt_str, value, parser):
120         setattr(parser.values, option.dest, value.split(','))
121
122     def _find_term_columns():
123         columns = os.environ.get('COLUMNS', None)
124         if columns:
125             return int(columns)
126
127         try:
128             sp = subprocess.Popen(['stty', 'size'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
129             out,err = sp.communicate()
130             return int(out.split()[1])
131         except:
132             pass
133         return None
134
135     def _hide_login_info(opts):
136         opts = list(opts)
137         for private_opt in ['-p', '--password', '-u', '--username', '--video-password']:
138             try:
139                 i = opts.index(private_opt)
140                 opts[i+1] = '<PRIVATE>'
141             except ValueError:
142                 pass
143         return opts
144
145     max_width = 80
146     max_help_position = 80
147
148     # No need to wrap help messages if we're on a wide console
149     columns = _find_term_columns()
150     if columns: max_width = columns
151
152     fmt = optparse.IndentedHelpFormatter(width=max_width, max_help_position=max_help_position)
153     fmt.format_option_strings = _format_option_string
154
155     kw = {
156         'version'   : __version__,
157         'formatter' : fmt,
158         'usage' : '%prog [options] url [url...]',
159         'conflict_handler' : 'resolve',
160     }
161
162     parser = optparse.OptionParser(**kw)
163
164     # option groups
165     general        = optparse.OptionGroup(parser, 'General Options')
166     selection      = optparse.OptionGroup(parser, 'Video Selection')
167     authentication = optparse.OptionGroup(parser, 'Authentication Options')
168     video_format   = optparse.OptionGroup(parser, 'Video Format Options')
169     subtitles      = optparse.OptionGroup(parser, 'Subtitle Options')
170     downloader     = optparse.OptionGroup(parser, 'Download Options')
171     postproc       = optparse.OptionGroup(parser, 'Post-processing Options')
172     filesystem     = optparse.OptionGroup(parser, 'Filesystem Options')
173     verbosity      = optparse.OptionGroup(parser, 'Verbosity / Simulation Options')
174
175     general.add_option('-h', '--help',
176             action='help', help='print this help text and exit')
177     general.add_option('-v', '--version',
178             action='version', help='print program version and exit')
179     general.add_option('-U', '--update',
180             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)')
181     general.add_option('-i', '--ignore-errors',
182             action='store_true', dest='ignoreerrors', help='continue on download errors, for example to to skip unavailable videos in a playlist', default=False)
183     general.add_option('--abort-on-error',
184             action='store_false', dest='ignoreerrors',
185             help='Abort downloading of further videos (in the playlist or the command line) if an error occurs')
186     general.add_option('--dump-user-agent',
187             action='store_true', dest='dump_user_agent',
188             help='display the current browser identification', default=False)
189     general.add_option('--user-agent',
190             dest='user_agent', help='specify a custom user agent', metavar='UA')
191     general.add_option('--referer',
192             dest='referer', help='specify a custom referer, use if the video access is restricted to one domain',
193             metavar='REF', default=None)
194     general.add_option('--list-extractors',
195             action='store_true', dest='list_extractors',
196             help='List all supported extractors and the URLs they would handle', default=False)
197     general.add_option('--extractor-descriptions',
198             action='store_true', dest='list_extractor_descriptions',
199             help='Output descriptions of all supported extractors', default=False)
200     general.add_option('--proxy', dest='proxy', default=None, help='Use the specified HTTP/HTTPS proxy', metavar='URL')
201     general.add_option('--no-check-certificate', action='store_true', dest='no_check_certificate', default=False, help='Suppress HTTPS certificate validation.')
202     general.add_option(
203         '--cache-dir', dest='cachedir', default=get_cachedir(), metavar='DIR',
204         help='Location in the filesystem where youtube-dl can store downloaded information permanently. By default $XDG_CACHE_HOME/youtube-dl or ~/.cache/youtube-dl .')
205     general.add_option(
206         '--no-cache-dir', action='store_const', const=None, dest='cachedir',
207         help='Disable filesystem caching')
208
209
210     selection.add_option('--playlist-start',
211             dest='playliststart', metavar='NUMBER', help='playlist video to start at (default is %default)', default=1)
212     selection.add_option('--playlist-end',
213             dest='playlistend', metavar='NUMBER', help='playlist video to end at (default is last)', default=-1)
214     selection.add_option('--match-title', dest='matchtitle', metavar='REGEX',help='download only matching titles (regex or caseless sub-string)')
215     selection.add_option('--reject-title', dest='rejecttitle', metavar='REGEX',help='skip download for matching titles (regex or caseless sub-string)')
216     selection.add_option('--max-downloads', metavar='NUMBER', dest='max_downloads', help='Abort after downloading NUMBER files', default=None)
217     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)
218     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)
219     selection.add_option('--date', metavar='DATE', dest='date', help='download only videos uploaded in this date', default=None)
220     selection.add_option('--datebefore', metavar='DATE', dest='datebefore', help='download only videos uploaded before this date', default=None)
221     selection.add_option('--dateafter', metavar='DATE', dest='dateafter', help='download only videos uploaded after this date', default=None)
222     selection.add_option('--no-playlist', action='store_true', dest='noplaylist', help='download only the currently playing video', default=False)
223     selection.add_option('--age-limit', metavar='YEARS', dest='age_limit',
224                          help='download only videos suitable for the given age',
225                          default=None, type=int)
226     selection.add_option('--download-archive', metavar='FILE',
227                          dest='download_archive',
228                          help='Download only videos not present in the archive file. Record all downloaded videos in it.')
229
230
231     authentication.add_option('-u', '--username',
232             dest='username', metavar='USERNAME', help='account username')
233     authentication.add_option('-p', '--password',
234             dest='password', metavar='PASSWORD', help='account password')
235     authentication.add_option('-n', '--netrc',
236             action='store_true', dest='usenetrc', help='use .netrc authentication data', default=False)
237     authentication.add_option('--video-password',
238             dest='videopassword', metavar='PASSWORD', help='video password (vimeo only)')
239
240
241     video_format.add_option('-f', '--format',
242             action='store', dest='format', metavar='FORMAT', default='best',
243             help='video format code, specifiy the order of preference using slashes: "-f 22/17/18". "-f mp4" and "-f flv" are also supported')
244     video_format.add_option('--all-formats',
245             action='store_const', dest='format', help='download all available video formats', const='all')
246     video_format.add_option('--prefer-free-formats',
247             action='store_true', dest='prefer_free_formats', default=False, help='prefer free video formats unless a specific one is requested')
248     video_format.add_option('--max-quality',
249             action='store', dest='format_limit', metavar='FORMAT', help='highest quality format to download')
250     video_format.add_option('-F', '--list-formats',
251             action='store_true', dest='listformats', help='list all available formats (currently youtube only)')
252
253     subtitles.add_option('--write-sub', '--write-srt',
254             action='store_true', dest='writesubtitles',
255             help='write subtitle file', default=False)
256     subtitles.add_option('--write-auto-sub', '--write-automatic-sub',
257             action='store_true', dest='writeautomaticsub',
258             help='write automatic subtitle file (youtube only)', default=False)
259     subtitles.add_option('--all-subs',
260             action='store_true', dest='allsubtitles',
261             help='downloads all the available subtitles of the video', default=False)
262     subtitles.add_option('--list-subs',
263             action='store_true', dest='listsubtitles',
264             help='lists all available subtitles for the video', default=False)
265     subtitles.add_option('--sub-format',
266             action='store', dest='subtitlesformat', metavar='FORMAT',
267             help='subtitle format (default=srt) ([sbv/vtt] youtube only)', default='srt')
268     subtitles.add_option('--sub-lang', '--sub-langs', '--srt-lang',
269             action='callback', dest='subtitleslangs', metavar='LANGS', type='str',
270             default=[], callback=_comma_separated_values_options_callback,
271             help='languages of the subtitles to download (optional) separated by commas, use IETF language tags like \'en,pt\'')
272
273     downloader.add_option('-r', '--rate-limit',
274             dest='ratelimit', metavar='LIMIT', help='maximum download rate in bytes per second (e.g. 50K or 4.2M)')
275     downloader.add_option('-R', '--retries',
276             dest='retries', metavar='RETRIES', help='number of retries (default is %default)', default=10)
277     downloader.add_option('--buffer-size',
278             dest='buffersize', metavar='SIZE', help='size of download buffer (e.g. 1024 or 16K) (default is %default)', default="1024")
279     downloader.add_option('--no-resize-buffer',
280             action='store_true', dest='noresizebuffer',
281             help='do not automatically adjust the buffer size. By default, the buffer size is automatically resized from an initial value of SIZE.', default=False)
282     downloader.add_option('--test', action='store_true', dest='test', default=False, help=optparse.SUPPRESS_HELP)
283
284     verbosity.add_option('-q', '--quiet',
285             action='store_true', dest='quiet', help='activates quiet mode', default=False)
286     verbosity.add_option('-s', '--simulate',
287             action='store_true', dest='simulate', help='do not download the video and do not write anything to disk', default=False)
288     verbosity.add_option('--skip-download',
289             action='store_true', dest='skip_download', help='do not download the video', default=False)
290     verbosity.add_option('-g', '--get-url',
291             action='store_true', dest='geturl', help='simulate, quiet but print URL', default=False)
292     verbosity.add_option('-e', '--get-title',
293             action='store_true', dest='gettitle', help='simulate, quiet but print title', default=False)
294     verbosity.add_option('--get-id',
295             action='store_true', dest='getid', help='simulate, quiet but print id', default=False)
296     verbosity.add_option('--get-thumbnail',
297             action='store_true', dest='getthumbnail',
298             help='simulate, quiet but print thumbnail URL', default=False)
299     verbosity.add_option('--get-description',
300             action='store_true', dest='getdescription',
301             help='simulate, quiet but print video description', default=False)
302     verbosity.add_option('--get-filename',
303             action='store_true', dest='getfilename',
304             help='simulate, quiet but print output filename', default=False)
305     verbosity.add_option('--get-format',
306             action='store_true', dest='getformat',
307             help='simulate, quiet but print output format', 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 pages to files in the current directory')
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         xdg_config_home = os.environ.get('XDG_CONFIG_HOME')
421         if xdg_config_home:
422             userConfFile = os.path.join(xdg_config_home, 'youtube-dl', 'config')
423             if not os.path.isfile(userConfFile):
424                 userConfFile = os.path.join(xdg_config_home, 'youtube-dl.conf')
425         else:
426             userConfFile = os.path.join(os.path.expanduser('~'), '.config', 'youtube-dl', 'config')
427             if not os.path.isfile(userConfFile):
428                 userConfFile = os.path.join(os.path.expanduser('~'), '.config', 'youtube-dl.conf')
429         systemConf = _readOptions('/etc/youtube-dl.conf')
430         userConf = _readOptions(userConfFile)
431         commandLineConf = sys.argv[1:]
432         argv = systemConf + userConf + commandLineConf
433         opts, args = parser.parse_args(argv)
434         if opts.verbose:
435             write_string(u'[debug] System config: ' + repr(_hide_login_info(systemConf)) + '\n')
436             write_string(u'[debug] User config: ' + repr(_hide_login_info(userConf)) + '\n')
437             write_string(u'[debug] Command-line args: ' + repr(_hide_login_info(commandLineConf)) + '\n')
438
439     return parser, opts, args
440
441 def _real_main(argv=None):
442     # Compatibility fixes for Windows
443     if sys.platform == 'win32':
444         # https://github.com/rg3/youtube-dl/issues/820
445         codecs.register(lambda name: codecs.lookup('utf-8') if name == 'cp65001' else None)
446
447     parser, opts, args = parseOpts(argv)
448
449     # Open appropriate CookieJar
450     if opts.cookiefile is None:
451         jar = compat_cookiejar.CookieJar()
452     else:
453         try:
454             jar = compat_cookiejar.MozillaCookieJar(opts.cookiefile)
455             if os.access(opts.cookiefile, os.R_OK):
456                 jar.load()
457         except (IOError, OSError) as err:
458             if opts.verbose:
459                 traceback.print_exc()
460             write_string(u'ERROR: unable to open cookie file\n')
461             sys.exit(101)
462     # Set user agent
463     if opts.user_agent is not None:
464         std_headers['User-Agent'] = opts.user_agent
465
466     # Set referer
467     if opts.referer is not None:
468         std_headers['Referer'] = opts.referer
469
470     # Dump user agent
471     if opts.dump_user_agent:
472         compat_print(std_headers['User-Agent'])
473         sys.exit(0)
474
475     # Batch file verification
476     batchurls = []
477     if opts.batchfile is not None:
478         try:
479             if opts.batchfile == '-':
480                 batchfd = sys.stdin
481             else:
482                 batchfd = open(opts.batchfile, 'r')
483             batchurls = batchfd.readlines()
484             batchurls = [x.strip() for x in batchurls]
485             batchurls = [x for x in batchurls if len(x) > 0 and not re.search(r'^[#/;]', x)]
486             if opts.verbose:
487                 write_string(u'[debug] Batch file urls: ' + repr(batchurls) + u'\n')
488         except IOError:
489             sys.exit(u'ERROR: batch file could not be read')
490     all_urls = batchurls + args
491     all_urls = [url.strip() for url in all_urls]
492
493     opener = _setup_opener(jar=jar, opts=opts)
494
495     extractors = gen_extractors()
496
497     if opts.list_extractors:
498         for ie in sorted(extractors, key=lambda ie: ie.IE_NAME.lower()):
499             compat_print(ie.IE_NAME + (' (CURRENTLY BROKEN)' if not ie._WORKING else ''))
500             matchedUrls = [url for url in all_urls if ie.suitable(url)]
501             all_urls = [url for url in all_urls if url not in matchedUrls]
502             for mu in matchedUrls:
503                 compat_print(u'  ' + mu)
504         sys.exit(0)
505     if opts.list_extractor_descriptions:
506         for ie in sorted(extractors, key=lambda ie: ie.IE_NAME.lower()):
507             if not ie._WORKING:
508                 continue
509             desc = getattr(ie, 'IE_DESC', ie.IE_NAME)
510             if desc is False:
511                 continue
512             if hasattr(ie, 'SEARCH_KEY'):
513                 _SEARCHES = (u'cute kittens', u'slithering pythons', u'falling cat', u'angry poodle', u'purple fish', u'running tortoise')
514                 _COUNTS = (u'', u'5', u'10', u'all')
515                 desc += u' (Example: "%s%s:%s" )' % (ie.SEARCH_KEY, random.choice(_COUNTS), random.choice(_SEARCHES))
516             compat_print(desc)
517         sys.exit(0)
518
519
520     # Conflicting, missing and erroneous options
521     if opts.usenetrc and (opts.username is not None or opts.password is not None):
522         parser.error(u'using .netrc conflicts with giving username/password')
523     if opts.password is not None and opts.username is None:
524         parser.error(u' account username missing\n')
525     if opts.outtmpl is not None and (opts.usetitle or opts.autonumber or opts.useid):
526         parser.error(u'using output template conflicts with using title, video ID or auto number')
527     if opts.usetitle and opts.useid:
528         parser.error(u'using title conflicts with using video ID')
529     if opts.username is not None and opts.password is None:
530         opts.password = getpass.getpass(u'Type account password and press return:')
531     if opts.ratelimit is not None:
532         numeric_limit = FileDownloader.parse_bytes(opts.ratelimit)
533         if numeric_limit is None:
534             parser.error(u'invalid rate limit specified')
535         opts.ratelimit = numeric_limit
536     if opts.min_filesize is not None:
537         numeric_limit = FileDownloader.parse_bytes(opts.min_filesize)
538         if numeric_limit is None:
539             parser.error(u'invalid min_filesize specified')
540         opts.min_filesize = numeric_limit
541     if opts.max_filesize is not None:
542         numeric_limit = FileDownloader.parse_bytes(opts.max_filesize)
543         if numeric_limit is None:
544             parser.error(u'invalid max_filesize specified')
545         opts.max_filesize = numeric_limit
546     if opts.retries is not None:
547         try:
548             opts.retries = int(opts.retries)
549         except (TypeError, ValueError) as err:
550             parser.error(u'invalid retry count specified')
551     if opts.buffersize is not None:
552         numeric_buffersize = FileDownloader.parse_bytes(opts.buffersize)
553         if numeric_buffersize is None:
554             parser.error(u'invalid buffer size specified')
555         opts.buffersize = numeric_buffersize
556     try:
557         opts.playliststart = int(opts.playliststart)
558         if opts.playliststart <= 0:
559             raise ValueError(u'Playlist start must be positive')
560     except (TypeError, ValueError) as err:
561         parser.error(u'invalid playlist start number specified')
562     try:
563         opts.playlistend = int(opts.playlistend)
564         if opts.playlistend != -1 and (opts.playlistend <= 0 or opts.playlistend < opts.playliststart):
565             raise ValueError(u'Playlist end must be greater than playlist start')
566     except (TypeError, ValueError) as err:
567         parser.error(u'invalid playlist end number specified')
568     if opts.extractaudio:
569         if opts.audioformat not in ['best', 'aac', 'mp3', 'm4a', 'opus', 'vorbis', 'wav']:
570             parser.error(u'invalid audio format specified')
571     if opts.audioquality:
572         opts.audioquality = opts.audioquality.strip('k').strip('K')
573         if not opts.audioquality.isdigit():
574             parser.error(u'invalid audio quality specified')
575     if opts.recodevideo is not None:
576         if opts.recodevideo not in ['mp4', 'flv', 'webm', 'ogg']:
577             parser.error(u'invalid video recode format specified')
578     if opts.date is not None:
579         date = DateRange.day(opts.date)
580     else:
581         date = DateRange(opts.dateafter, opts.datebefore)
582
583     # --all-sub automatically sets --write-sub if --write-auto-sub is not given
584     # this was the old behaviour if only --all-sub was given.
585     if opts.allsubtitles and (opts.writeautomaticsub == False):
586         opts.writesubtitles = True
587
588     if sys.version_info < (3,):
589         # In Python 2, sys.argv is a bytestring (also note http://bugs.python.org/issue2128 for Windows systems)
590         if opts.outtmpl is not None:
591             opts.outtmpl = opts.outtmpl.decode(preferredencoding())
592     outtmpl =((opts.outtmpl is not None and opts.outtmpl)
593             or (opts.format == '-1' and opts.usetitle and u'%(title)s-%(id)s-%(format)s.%(ext)s')
594             or (opts.format == '-1' and u'%(id)s-%(format)s.%(ext)s')
595             or (opts.usetitle and opts.autonumber and u'%(autonumber)s-%(title)s-%(id)s.%(ext)s')
596             or (opts.usetitle and u'%(title)s-%(id)s.%(ext)s')
597             or (opts.useid and u'%(id)s.%(ext)s')
598             or (opts.autonumber and u'%(autonumber)s-%(id)s.%(ext)s')
599             or u'%(title)s-%(id)s.%(ext)s')
600     if '%(ext)s' not in outtmpl and opts.extractaudio:
601         parser.error(u'Cannot download a video and extract audio into the same'
602                      u' file! Use "%%(ext)s" instead of %r' %
603                      determine_ext(outtmpl, u''))
604
605     # YoutubeDL
606     ydl = YoutubeDL({
607         'usenetrc': opts.usenetrc,
608         'username': opts.username,
609         'password': opts.password,
610         'videopassword': opts.videopassword,
611         'quiet': (opts.quiet or opts.geturl or opts.gettitle or opts.getid or opts.getthumbnail or opts.getdescription or opts.getfilename or opts.getformat),
612         'forceurl': opts.geturl,
613         'forcetitle': opts.gettitle,
614         'forceid': opts.getid,
615         'forcethumbnail': opts.getthumbnail,
616         'forcedescription': opts.getdescription,
617         'forcefilename': opts.getfilename,
618         'forceformat': opts.getformat,
619         'simulate': opts.simulate,
620         '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),
621         'format': opts.format,
622         'format_limit': opts.format_limit,
623         'listformats': opts.listformats,
624         'outtmpl': outtmpl,
625         'autonumber_size': opts.autonumber_size,
626         'restrictfilenames': opts.restrictfilenames,
627         'ignoreerrors': opts.ignoreerrors,
628         'ratelimit': opts.ratelimit,
629         'nooverwrites': opts.nooverwrites,
630         'retries': opts.retries,
631         'buffersize': opts.buffersize,
632         'noresizebuffer': opts.noresizebuffer,
633         'continuedl': opts.continue_dl,
634         'noprogress': opts.noprogress,
635         'progress_with_newline': opts.progress_with_newline,
636         'playliststart': opts.playliststart,
637         'playlistend': opts.playlistend,
638         'noplaylist': opts.noplaylist,
639         'logtostderr': opts.outtmpl == '-',
640         'consoletitle': opts.consoletitle,
641         'nopart': opts.nopart,
642         'updatetime': opts.updatetime,
643         'writedescription': opts.writedescription,
644         'writeannotations': opts.writeannotations,
645         'writeinfojson': opts.writeinfojson,
646         'writethumbnail': opts.writethumbnail,
647         'writesubtitles': opts.writesubtitles,
648         'writeautomaticsub': opts.writeautomaticsub,
649         'allsubtitles': opts.allsubtitles,
650         'listsubtitles': opts.listsubtitles,
651         'subtitlesformat': opts.subtitlesformat,
652         'subtitleslangs': opts.subtitleslangs,
653         'matchtitle': decodeOption(opts.matchtitle),
654         'rejecttitle': decodeOption(opts.rejecttitle),
655         'max_downloads': opts.max_downloads,
656         'prefer_free_formats': opts.prefer_free_formats,
657         'verbose': opts.verbose,
658         'dump_intermediate_pages': opts.dump_intermediate_pages,
659         'write_pages': opts.write_pages,
660         'test': opts.test,
661         'keepvideo': opts.keepvideo,
662         'min_filesize': opts.min_filesize,
663         'max_filesize': opts.max_filesize,
664         'daterange': date,
665         'cachedir': opts.cachedir,
666         'youtube_print_sig_code': opts.youtube_print_sig_code,
667         'age_limit': opts.age_limit,
668         'download_archive': opts.download_archive,
669         })
670
671     if opts.verbose:
672         write_string(u'[debug] youtube-dl version ' + __version__ + u'\n')
673         try:
674             sp = subprocess.Popen(
675                 ['git', 'rev-parse', '--short', 'HEAD'],
676                 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
677                 cwd=os.path.dirname(os.path.abspath(__file__)))
678             out, err = sp.communicate()
679             out = out.decode().strip()
680             if re.match('[0-9a-f]+', out):
681                 write_string(u'[debug] Git HEAD: ' + out + u'\n')
682         except:
683             try:
684                 sys.exc_clear()
685             except:
686                 pass
687         write_string(u'[debug] Python version %s - %s' %(platform.python_version(), platform_name()) + u'\n')
688
689         proxy_map = {}
690         for handler in opener.handlers:
691             if hasattr(handler, 'proxies'):
692                 proxy_map.update(handler.proxies)
693         write_string(u'[debug] Proxy map: ' + compat_str(proxy_map) + u'\n')
694
695     ydl.add_default_info_extractors()
696
697     # PostProcessors
698     # Add the metadata pp first, the other pps will copy it
699     if opts.addmetadata:
700         ydl.add_post_processor(FFmpegMetadataPP())
701     if opts.extractaudio:
702         ydl.add_post_processor(FFmpegExtractAudioPP(preferredcodec=opts.audioformat, preferredquality=opts.audioquality, nopostoverwrites=opts.nopostoverwrites))
703     if opts.recodevideo:
704         ydl.add_post_processor(FFmpegVideoConvertor(preferedformat=opts.recodevideo))
705     if opts.embedsubtitles:
706         ydl.add_post_processor(FFmpegEmbedSubtitlePP(subtitlesformat=opts.subtitlesformat))
707
708     # Update version
709     if opts.update_self:
710         update_self(ydl.to_screen, opts.verbose)
711
712     # Maybe do nothing
713     if len(all_urls) < 1:
714         if not opts.update_self:
715             parser.error(u'you must provide at least one URL')
716         else:
717             sys.exit()
718
719     try:
720         retcode = ydl.download(all_urls)
721     except MaxDownloadsReached:
722         ydl.to_screen(u'--max-download limit reached, aborting.')
723         retcode = 101
724
725     # Dump cookie jar if requested
726     if opts.cookiefile is not None:
727         try:
728             jar.save()
729         except (IOError, OSError):
730             sys.exit(u'ERROR: unable to save cookie jar')
731
732     sys.exit(retcode)
733
734
735 def _setup_opener(jar=None, opts=None, timeout=300):
736     if opts is None:
737         FakeOptions = collections.namedtuple(
738             'FakeOptions', ['proxy', 'no_check_certificate'])
739         opts = FakeOptions(proxy=None, no_check_certificate=False)
740
741     cookie_processor = compat_urllib_request.HTTPCookieProcessor(jar)
742     if opts.proxy is not None:
743         if opts.proxy == '':
744             proxies = {}
745         else:
746             proxies = {'http': opts.proxy, 'https': opts.proxy}
747     else:
748         proxies = compat_urllib_request.getproxies()
749         # Set HTTPS proxy to HTTP one if given (https://github.com/rg3/youtube-dl/issues/805)
750         if 'http' in proxies and 'https' not in proxies:
751             proxies['https'] = proxies['http']
752     proxy_handler = compat_urllib_request.ProxyHandler(proxies)
753     https_handler = make_HTTPS_handler(opts)
754     opener = compat_urllib_request.build_opener(
755         https_handler, proxy_handler, cookie_processor, YoutubeDLHandler())
756     # Delete the default user-agent header, which would otherwise apply in
757     # cases where our custom HTTP handler doesn't come into play
758     # (See https://github.com/rg3/youtube-dl/issues/1309 for details)
759     opener.addheaders = []
760     compat_urllib_request.install_opener(opener)
761     socket.setdefaulttimeout(timeout)
762     return opener
763
764
765 def main(argv=None):
766     try:
767         _real_main(argv)
768     except DownloadError:
769         sys.exit(1)
770     except SameFileError:
771         sys.exit(u'ERROR: fixed output name but more than one file to download')
772     except KeyboardInterrupt:
773         sys.exit(u'\nERROR: Interrupted by user')