youtube-dl

Another place where youtube-dl lives on
git clone git://git.oshgnacknak.de/youtube-dl.git
Log | Files | Refs | README | LICENSE

commit 7d4111ed14848c3e72d55d47f11cd7e9fadea403
parent d37cab2a9d1da8056460613007f3099e7a9d8f7e
Author: Philipp Hagemeister <phihag@phihag.de>
Date:   Sun, 23 Nov 2014 10:49:19 +0100

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

Reported at https://news.ycombinator.com/item?id=8648121

Diffstat:
Mtest/test_utils.py | 7+++++++
Myoutube_dl/YoutubeDL.py | 19+++++++++++++++++++
Myoutube_dl/__init__.py | 7++++---
Myoutube_dl/compat.py | 6+++++-
Myoutube_dl/utils.py | 6++++++
5 files changed, 41 insertions(+), 4 deletions(-)

diff --git a/test/test_utils.py b/test/test_utils.py @@ -47,6 +47,7 @@ from youtube_dl.utils import ( js_to_json, get_filesystem_encoding, intlist_to_bytes, + args_to_str, ) @@ -361,5 +362,11 @@ class TestUtil(unittest.TestCase): intlist_to_bytes([0, 1, 127, 128, 255]), 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__': unittest.main() diff --git a/youtube_dl/YoutubeDL.py b/youtube_dl/YoutubeDL.py @@ -29,6 +29,7 @@ from .compat import ( compat_str, compat_urllib_error, compat_urllib_request, + shlex_quote, ) from .utils import ( escape_url, @@ -60,6 +61,7 @@ from .utils import ( write_string, YoutubeDLHandler, prepend_extension, + args_to_str, ) from .cache import Cache from .extractor import get_info_extractor, gen_extractors @@ -253,6 +255,22 @@ class YoutubeDL(object): self.print_debug_header() 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): """Add an InfoExtractor object to the end of the list.""" self._ies.append(ie) @@ -1410,3 +1428,4 @@ class YoutubeDL(object): if encoding is None: encoding = preferredencoding() return encoding + diff --git a/youtube_dl/__init__.py b/youtube_dl/__init__.py @@ -334,11 +334,12 @@ def _real_main(argv=None): # Maybe do nothing if (len(all_urls) < 1) and (opts.load_info_filename is None): - if not (opts.update_self or opts.rm_cachedir): - parser.error('you must provide at least one URL') - else: + if opts.update_self or opts.rm_cachedir: 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: if opts.load_info_filename is not None: retcode = ydl.download_with_info_file(opts.load_info_filename) diff --git a/youtube_dl/compat.py b/youtube_dl/compat.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals import getpass import optparse import os +import re import subprocess import sys @@ -174,7 +175,10 @@ try: from shlex import quote as shlex_quote except ImportError: # Python < 3.3 def shlex_quote(s): - return "'" + s.replace("'", "'\"'\"'") + "'" + if re.match(r'^[-_\w./]+$', s): + return s + else: + return "'" + s.replace("'", "'\"'\"'") + "'" def compat_ord(c): diff --git a/youtube_dl/utils.py b/youtube_dl/utils.py @@ -41,6 +41,7 @@ from .compat import ( compat_urllib_parse_urlparse, compat_urllib_request, compat_urlparse, + shlex_quote, ) @@ -1433,3 +1434,8 @@ def ytdl_is_updateable(): from zipimport import zipimporter 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)