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