From 7bc30b43b70556630b4a93c03fefc0d888e3d19f Mon Sep 17 00:00:00 2001 From: Unit 193 Date: Thu, 30 Dec 2021 01:56:41 -0500 Subject: New upstream version 1.20.0. --- test/test_results.py | 31 ++- test/test_util.py | 25 +++ test/test_ytdl.py | 545 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 583 insertions(+), 18 deletions(-) create mode 100644 test/test_ytdl.py (limited to 'test') diff --git a/test/test_results.py b/test/test_results.py index 944f14d..37dea38 100644 --- a/test/test_results.py +++ b/test/test_results.py @@ -353,28 +353,23 @@ def generate_tests(): # enable selective testing for direct calls if __name__ == '__main__' and len(sys.argv) > 1: - if sys.argv[1].lower() == "all": - fltr = lambda c, bc: True # noqa: E731 - elif sys.argv[1].lower() == "broken": - fltr = lambda c, bc: c in BROKEN # noqa: E731 - else: - argv = sys.argv[1:] - fltr = lambda c, bc: c in argv or bc in argv # noqa: E731 + categories = sys.argv[1:] + negate = False + if categories[0].lower() == "all": + categories = () + negate = True + elif categories[0].lower() == "broken": + categories = BROKEN del sys.argv[1:] else: - skip = set(BROKEN) - if skip: - print("skipping:", ", ".join(skip)) - fltr = lambda c, bc: c not in skip # noqa: E731 - - # filter available extractor classes - extractors = [ - extr for extr in extractor.extractors() - if fltr(extr.category, extr.basecategory) - ] + categories = BROKEN + negate = True + if categories: + print("skipping:", ", ".join(categories)) + fltr = util.build_extractor_filter(categories, negate=negate) # add 'test_...' methods - for extr in extractors: + for extr in filter(fltr, extractor.extractors()): name = "test_" + extr.__name__ + "_" for num, tcase in enumerate(extr._get_tests(), 1): test = _generate_test(extr, tcase) diff --git a/test/test_util.py b/test/test_util.py index 32e9784..ce403a8 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -357,6 +357,31 @@ class TestOther(unittest.TestCase): with self.assertRaises(exception.StopExtraction): expr() + def test_build_duration_func(self, f=util.build_duration_func): + for v in (0, 0.0, "", None, (), []): + self.assertIsNone(f(v)) + + def test_single(df, v): + for _ in range(10): + self.assertEqual(df(), v) + + def test_range(df, lower, upper): + for __ in range(10): + v = df() + self.assertGreaterEqual(v, lower) + self.assertLessEqual(v, upper) + + test_single(f(3), 3) + test_single(f(3.0), 3.0) + test_single(f("3"), 3) + test_single(f("3.0-"), 3) + test_single(f(" 3 -"), 3) + + test_range(f((2, 4)), 2, 4) + test_range(f([2, 4]), 2, 4) + test_range(f("2-4"), 2, 4) + test_range(f(" 2.0 - 4 "), 2, 4) + def test_extractor_filter(self): # empty func = util.build_extractor_filter("") diff --git a/test/test_ytdl.py b/test/test_ytdl.py new file mode 100644 index 0000000..97431e3 --- /dev/null +++ b/test/test_ytdl.py @@ -0,0 +1,545 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright 2021 Mike Fährmann +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. + +import os +import sys +import unittest + +import re +import shlex + +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +from gallery_dl import ytdl, util, config + + +class Test_CommandlineArguments(unittest.TestCase): + module_name = "youtube_dl" + + @classmethod + def setUpClass(cls): + try: + cls.module = __import__(cls.module_name) + except ImportError: + raise unittest.SkipTest("cannot import module '{}'".format( + cls.module_name)) + cls.default = ytdl.parse_command_line(cls.module, []) + + def test_ignore_errors(self): + self._("--ignore-errors" , "ignoreerrors", True) + self._("--abort-on-error", "ignoreerrors", False) + + def test_default_search(self): + self._(["--default-search", "foo"] , "default_search", "foo") + + def test_mark_watched(self): + self._("--mark-watched" , "mark_watched", True) + self._("--no-mark-watched", "mark_watched", False) + + def test_proxy(self): + self._(["--proxy", "socks5://127.0.0.1:1080/"], + "proxy", "socks5://127.0.0.1:1080/") + self._(["--cn-verification-proxy", "https://127.0.0.1"], + "cn_verification_proxy", "https://127.0.0.1") + self._(["--geo-verification-proxy", "127.0.0.1"], + "geo_verification_proxy", "127.0.0.1") + + def test_retries(self): + inf = float("inf") + + self._(["--retries", "5"], "retries", 5) + self._(["--retries", "inf"], "retries", inf) + self._(["--retries", "infinite"], "retries", inf) + self._(["--fragment-retries", "8"], "fragment_retries", 8) + self._(["--fragment-retries", "inf"], "fragment_retries", inf) + self._(["--fragment-retries", "infinite"], "fragment_retries", inf) + + def test_geo_bypass(self): + self._("--geo-bypass", "geo_bypass", True) + self._("--no-geo-bypass", "geo_bypass", False) + self._(["--geo-bypass-country", "EN"], "geo_bypass_country", "EN") + self._(["--geo-bypass-ip-block", "198.51.100.14/24"], + "geo_bypass_ip_block", "198.51.100.14/24") + + def test_headers(self): + headers = self.module.std_headers + + self.assertNotEqual(headers["User-Agent"], "Foo/1.0") + self._(["--user-agent", "Foo/1.0"]) + self.assertEqual(headers["User-Agent"], "Foo/1.0") + + self.assertNotIn("Referer", headers) + self._(["--referer", "http://example.org/"]) + self.assertEqual(headers["Referer"], "http://example.org/") + + self.assertNotEqual(headers["Accept"], "*/*") + self.assertNotIn("DNT", headers) + self._([ + "--add-header", "accept:*/*", + "--add-header", "dnt:1", + ]) + self.assertEqual(headers["accept"], "*/*") + self.assertEqual(headers["dnt"], "1") + + def test_extract_audio(self): + opts = self._(["--extract-audio"]) + self.assertEqual(opts["postprocessors"][0], { + "key": "FFmpegExtractAudio", + "preferredcodec": "best", + "preferredquality": "5", + "nopostoverwrites": False, + }) + + opts = self._([ + "--extract-audio", + "--audio-format", "opus", + "--audio-quality", "9", + "--no-post-overwrites", + ]) + self.assertEqual(opts["postprocessors"][0], { + "key": "FFmpegExtractAudio", + "preferredcodec": "opus", + "preferredquality": "9", + "nopostoverwrites": True, + }) + + def test_recode_video(self): + opts = self._(["--recode-video", " mkv "]) + self.assertEqual(opts["postprocessors"][0], { + "key": "FFmpegVideoConvertor", + "preferedformat": "mkv", + }) + + def test_subs(self): + opts = self._(["--convert-subs", "srt"]) + conv = {"key": "FFmpegSubtitlesConvertor", "format": "srt"} + if self.module_name == "yt_dlp": + conv["when"] = "before_dl" + self.assertEqual(opts["postprocessors"][0], conv) + + def test_embed(self): + subs = {"key": "FFmpegEmbedSubtitle"} + thumb = {"key": "EmbedThumbnail", "already_have_thumbnail": False} + if self.module_name == "yt_dlp": + subs["already_have_subtitle"] = False + + opts = self._(["--embed-subs", "--embed-thumbnail"]) + self.assertEqual(opts["postprocessors"], [subs, thumb]) + + thumb["already_have_thumbnail"] = True + if self.module_name == "yt_dlp": + subs["already_have_subtitle"] = True + + opts = self._([ + "--embed-thumbnail", + "--embed-subs", + "--write-sub", + "--write-all-thumbnails", + ]) + self.assertEqual(opts["postprocessors"], [subs, thumb]) + + def test_metadata(self): + opts = self._("--add-metadata") + self.assertEqual(opts["postprocessors"][0], {"key": "FFmpegMetadata"}) + + def test_metadata_from_title(self): + opts = self._(["--metadata-from-title", "%(artist)s - %(title)s"]) + self.assertEqual(opts["postprocessors"][0], { + "key": "MetadataFromTitle", + "titleformat": "%(artist)s - %(title)s", + }) + + def test_xattr(self): + self._("--xattr-set-filesize", "xattr_set_filesize", True) + + opts = self._("--xattrs") + self.assertEqual(opts["postprocessors"][0], {"key": "XAttrMetadata"}) + + def test_noop(self): + result = self._([ + "--update", + "--dump-user-agent", + "--list-extractors", + "--extractor-descriptions", + "--ignore-config", + "--config-location", + "--dump-json", + "--dump-single-json", + "--list-thumbnails", + ]) + + result["daterange"] = self.default["daterange"] + self.assertEqual(result, self.default) + + def _(self, cmdline, option=util.SENTINEL, expected=None): + if isinstance(cmdline, str): + cmdline = [cmdline] + result = ytdl.parse_command_line(self.module, cmdline) + if option is not util.SENTINEL: + self.assertEqual(result[option], expected, option) + return result + + +class Test_CommandlineArguments_YtDlp(Test_CommandlineArguments): + module_name = "yt_dlp" + + def test_retries_extractor(self): + inf = float("inf") + + self._(["--extractor-retries", "5"], "extractor_retries", 5) + self._(["--extractor-retries", "inf"], "extractor_retries", inf) + self._(["--extractor-retries", "infinite"], "extractor_retries", inf) + + def test_remuxs_video(self): + opts = self._(["--remux-video", " mkv "]) + self.assertEqual(opts["postprocessors"][0], { + "key": "FFmpegVideoRemuxer", + "preferedformat": "mkv", + }) + + def test_metadata(self): + opts = self._(["--embed-metadata", + "--no-embed-chapters", + "--embed-info-json"]) + self.assertEqual(opts["postprocessors"][0], { + "key": "FFmpegMetadata", + "add_chapters": False, + "add_metadata": True, + "add_infojson": True, + }) + + def test_metadata_from_title(self): + opts = self._(["--metadata-from-title", "%(artist)s - %(title)s"]) + self.assertEqual(opts["postprocessors"][0], { + "key": "MetadataParser", + "when": "pre_process", + "actions": [self.module.MetadataFromFieldPP.to_action( + "title:%(artist)s - %(title)s")], + }) + + +if __name__ == "__main__": + unittest.main(warnings="ignore") + +''' +Usage: __main__.py [OPTIONS] URL [URL...] + +Options: + General Options: + -h, --help Print this help text and exit + --version Print program version and exit + --force-generic-extractor Force extraction to use the generic + extractor + --flat-playlist Do not extract the videos of a + playlist, only list them. + --no-color Do not emit color codes in output + + Network Options: + --socket-timeout SECONDS Time to wait before giving up, in + seconds + --source-address IP Client-side IP address to bind to + -4, --force-ipv4 Make all connections via IPv4 + -6, --force-ipv6 Make all connections via IPv6 + + Video Selection: + --playlist-start NUMBER Playlist video to start at (default is + 1) + --playlist-end NUMBER Playlist video to end at (default is + last) + --playlist-items ITEM_SPEC Playlist video items to download. + Specify indices of the videos in the + playlist separated by commas like: "-- + playlist-items 1,2,5,8" if you want to + download videos indexed 1, 2, 5, 8 in + the playlist. You can specify range: " + --playlist-items 1-3,7,10-13", it will + download the videos at index 1, 2, 3, + 7, 10, 11, 12 and 13. + --match-title REGEX Download only matching titles (regex or + caseless sub-string) + --reject-title REGEX Skip download for matching titles + (regex or caseless sub-string) + --max-downloads NUMBER Abort after downloading NUMBER files + --min-filesize SIZE Do not download any videos smaller than + SIZE (e.g. 50k or 44.6m) + --max-filesize SIZE Do not download any videos larger than + SIZE (e.g. 50k or 44.6m) + --date DATE Download only videos uploaded in this + date + --datebefore DATE Download only videos uploaded on or + before this date (i.e. inclusive) + --dateafter DATE Download only videos uploaded on or + after this date (i.e. inclusive) + --min-views COUNT Do not download any videos with less + than COUNT views + --max-views COUNT Do not download any videos with more + than COUNT views + --match-filter FILTER Generic video filter. Specify any key + (see the "OUTPUT TEMPLATE" for a list + of available keys) to match if the key + is present, !key to check if the key is + not present, key > NUMBER (like + "comment_count > 12", also works with + >=, <, <=, !=, =) to compare against a + number, key = 'LITERAL' (like "uploader + = 'Mike Smith'", also works with !=) to + match against a string literal and & to + require multiple matches. Values which + are not known are excluded unless you + put a question mark (?) after the + operator. For example, to only match + videos that have been liked more than + 100 times and disliked less than 50 + times (or the dislike functionality is + not available at the given service), + but who also have a description, use + --match-filter "like_count > 100 & + dislike_count