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