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