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