Provide guidance when called with a YouTube ID starting with a dash.

Reported at https://news.ycombinator.com/item?id=8648121
This commit is contained in:
Philipp Hagemeister 2014-11-23 10:49:19 +01:00
parent d37cab2a9d
commit 7d4111ed14
5 changed files with 41 additions and 4 deletions

View file

@ -47,6 +47,7 @@
js_to_json, js_to_json,
get_filesystem_encoding, get_filesystem_encoding,
intlist_to_bytes, intlist_to_bytes,
args_to_str,
) )
@ -361,5 +362,11 @@ def test_intlist_to_bytes(self):
intlist_to_bytes([0, 1, 127, 128, 255]), intlist_to_bytes([0, 1, 127, 128, 255]),
b'\x00\x01\x7f\x80\xff') b'\x00\x01\x7f\x80\xff')
def test_args_to_str(self):
self.assertEqual(
args_to_str(['foo', 'ba/r', '-baz', '2 be', '']),
'foo ba/r -baz \'2 be\' \'\''
)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View file

@ -29,6 +29,7 @@
compat_str, compat_str,
compat_urllib_error, compat_urllib_error,
compat_urllib_request, compat_urllib_request,
shlex_quote,
) )
from .utils import ( from .utils import (
escape_url, escape_url,
@ -60,6 +61,7 @@
write_string, write_string,
YoutubeDLHandler, YoutubeDLHandler,
prepend_extension, prepend_extension,
args_to_str,
) )
from .cache import Cache from .cache import Cache
from .extractor import get_info_extractor, gen_extractors from .extractor import get_info_extractor, gen_extractors
@ -253,6 +255,22 @@ def __init__(self, params=None, auto_init=True):
self.print_debug_header() self.print_debug_header()
self.add_default_info_extractors() self.add_default_info_extractors()
def warn_if_short_id(self, argv):
# short YouTube ID starting with dash?
idxs = [
i for i, a in enumerate(argv)
if re.match(r'^-[0-9A-Za-z_-]{10}$', a)]
if idxs:
correct_argv = (
['youtube-dl'] +
[a for i, a in enumerate(argv) if i not in idxs] +
['--'] + [argv[i] for i in idxs]
)
self.report_warning(
'Long argument string detected. '
'Use -- to separate parameters and URLs, like this:\n%s\n' %
args_to_str(correct_argv))
def add_info_extractor(self, ie): def add_info_extractor(self, ie):
"""Add an InfoExtractor object to the end of the list.""" """Add an InfoExtractor object to the end of the list."""
self._ies.append(ie) self._ies.append(ie)
@ -1410,3 +1428,4 @@ def get_encoding(self):
if encoding is None: if encoding is None:
encoding = preferredencoding() encoding = preferredencoding()
return encoding return encoding

View file

@ -334,11 +334,12 @@ def _real_main(argv=None):
# Maybe do nothing # Maybe do nothing
if (len(all_urls) < 1) and (opts.load_info_filename is None): if (len(all_urls) < 1) and (opts.load_info_filename is None):
if not (opts.update_self or opts.rm_cachedir): if opts.update_self or opts.rm_cachedir:
parser.error('you must provide at least one URL')
else:
sys.exit() sys.exit()
ydl.warn_if_short_id(sys.argv[1:] if argv is None else argv)
parser.error('you must provide at least one URL')
try: try:
if opts.load_info_filename is not None: if opts.load_info_filename is not None:
retcode = ydl.download_with_info_file(opts.load_info_filename) retcode = ydl.download_with_info_file(opts.load_info_filename)

View file

@ -3,6 +3,7 @@
import getpass import getpass
import optparse import optparse
import os import os
import re
import subprocess import subprocess
import sys import sys
@ -174,7 +175,10 @@ def compat_parse_qs(qs, keep_blank_values=False, strict_parsing=False,
from shlex import quote as shlex_quote from shlex import quote as shlex_quote
except ImportError: # Python < 3.3 except ImportError: # Python < 3.3
def shlex_quote(s): def shlex_quote(s):
return "'" + s.replace("'", "'\"'\"'") + "'" if re.match(r'^[-_\w./]+$', s):
return s
else:
return "'" + s.replace("'", "'\"'\"'") + "'"
def compat_ord(c): def compat_ord(c):

View file

@ -41,6 +41,7 @@
compat_urllib_parse_urlparse, compat_urllib_parse_urlparse,
compat_urllib_request, compat_urllib_request,
compat_urlparse, compat_urlparse,
shlex_quote,
) )
@ -1433,3 +1434,8 @@ def ytdl_is_updateable():
from zipimport import zipimporter from zipimport import zipimporter
return isinstance(globals().get('__loader__'), zipimporter) or hasattr(sys, 'frozen') return isinstance(globals().get('__loader__'), zipimporter) or hasattr(sys, 'frozen')
def args_to_str(args):
# Get a short string representation for a subprocess command
return ' '.join(shlex_quote(a) for a in args)