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