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