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