From 47192f92d801f38c0a608ca9c6cecc682ab2ecc6 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 30 Sep 2013 16:26:25 -0400 Subject: [PATCH 1/3] implement --no-playlist to only download current video - closes #755 --- README.md | 1 + youtube_dl/YoutubeDL.py | 1 + youtube_dl/__init__.py | 2 ++ youtube_dl/extractor/youtube.py | 13 ++++++++++++- 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fc8070c37..66a483b76 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ which means you can modify it, redistribute it or use it however you like. --date DATE download only videos uploaded in this date --datebefore DATE download only videos uploaded before this date --dateafter DATE download only videos uploaded after this date + --no-playlist download only the currently playing video ## Download Options: -r, --rate-limit LIMIT maximum download rate (e.g. 50k or 44.6m) diff --git a/youtube_dl/YoutubeDL.py b/youtube_dl/YoutubeDL.py index 44a272e7e..2503fd09b 100644 --- a/youtube_dl/YoutubeDL.py +++ b/youtube_dl/YoutubeDL.py @@ -83,6 +83,7 @@ class YoutubeDL(object): skip_download: Skip the actual download of the video file cachedir: Location of the cache files in the filesystem. None to disable filesystem cache. + noplaylist: Download single video instead of a playlist if in doubt. The following parameters are not used by YoutubeDL itself, they are used by the FileDownloader: diff --git a/youtube_dl/__init__.py b/youtube_dl/__init__.py index 28a7bdd92..c9e75eab4 100644 --- a/youtube_dl/__init__.py +++ b/youtube_dl/__init__.py @@ -187,6 +187,7 @@ def parseOpts(overrideArguments=None): selection.add_option('--date', metavar='DATE', dest='date', help='download only videos uploaded in this date', default=None) selection.add_option('--datebefore', metavar='DATE', dest='datebefore', help='download only videos uploaded before this date', default=None) selection.add_option('--dateafter', metavar='DATE', dest='dateafter', help='download only videos uploaded after this date', default=None) + selection.add_option('--no-playlist', action='store_true', dest='noplaylist', help='download only the currently playing video', default=False) authentication.add_option('-u', '--username', @@ -599,6 +600,7 @@ def _real_main(argv=None): 'progress_with_newline': opts.progress_with_newline, 'playliststart': opts.playliststart, 'playlistend': opts.playlistend, + 'noplaylist': opts.noplaylist, 'logtostderr': opts.outtmpl == '-', 'consoletitle': opts.consoletitle, 'nopart': opts.nopart, diff --git a/youtube_dl/extractor/youtube.py b/youtube_dl/extractor/youtube.py index 53f13b516..c6876c69f 100644 --- a/youtube_dl/extractor/youtube.py +++ b/youtube_dl/extractor/youtube.py @@ -13,6 +13,7 @@ import struct import traceback import xml.etree.ElementTree import zlib +import urlparse from .common import InfoExtractor, SearchInfoExtractor from .subtitles import SubtitlesInfoExtractor @@ -1523,9 +1524,19 @@ class YoutubePlaylistIE(InfoExtractor): mobj = re.match(self._VALID_URL, url, re.VERBOSE) if mobj is None: raise ExtractorError(u'Invalid URL: %s' % url) + playlist_id = mobj.group(1) or mobj.group(2) + + # Check if it's a video-specific URL + query_dict = urlparse.parse_qs(urlparse.urlparse(url).query) + if 'v' in query_dict: + video_id = query_dict['v'][0] + if self._downloader.params.get('noplaylist'): + self.to_screen(u'Downloading just video %s because of --no-playlist' % video_id) + return self.url_result('https://www.youtube.com/watch?v=' + video_id, 'Youtube') + else: + self.to_screen(u'Downloading playlist PL%s - add --no-playlist to just download video %s' % (playlist_id, video_id)) # Download playlist videos from API - playlist_id = mobj.group(1) or mobj.group(2) videos = [] for page_num in itertools.count(1): From d4d9920a2630ef6c44cffa1b923e41291b44b5f0 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 30 Sep 2013 18:01:17 -0400 Subject: [PATCH 2/3] add test for --no-playlist --- test/test_youtube_lists.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/test_youtube_lists.py b/test/test_youtube_lists.py index dd9e292b0..f28fe78e0 100644 --- a/test/test_youtube_lists.py +++ b/test/test_youtube_lists.py @@ -27,6 +27,13 @@ class TestYoutubeLists(unittest.TestCase): ytie_results = [YoutubeIE()._extract_id(url['url']) for url in result['entries']] self.assertEqual(ytie_results, [ 'bV9L5Ht9LgY', 'FXxLjLQi3Fg', 'tU3Bgo5qJZE']) + def test_youtube_playlist_noplaylist(self): + dl = FakeYDL() + dl.params['noplaylist'] = True + ie = YoutubePlaylistIE(dl) + result = ie.extract('https://www.youtube.com/watch?v=FXxLjLQi3Fg&list=PLwiyx1dc3P2JR9N8gQaQN_BCvlSlap7re') + self.assertEqual(result['_type'], 'url') + def test_issue_673(self): dl = FakeYDL() ie = YoutubePlaylistIE(dl) From 7c61bd36bb172485815288d44e00acb676e8eaff Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Tue, 1 Oct 2013 11:58:13 -0400 Subject: [PATCH 3/3] [youtube] correct --no-playlist for python3 --- test/test_youtube_lists.py | 1 + youtube_dl/extractor/youtube.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/test/test_youtube_lists.py b/test/test_youtube_lists.py index f28fe78e0..53e65816d 100644 --- a/test/test_youtube_lists.py +++ b/test/test_youtube_lists.py @@ -33,6 +33,7 @@ class TestYoutubeLists(unittest.TestCase): ie = YoutubePlaylistIE(dl) result = ie.extract('https://www.youtube.com/watch?v=FXxLjLQi3Fg&list=PLwiyx1dc3P2JR9N8gQaQN_BCvlSlap7re') self.assertEqual(result['_type'], 'url') + self.assertEqual(YoutubeIE()._extract_id(result['url']), 'FXxLjLQi3Fg') def test_issue_673(self): dl = FakeYDL() diff --git a/youtube_dl/extractor/youtube.py b/youtube_dl/extractor/youtube.py index c6876c69f..5d932f8a4 100644 --- a/youtube_dl/extractor/youtube.py +++ b/youtube_dl/extractor/youtube.py @@ -13,7 +13,6 @@ import struct import traceback import xml.etree.ElementTree import zlib -import urlparse from .common import InfoExtractor, SearchInfoExtractor from .subtitles import SubtitlesInfoExtractor @@ -24,6 +23,7 @@ from ..utils import ( compat_urllib_error, compat_urllib_parse, compat_urllib_request, + compat_urlparse, compat_str, clean_html, @@ -1527,7 +1527,7 @@ class YoutubePlaylistIE(InfoExtractor): playlist_id = mobj.group(1) or mobj.group(2) # Check if it's a video-specific URL - query_dict = urlparse.parse_qs(urlparse.urlparse(url).query) + query_dict = compat_urlparse.parse_qs(compat_urlparse.urlparse(url).query) if 'v' in query_dict: video_id = query_dict['v'][0] if self._downloader.params.get('noplaylist'):