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