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