diff --git a/test/__init__.py b/test/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/test/helper.py b/test/helper.py
deleted file mode 100644
index 6f2129eff..000000000
--- a/test/helper.py
+++ /dev/null
@@ -1,285 +0,0 @@
-from __future__ import unicode_literals
-
-import errno
-import hashlib
-import json
-import os.path
-import re
-import ssl
-import sys
-import types
-import unittest
-
-import youtube_dl.extractor
-from youtube_dl import YoutubeDL
-from youtube_dl.compat import (
- compat_open as open,
- compat_os_name,
- compat_str,
-)
-from youtube_dl.utils import (
- IDENTITY,
- preferredencoding,
- write_string,
-)
-
-
-def get_params(override=None):
- PARAMETERS_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)),
- "parameters.json")
- LOCAL_PARAMETERS_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)),
- "local_parameters.json")
- with open(PARAMETERS_FILE, encoding='utf-8') as pf:
- parameters = json.load(pf)
- if os.path.exists(LOCAL_PARAMETERS_FILE):
- with open(LOCAL_PARAMETERS_FILE, encoding='utf-8') as pf:
- parameters.update(json.load(pf))
- if override:
- parameters.update(override)
- return parameters
-
-
-def try_rm(filename):
- """ Remove a file if it exists """
- try:
- os.remove(filename)
- except OSError as ose:
- if ose.errno != errno.ENOENT:
- raise
-
-
-def report_warning(message):
- '''
- Print the message to stderr, it will be prefixed with 'WARNING:'
- If stderr is a tty file the 'WARNING:' will be colored
- '''
- if sys.stderr.isatty() and compat_os_name != 'nt':
- _msg_header = '\033[0;33mWARNING:\033[0m'
- else:
- _msg_header = 'WARNING:'
- output = '%s %s\n' % (_msg_header, message)
- if 'b' in getattr(sys.stderr, 'mode', '') or sys.version_info[0] < 3:
- output = output.encode(preferredencoding())
- sys.stderr.write(output)
-
-
-class FakeYDL(YoutubeDL):
- def __init__(self, override=None):
- # Different instances of the downloader can't share the same dictionary
- # some test set the "sublang" parameter, which would break the md5 checks.
- params = get_params(override=override)
- super(FakeYDL, self).__init__(params, auto_init=False)
- self.result = []
-
- def to_screen(self, s, skip_eol=None):
- print(s)
-
- def trouble(self, *args, **kwargs):
- s = args[0] if len(args) > 0 else kwargs.get('message', 'Missing message')
- raise Exception(s)
-
- def download(self, x):
- self.result.append(x)
-
- def expect_warning(self, regex):
- # Silence an expected warning matching a regex
- old_report_warning = self.report_warning
-
- def report_warning(self, message):
- if re.match(regex, message):
- return
- old_report_warning(message)
- self.report_warning = types.MethodType(report_warning, self)
-
-
-class FakeLogger(object):
- def debug(self, msg):
- pass
-
- def warning(self, msg):
- pass
-
- def error(self, msg):
- pass
-
-
-def gettestcases(include_onlymatching=False):
- for ie in youtube_dl.extractor.gen_extractors():
- for tc in ie.get_testcases(include_onlymatching):
- yield tc
-
-
-md5 = lambda s: hashlib.md5(s.encode('utf-8')).hexdigest()
-
-
-def expect_value(self, got, expected, field):
- if isinstance(expected, compat_str) and expected.startswith('re:'):
- match_str = expected[len('re:'):]
- match_rex = re.compile(match_str)
-
- self.assertTrue(
- isinstance(got, compat_str),
- 'Expected a %s object, but got %s for field %s' % (
- compat_str.__name__, type(got).__name__, field))
- self.assertTrue(
- match_rex.match(got),
- 'field %s (value: %r) should match %r' % (field, got, match_str))
- elif isinstance(expected, compat_str) and expected.startswith('startswith:'):
- start_str = expected[len('startswith:'):]
- self.assertTrue(
- isinstance(got, compat_str),
- 'Expected a %s object, but got %s for field %s' % (
- compat_str.__name__, type(got).__name__, field))
- self.assertTrue(
- got.startswith(start_str),
- 'field %s (value: %r) should start with %r' % (field, got, start_str))
- elif isinstance(expected, compat_str) and expected.startswith('contains:'):
- contains_str = expected[len('contains:'):]
- self.assertTrue(
- isinstance(got, compat_str),
- 'Expected a %s object, but got %s for field %s' % (
- compat_str.__name__, type(got).__name__, field))
- self.assertTrue(
- contains_str in got,
- 'field %s (value: %r) should contain %r' % (field, got, contains_str))
- elif isinstance(expected, compat_str) and re.match(r'lambda \w+:', expected):
- fn = eval(expected)
- suite = expected.split(':', 1)[1].strip()
- self.assertTrue(
- fn(got),
- 'Expected field %s to meet condition %s, but value %r failed ' % (field, suite, got))
- elif isinstance(expected, type):
- self.assertTrue(
- isinstance(got, expected),
- 'Expected type %r for field %s, but got value %r of type %r' % (expected, field, got, type(got)))
- elif isinstance(expected, dict) and isinstance(got, dict):
- expect_dict(self, got, expected)
- elif isinstance(expected, list) and isinstance(got, list):
- self.assertEqual(
- len(expected), len(got),
- 'Expected a list of length %d, but got a list of length %d for field %s' % (
- len(expected), len(got), field))
- for index, (item_got, item_expected) in enumerate(zip(got, expected)):
- type_got = type(item_got)
- type_expected = type(item_expected)
- self.assertEqual(
- type_expected, type_got,
- 'Type mismatch for list item at index %d for field %s, expected %r, got %r' % (
- index, field, type_expected, type_got))
- expect_value(self, item_got, item_expected, field)
- else:
- if isinstance(expected, compat_str) and expected.startswith('md5:'):
- self.assertTrue(
- isinstance(got, compat_str),
- 'Expected field %s to be a unicode object, but got value %r of type %r' % (field, got, type(got)))
- got = 'md5:' + md5(got)
- elif isinstance(expected, compat_str) and re.match(r'^(?:min|max)?count:\d+', expected):
- self.assertTrue(
- isinstance(got, (list, dict)),
- 'Expected field %s to be a list or a dict, but it is of type %s' % (
- field, type(got).__name__))
- op, _, expected_num = expected.partition(':')
- expected_num = int(expected_num)
- if op == 'mincount':
- assert_func = self.assertGreaterEqual
- msg_tmpl = 'Expected %d items in field %s, but only got %d'
- elif op == 'maxcount':
- assert_func = self.assertLessEqual
- msg_tmpl = 'Expected maximum %d items in field %s, but got %d'
- elif op == 'count':
- assert_func = self.assertEqual
- msg_tmpl = 'Expected exactly %d items in field %s, but got %d'
- else:
- assert False
- assert_func(
- len(got), expected_num,
- msg_tmpl % (expected_num, field, len(got)))
- return
- self.assertEqual(
- expected, got,
- 'Invalid value for field %s, expected %r, got %r' % (field, expected, got))
-
-
-def expect_dict(self, got_dict, expected_dict):
- for info_field, expected in expected_dict.items():
- got = got_dict.get(info_field)
- expect_value(self, got, expected, info_field)
-
-
-def expect_info_dict(self, got_dict, expected_dict):
- expect_dict(self, got_dict, expected_dict)
- # Check for the presence of mandatory fields
- if got_dict.get('_type') not in ('playlist', 'multi_video'):
- for key in ('id', 'url', 'title', 'ext'):
- self.assertTrue(got_dict.get(key), 'Missing mandatory field %s' % key)
- # Check for mandatory fields that are automatically set by YoutubeDL
- for key in ['webpage_url', 'extractor', 'extractor_key']:
- self.assertTrue(got_dict.get(key), 'Missing field: %s' % key)
-
- # Are checkable fields missing from the test case definition?
- test_info_dict = dict((key, value if not isinstance(value, compat_str) or len(value) < 250 else 'md5:' + md5(value))
- for key, value in got_dict.items()
- if value and key in ('id', 'title', 'description', 'uploader', 'upload_date', 'timestamp', 'uploader_id', 'location', 'age_limit'))
- missing_keys = set(test_info_dict.keys()) - set(expected_dict.keys())
- if missing_keys:
- def _repr(v):
- if isinstance(v, compat_str):
- return "'%s'" % v.replace('\\', '\\\\').replace("'", "\\'").replace('\n', '\\n')
- else:
- return repr(v)
- info_dict_str = ''
- if len(missing_keys) != len(expected_dict):
- info_dict_str += ''.join(
- ' %s: %s,\n' % (_repr(k), _repr(v))
- for k, v in test_info_dict.items() if k not in missing_keys)
-
- if info_dict_str:
- info_dict_str += '\n'
- info_dict_str += ''.join(
- ' %s: %s,\n' % (_repr(k), _repr(test_info_dict[k]))
- for k in missing_keys)
- write_string(
- '\n\'info_dict\': {\n' + info_dict_str + '},\n', out=sys.stderr)
- self.assertFalse(
- missing_keys,
- 'Missing keys in test definition: %s' % (
- ', '.join(sorted(missing_keys))))
-
-
-def assertRegexpMatches(self, text, regexp, msg=None):
- if hasattr(self, 'assertRegexp'):
- return self.assertRegexp(text, regexp, msg)
- else:
- m = re.match(regexp, text)
- if not m:
- note = 'Regexp didn\'t match: %r not found' % (regexp)
- if len(text) < 1000:
- note += ' in %r' % text
- if msg is None:
- msg = note
- else:
- msg = note + ', ' + msg
- self.assertTrue(m, msg)
-
-
-def expect_warnings(ydl, warnings_re):
- real_warning = ydl.report_warning
-
- def _report_warning(w):
- if not any(re.search(w_re, w) for w_re in warnings_re):
- real_warning(w)
-
- ydl.report_warning = _report_warning
-
-
-def http_server_port(httpd):
- if os.name == 'java' and isinstance(httpd.socket, ssl.SSLSocket):
- # In Jython SSLSocket is not a subclass of socket.socket
- sock = httpd.socket.sock
- else:
- sock = httpd.socket
- return sock.getsockname()[1]
-
-
-def expectedFailureIf(cond):
- return unittest.expectedFailure if cond else IDENTITY
diff --git a/test/parameters.json b/test/parameters.json
deleted file mode 100644
index 864c9d130..000000000
--- a/test/parameters.json
+++ /dev/null
@@ -1,42 +0,0 @@
-{
- "consoletitle": false,
- "continuedl": true,
- "forcedescription": false,
- "forcefilename": false,
- "forceformat": false,
- "forcethumbnail": false,
- "forcetitle": false,
- "forceurl": false,
- "format": "best",
- "ignoreerrors": false,
- "listformats": null,
- "logtostderr": false,
- "matchtitle": null,
- "max_downloads": null,
- "nooverwrites": false,
- "nopart": false,
- "noprogress": false,
- "outtmpl": "%(id)s.%(ext)s",
- "password": null,
- "playliststart": 1,
- "prefer_free_formats": false,
- "quiet": false,
- "ratelimit": null,
- "rejecttitle": null,
- "retries": 10,
- "simulate": false,
- "subtitleslang": null,
- "subtitlesformat": "best",
- "test": true,
- "updatetime": true,
- "usenetrc": false,
- "username": null,
- "verbose": true,
- "writedescription": false,
- "writeinfojson": true,
- "writesubtitles": false,
- "allsubtitles": false,
- "listsubtitles": false,
- "socket_timeout": 20,
- "fixup": "never"
-}
diff --git a/test/swftests/.gitignore b/test/swftests/.gitignore
deleted file mode 100644
index da97ff7ca..000000000
--- a/test/swftests/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*.swf
diff --git a/test/swftests/ArrayAccess.as b/test/swftests/ArrayAccess.as
deleted file mode 100644
index e22caa386..000000000
--- a/test/swftests/ArrayAccess.as
+++ /dev/null
@@ -1,19 +0,0 @@
-// input: [["a", "b", "c", "d"]]
-// output: ["c", "b", "a", "d"]
-
-package {
-public class ArrayAccess {
- public static function main(ar:Array):Array {
- var aa:ArrayAccess = new ArrayAccess();
- return aa.f(ar, 2);
- }
-
- private function f(ar:Array, num:Number):Array{
- var x:String = ar[0];
- var y:String = ar[num % ar.length];
- ar[0] = y;
- ar[num] = x;
- return ar;
- }
-}
-}
diff --git a/test/swftests/ClassCall.as b/test/swftests/ClassCall.as
deleted file mode 100644
index aef58daf3..000000000
--- a/test/swftests/ClassCall.as
+++ /dev/null
@@ -1,17 +0,0 @@
-// input: []
-// output: 121
-
-package {
-public class ClassCall {
- public static function main():int{
- var f:OtherClass = new OtherClass();
- return f.func(100,20);
- }
-}
-}
-
-class OtherClass {
- public function func(x: int, y: int):int {
- return x+y+1;
- }
-}
diff --git a/test/swftests/ClassConstruction.as b/test/swftests/ClassConstruction.as
deleted file mode 100644
index 436479f8f..000000000
--- a/test/swftests/ClassConstruction.as
+++ /dev/null
@@ -1,15 +0,0 @@
-// input: []
-// output: 0
-
-package {
-public class ClassConstruction {
- public static function main():int{
- var f:Foo = new Foo();
- return 0;
- }
-}
-}
-
-class Foo {
-
-}
diff --git a/test/swftests/ConstArrayAccess.as b/test/swftests/ConstArrayAccess.as
deleted file mode 100644
index 07dc3f460..000000000
--- a/test/swftests/ConstArrayAccess.as
+++ /dev/null
@@ -1,18 +0,0 @@
-// input: []
-// output: 4
-
-package {
-public class ConstArrayAccess {
- private static const x:int = 2;
- private static const ar:Array = ["42", "3411"];
-
- public static function main():int{
- var c:ConstArrayAccess = new ConstArrayAccess();
- return c.f();
- }
-
- public function f(): int {
- return ar[1].length;
- }
-}
-}
diff --git a/test/swftests/ConstantInt.as b/test/swftests/ConstantInt.as
deleted file mode 100644
index e0bbb6166..000000000
--- a/test/swftests/ConstantInt.as
+++ /dev/null
@@ -1,12 +0,0 @@
-// input: []
-// output: 2
-
-package {
-public class ConstantInt {
- private static const x:int = 2;
-
- public static function main():int{
- return x;
- }
-}
-}
diff --git a/test/swftests/DictCall.as b/test/swftests/DictCall.as
deleted file mode 100644
index c2d174cc2..000000000
--- a/test/swftests/DictCall.as
+++ /dev/null
@@ -1,10 +0,0 @@
-// input: [{"x": 1, "y": 2}]
-// output: 3
-
-package {
-public class DictCall {
- public static function main(d:Object):int{
- return d.x + d.y;
- }
-}
-}
diff --git a/test/swftests/EqualsOperator.as b/test/swftests/EqualsOperator.as
deleted file mode 100644
index 837a69a46..000000000
--- a/test/swftests/EqualsOperator.as
+++ /dev/null
@@ -1,10 +0,0 @@
-// input: []
-// output: false
-
-package {
-public class EqualsOperator {
- public static function main():Boolean{
- return 1 == 2;
- }
-}
-}
diff --git a/test/swftests/LocalVars.as b/test/swftests/LocalVars.as
deleted file mode 100644
index b2911a9f3..000000000
--- a/test/swftests/LocalVars.as
+++ /dev/null
@@ -1,13 +0,0 @@
-// input: [1, 2]
-// output: 3
-
-package {
-public class LocalVars {
- public static function main(a:int, b:int):int{
- var c:int = a + b + b;
- var d:int = c - b;
- var e:int = d;
- return e;
- }
-}
-}
diff --git a/test/swftests/MemberAssignment.as b/test/swftests/MemberAssignment.as
deleted file mode 100644
index dcba5e3ff..000000000
--- a/test/swftests/MemberAssignment.as
+++ /dev/null
@@ -1,22 +0,0 @@
-// input: [1]
-// output: 2
-
-package {
-public class MemberAssignment {
- public var v:int;
-
- public function g():int {
- return this.v;
- }
-
- public function f(a:int):int{
- this.v = a;
- return this.v + this.g();
- }
-
- public static function main(a:int): int {
- var v:MemberAssignment = new MemberAssignment();
- return v.f(a);
- }
-}
-}
diff --git a/test/swftests/NeOperator.as b/test/swftests/NeOperator.as
deleted file mode 100644
index 61dcbc4e9..000000000
--- a/test/swftests/NeOperator.as
+++ /dev/null
@@ -1,24 +0,0 @@
-// input: []
-// output: 123
-
-package {
-public class NeOperator {
- public static function main(): int {
- var res:int = 0;
- if (1 != 2) {
- res += 3;
- } else {
- res += 4;
- }
- if (2 != 2) {
- res += 10;
- } else {
- res += 20;
- }
- if (9 == 9) {
- res += 100;
- }
- return res;
- }
-}
-}
diff --git a/test/swftests/PrivateCall.as b/test/swftests/PrivateCall.as
deleted file mode 100644
index f1c110a37..000000000
--- a/test/swftests/PrivateCall.as
+++ /dev/null
@@ -1,21 +0,0 @@
-// input: []
-// output: 9
-
-package {
-public class PrivateCall {
- public static function main():int{
- var f:OtherClass = new OtherClass();
- return f.func();
- }
-}
-}
-
-class OtherClass {
- private function pf():int {
- return 9;
- }
-
- public function func():int {
- return this.pf();
- }
-}
diff --git a/test/swftests/PrivateVoidCall.as b/test/swftests/PrivateVoidCall.as
deleted file mode 100644
index 2cc016797..000000000
--- a/test/swftests/PrivateVoidCall.as
+++ /dev/null
@@ -1,22 +0,0 @@
-// input: []
-// output: 9
-
-package {
-public class PrivateVoidCall {
- public static function main():int{
- var f:OtherClass = new OtherClass();
- f.func();
- return 9;
- }
-}
-}
-
-class OtherClass {
- private function pf():void {
- ;
- }
-
- public function func():void {
- this.pf();
- }
-}
diff --git a/test/swftests/StaticAssignment.as b/test/swftests/StaticAssignment.as
deleted file mode 100644
index b061c219d..000000000
--- a/test/swftests/StaticAssignment.as
+++ /dev/null
@@ -1,13 +0,0 @@
-// input: [1]
-// output: 1
-
-package {
-public class StaticAssignment {
- public static var v:int;
-
- public static function main(a:int):int{
- v = a;
- return v;
- }
-}
-}
diff --git a/test/swftests/StaticRetrieval.as b/test/swftests/StaticRetrieval.as
deleted file mode 100644
index c8352d819..000000000
--- a/test/swftests/StaticRetrieval.as
+++ /dev/null
@@ -1,16 +0,0 @@
-// input: []
-// output: 1
-
-package {
-public class StaticRetrieval {
- public static var v:int;
-
- public static function main():int{
- if (v) {
- return 0;
- } else {
- return 1;
- }
- }
-}
-}
diff --git a/test/swftests/StringBasics.as b/test/swftests/StringBasics.as
deleted file mode 100644
index d27430b13..000000000
--- a/test/swftests/StringBasics.as
+++ /dev/null
@@ -1,11 +0,0 @@
-// input: []
-// output: 3
-
-package {
-public class StringBasics {
- public static function main():int{
- var s:String = "abc";
- return s.length;
- }
-}
-}
diff --git a/test/swftests/StringCharCodeAt.as b/test/swftests/StringCharCodeAt.as
deleted file mode 100644
index c20d74d65..000000000
--- a/test/swftests/StringCharCodeAt.as
+++ /dev/null
@@ -1,11 +0,0 @@
-// input: []
-// output: 9897
-
-package {
-public class StringCharCodeAt {
- public static function main():int{
- var s:String = "abc";
- return s.charCodeAt(1) * 100 + s.charCodeAt();
- }
-}
-}
diff --git a/test/swftests/StringConversion.as b/test/swftests/StringConversion.as
deleted file mode 100644
index c976f5042..000000000
--- a/test/swftests/StringConversion.as
+++ /dev/null
@@ -1,11 +0,0 @@
-// input: []
-// output: 2
-
-package {
-public class StringConversion {
- public static function main():int{
- var s:String = String(99);
- return s.length;
- }
-}
-}
diff --git a/test/test_InfoExtractor.py b/test/test_InfoExtractor.py
deleted file mode 100644
index 09100a1d6..000000000
--- a/test/test_InfoExtractor.py
+++ /dev/null
@@ -1,1407 +0,0 @@
-#!/usr/bin/env python
-
-from __future__ import unicode_literals
-
-# Allow direct execution
-import os
-import sys
-import unittest
-
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-import threading
-
-from test.helper import (
- expect_dict,
- expect_value,
- FakeYDL,
- http_server_port,
-)
-from youtube_dl.compat import (
- compat_etree_fromstring,
- compat_http_server,
- compat_open as open,
-)
-from youtube_dl.extractor.common import InfoExtractor
-from youtube_dl.extractor import (
- get_info_extractor,
- YoutubeIE,
-)
-from youtube_dl.utils import (
- encode_data_uri,
- ExtractorError,
- RegexNotFoundError,
- strip_jsonp,
-)
-
-
-TEAPOT_RESPONSE_STATUS = 418
-TEAPOT_RESPONSE_BODY = "
418 I'm a teapot
"
-
-
-class InfoExtractorTestRequestHandler(compat_http_server.BaseHTTPRequestHandler):
- def log_message(self, format, *args):
- pass
-
- def do_GET(self):
- if self.path == '/teapot':
- self.send_response(TEAPOT_RESPONSE_STATUS)
- self.send_header('Content-Type', 'text/html; charset=utf-8')
- self.end_headers()
- self.wfile.write(TEAPOT_RESPONSE_BODY.encode())
- else:
- assert False
-
-
-class DummyIE(InfoExtractor):
- pass
-
-
-class TestInfoExtractor(unittest.TestCase):
- def setUp(self):
- self.ie = DummyIE(FakeYDL())
-
- def test_ie_key(self):
- self.assertEqual(get_info_extractor(YoutubeIE.ie_key()), YoutubeIE)
-
- def test_html_search_regex(self):
- html = 'Watch this video
'
- search = lambda re, *args: self.ie._html_search_regex(re, html, *args)
- self.assertEqual(search(r'(.+?)
', 'foo'), 'Watch this video')
-
- def test_opengraph(self):
- ie = self.ie
- html = '''
-
-
-
-
-
-
-
-
-
- '''
- self.assertEqual(ie._og_search_title(html), 'Foo')
- self.assertEqual(ie._og_search_description(html), 'Some video\'s description ')
- self.assertEqual(ie._og_search_thumbnail(html), 'http://domain.com/pic.jpg?key1=val1&key2=val2')
- self.assertEqual(ie._og_search_video_url(html, default=None), None)
- self.assertEqual(ie._og_search_property('foobar', html), 'Foo')
- self.assertEqual(ie._og_search_property('test1', html), 'foo > < bar')
- self.assertEqual(ie._og_search_property('test2', html), 'foo >//< bar')
- self.assertEqual(ie._og_search_property('test3', html), 'Ill-formatted opengraph')
- self.assertEqual(ie._og_search_property(('test0', 'test1'), html), 'foo > < bar')
- self.assertRaises(RegexNotFoundError, ie._og_search_property, 'test0', html, None, fatal=True)
- self.assertRaises(RegexNotFoundError, ie._og_search_property, ('test0', 'test00'), html, None, fatal=True)
- self.assertEqual(ie._og_search_property('test4', html), 'unquoted-value')
-
- def test_html_search_meta(self):
- ie = self.ie
- html = '''
-
-
-
-
-
-
- '''
-
- self.assertEqual(ie._html_search_meta('a', html), '1')
- self.assertEqual(ie._html_search_meta('b', html), '2')
- self.assertEqual(ie._html_search_meta('c', html), '3')
- self.assertEqual(ie._html_search_meta('d', html), '4')
- self.assertEqual(ie._html_search_meta('e', html), '5')
- self.assertEqual(ie._html_search_meta('f', html), '6')
- self.assertEqual(ie._html_search_meta(('a', 'b', 'c'), html), '1')
- self.assertEqual(ie._html_search_meta(('c', 'b', 'a'), html), '3')
- self.assertEqual(ie._html_search_meta(('z', 'x', 'c'), html), '3')
- self.assertRaises(RegexNotFoundError, ie._html_search_meta, 'z', html, None, fatal=True)
- self.assertRaises(RegexNotFoundError, ie._html_search_meta, ('z', 'x'), html, None, fatal=True)
-
- def test_search_nextjs_data(self):
- html = '''
-
-
-
-
-
- Test _search_nextjs_data()
-
-
-
-
-
-
-'''
- search = self.ie._search_nextjs_data(html, 'testID')
- self.assertEqual(search['props']['pageProps']['video']['id'], 'testid')
- search = self.ie._search_nextjs_data(
- 'no next.js data here, move along', 'testID', default={'status': 0})
- self.assertEqual(search['status'], 0)
-
- def test_search_nuxt_data(self):
- html = '''
-
-
-
-
- Nuxt.js Test Page
-
-
-
-
-
-
-
-
-
-'''
- search = self.ie._search_nuxt_data(html, 'testID')
- self.assertEqual(search['track']['id'], 'testid')
-
- def test_search_json_ld_realworld(self):
- # https://github.com/ytdl-org/youtube-dl/issues/23306
- expect_dict(
- self,
- self.ie._search_json_ld(r'''''', None),
- {
- 'title': '1 On 1 With Kleio',
- 'description': 'Kleio Valentien',
- 'url': 'https://gvideo.eporner.com/xN49A1cT3eB/xN49A1cT3eB.mp4',
- 'timestamp': 1449347075,
- 'duration': 743.0,
- 'view_count': 1120958,
- 'width': 1920,
- 'height': 1080,
- })
-
- def test_download_json(self):
- uri = encode_data_uri(b'{"foo": "blah"}', 'application/json')
- self.assertEqual(self.ie._download_json(uri, None), {'foo': 'blah'})
- uri = encode_data_uri(b'callback({"foo": "blah"})', 'application/javascript')
- self.assertEqual(self.ie._download_json(uri, None, transform_source=strip_jsonp), {'foo': 'blah'})
- uri = encode_data_uri(b'{"foo": invalid}', 'application/json')
- self.assertRaises(ExtractorError, self.ie._download_json, uri, None)
- self.assertEqual(self.ie._download_json(uri, None, fatal=False), None)
-
- def test_parse_html5_media_entries(self):
- # inline video tag
- expect_dict(
- self,
- self.ie._parse_html5_media_entries(
- 'https://127.0.0.1/video.html',
- r'', None)[0],
- {
- 'formats': [{
- 'url': 'https://127.0.0.1/vid.mp4',
- }],
- })
-
- # from https://www.r18.com/
- # with kpbs in label
- expect_dict(
- self,
- self.ie._parse_html5_media_entries(
- 'https://www.r18.com/',
- r'''
-
- ''', None)[0],
- {
- 'formats': [{
- 'url': 'https://awscc3001.r18.com/litevideo/freepv/m/mgm/mgmr105/mgmr105_sm_w.mp4',
- 'ext': 'mp4',
- 'format_id': '300kbps',
- 'height': 240,
- 'tbr': 300,
- }, {
- 'url': 'https://awscc3001.r18.com/litevideo/freepv/m/mgm/mgmr105/mgmr105_dm_w.mp4',
- 'ext': 'mp4',
- 'format_id': '1000kbps',
- 'height': 480,
- 'tbr': 1000,
- }, {
- 'url': 'https://awscc3001.r18.com/litevideo/freepv/m/mgm/mgmr105/mgmr105_dmb_w.mp4',
- 'ext': 'mp4',
- 'format_id': '1500kbps',
- 'height': 740,
- 'tbr': 1500,
- }],
- 'thumbnail': '//pics.r18.com/digital/amateur/mgmr105/mgmr105jp.jpg'
- })
-
- # from https://www.csfd.cz/
- # with width and height
- expect_dict(
- self,
- self.ie._parse_html5_media_entries(
- 'https://www.csfd.cz/',
- r'''
-
- ''', None)[0],
- {
- 'formats': [{
- 'url': 'https://video.csfd.cz/files/videos/157/750/157750813/163327358_eac647.mp4',
- 'ext': 'mp4',
- 'width': 640,
- 'height': 360,
- }, {
- 'url': 'https://video.csfd.cz/files/videos/157/750/157750813/163327360_3d2646.mp4',
- 'ext': 'mp4',
- 'width': 1280,
- 'height': 720,
- }, {
- 'url': 'https://video.csfd.cz/files/videos/157/750/157750813/163327356_91f258.mp4',
- 'ext': 'mp4',
- 'width': 1920,
- 'height': 1080,
- }, {
- 'url': 'https://video.csfd.cz/files/videos/157/750/157750813/163327359_962b4a.webm',
- 'ext': 'webm',
- 'width': 640,
- 'height': 360,
- }, {
- 'url': 'https://video.csfd.cz/files/videos/157/750/157750813/163327361_6feee0.webm',
- 'ext': 'webm',
- 'width': 1280,
- 'height': 720,
- }, {
- 'url': 'https://video.csfd.cz/files/videos/157/750/157750813/163327357_8ab472.webm',
- 'ext': 'webm',
- 'width': 1920,
- 'height': 1080,
- }],
- 'subtitles': {
- 'cs': [{'url': 'https://video.csfd.cz/files/subtitles/163/344/163344115_4c388b.srt'}]
- },
- 'thumbnail': 'https://img.csfd.cz/files/images/film/video/preview/163/344/163344118_748d20.png?h360'
- })
-
- # from https://tamasha.com/v/Kkdjw
- # with height in label
- expect_dict(
- self,
- self.ie._parse_html5_media_entries(
- 'https://tamasha.com/v/Kkdjw',
- r'''
-
- ''', None)[0],
- {
- 'formats': [{
- 'url': 'https://s-v2.tamasha.com/statics/videos_file/19/8f/Kkdjw_198feff8577d0057536e905cce1fb61438dd64e0_n_240.mp4',
- }, {
- 'url': 'https://s-v2.tamasha.com/statics/videos_file/19/8f/Kkdjw_198feff8577d0057536e905cce1fb61438dd64e0_n_240.mp4',
- 'ext': 'mp4',
- 'format_id': '240p',
- 'height': 240,
- }, {
- 'url': 'https://s-v2.tamasha.com/statics/videos_file/20/00/Kkdjw_200041c66f657fc967db464d156eafbc1ed9fe6f_n_144.mp4',
- 'ext': 'mp4',
- 'format_id': '144p',
- 'height': 144,
- }]
- })
-
- # from https://www.directvnow.com
- # with data-src
- expect_dict(
- self,
- self.ie._parse_html5_media_entries(
- 'https://www.directvnow.com',
- r'''
-
- ''', None)[0],
- {
- 'formats': [{
- 'ext': 'mp4',
- 'url': 'https://cdn.directv.com/content/dam/dtv/prod/website_directvnow-international/videos/DTVN_hdr_HBO_v3.mp4',
- }]
- })
-
- # from https://www.directvnow.com
- # with data-src
- expect_dict(
- self,
- self.ie._parse_html5_media_entries(
- 'https://www.directvnow.com',
- r'''
-
- ''', None)[0],
- {
- 'formats': [{
- 'url': 'https://cdn.directv.com/content/dam/dtv/prod/website_directvnow-international/videos/DTVN_hdr_HBO_v3.mp4',
- 'ext': 'mp4',
- }]
- })
-
- # from https://www.klarna.com/uk/
- # with data-video-src
- expect_dict(
- self,
- self.ie._parse_html5_media_entries(
- 'https://www.directvnow.com',
- r'''
-
- ''', None)[0],
- {
- 'formats': [{
- 'url': 'https://www.klarna.com/uk/wp-content/uploads/sites/11/2019/01/KL062_Smooth3_0_DogWalking_5s_920x080_.mp4',
- 'ext': 'mp4',
- }],
- })
-
- # from https://0000.studio/
- # with type attribute but without extension in URL
- expect_dict(
- self,
- self.ie._parse_html5_media_entries(
- 'https://0000.studio',
- r'''
-
- ''', None)[0],
- {
- 'formats': [{
- 'url': 'https://d1ggyt9m8pwf3g.cloudfront.net/protected/ap-northeast-1:1864af40-28d5-492b-b739-b32314b1a527/archive/clip/838db6a7-8973-4cd6-840d-8517e4093c92',
- 'ext': 'mp4',
- }],
- })
-
- def test_extract_jwplayer_data_realworld(self):
- # from http://www.suffolk.edu/sjc/
- expect_dict(
- self,
- self.ie._extract_jwplayer_data(r'''
-
- ''', None, require_title=False),
- {
- 'id': 'XEgvuql4',
- 'formats': [{
- 'url': 'rtmp://192.138.214.154/live/sjclive',
- 'ext': 'flv'
- }]
- })
-
- # from https://www.pornoxo.com/videos/7564/striptease-from-sexy-secretary/
- expect_dict(
- self,
- self.ie._extract_jwplayer_data(r'''
-
- ''', 'dummy', require_title=False),
- {
- 'thumbnail': 'https://t03.vipstreamservice.com/thumbs/pxo-full/2009-12/14/a4b2157147afe5efa93ce1978e0265289c193874e02597.flv-full-13.jpg',
- 'formats': [{
- 'url': 'https://cdn.pornoxo.com/key=MF+oEbaxqTKb50P-w9G3nA,end=1489689259,ip=104.199.146.27/ip=104.199.146.27/speed=6573765/buffer=3.0/2009-12/4b2157147afe5efa93ce1978e0265289c193874e02597.flv',
- 'ext': 'flv'
- }]
- })
-
- # from http://www.indiedb.com/games/king-machine/videos
- expect_dict(
- self,
- self.ie._extract_jwplayer_data(r'''
-
- ''', 'dummy'),
- {
- 'title': 'king machine trailer 1',
- 'thumbnail': 'http://media.indiedb.com/cache/images/games/1/50/49678/thumb_620x2000/king-machine-trailer.mp4.jpg',
- 'formats': [{
- 'url': 'http://cdn.dbolical.com/cache/videos/games/1/50/49678/encode_mp4/king-machine-trailer.mp4',
- 'height': 360,
- 'ext': 'mp4'
- }, {
- 'url': 'http://cdn.dbolical.com/cache/videos/games/1/50/49678/encode720p_mp4/king-machine-trailer.mp4',
- 'height': 720,
- 'ext': 'mp4'
- }]
- })
-
- def test_parse_m3u8_formats(self):
- _TEST_CASES = [
- (
- # https://github.com/ytdl-org/youtube-dl/issues/11507
- # http://pluzz.francetv.fr/videos/le_ministere.html
- 'pluzz_francetv_11507',
- 'http://replayftv-vh.akamaihd.net/i/streaming-adaptatif_france-dom-tom/2017/S16/J2/156589847-58f59130c1f52-,standard1,standard2,standard3,standard4,standard5,.mp4.csmil/master.m3u8?caption=2017%2F16%2F156589847-1492488987.m3u8%3Afra%3AFrancais&audiotrack=0%3Afra%3AFrancais',
- [{
- 'url': 'http://replayftv-vh.akamaihd.net/i/streaming-adaptatif_france-dom-tom/2017/S16/J2/156589847-58f59130c1f52-,standard1,standard2,standard3,standard4,standard5,.mp4.csmil/index_0_av.m3u8?null=0',
- 'manifest_url': 'http://replayftv-vh.akamaihd.net/i/streaming-adaptatif_france-dom-tom/2017/S16/J2/156589847-58f59130c1f52-,standard1,standard2,standard3,standard4,standard5,.mp4.csmil/master.m3u8?caption=2017%2F16%2F156589847-1492488987.m3u8%3Afra%3AFrancais&audiotrack=0%3Afra%3AFrancais',
- 'ext': 'mp4',
- 'format_id': '180',
- 'protocol': 'm3u8',
- 'acodec': 'mp4a.40.2',
- 'vcodec': 'avc1.66.30',
- 'tbr': 180,
- 'width': 256,
- 'height': 144,
- }, {
- 'url': 'http://replayftv-vh.akamaihd.net/i/streaming-adaptatif_france-dom-tom/2017/S16/J2/156589847-58f59130c1f52-,standard1,standard2,standard3,standard4,standard5,.mp4.csmil/index_1_av.m3u8?null=0',
- 'manifest_url': 'http://replayftv-vh.akamaihd.net/i/streaming-adaptatif_france-dom-tom/2017/S16/J2/156589847-58f59130c1f52-,standard1,standard2,standard3,standard4,standard5,.mp4.csmil/master.m3u8?caption=2017%2F16%2F156589847-1492488987.m3u8%3Afra%3AFrancais&audiotrack=0%3Afra%3AFrancais',
- 'ext': 'mp4',
- 'format_id': '303',
- 'protocol': 'm3u8',
- 'acodec': 'mp4a.40.2',
- 'vcodec': 'avc1.66.30',
- 'tbr': 303,
- 'width': 320,
- 'height': 180,
- }, {
- 'url': 'http://replayftv-vh.akamaihd.net/i/streaming-adaptatif_france-dom-tom/2017/S16/J2/156589847-58f59130c1f52-,standard1,standard2,standard3,standard4,standard5,.mp4.csmil/index_2_av.m3u8?null=0',
- 'manifest_url': 'http://replayftv-vh.akamaihd.net/i/streaming-adaptatif_france-dom-tom/2017/S16/J2/156589847-58f59130c1f52-,standard1,standard2,standard3,standard4,standard5,.mp4.csmil/master.m3u8?caption=2017%2F16%2F156589847-1492488987.m3u8%3Afra%3AFrancais&audiotrack=0%3Afra%3AFrancais',
- 'ext': 'mp4',
- 'format_id': '575',
- 'protocol': 'm3u8',
- 'acodec': 'mp4a.40.2',
- 'vcodec': 'avc1.66.30',
- 'tbr': 575,
- 'width': 512,
- 'height': 288,
- }, {
- 'url': 'http://replayftv-vh.akamaihd.net/i/streaming-adaptatif_france-dom-tom/2017/S16/J2/156589847-58f59130c1f52-,standard1,standard2,standard3,standard4,standard5,.mp4.csmil/index_3_av.m3u8?null=0',
- 'manifest_url': 'http://replayftv-vh.akamaihd.net/i/streaming-adaptatif_france-dom-tom/2017/S16/J2/156589847-58f59130c1f52-,standard1,standard2,standard3,standard4,standard5,.mp4.csmil/master.m3u8?caption=2017%2F16%2F156589847-1492488987.m3u8%3Afra%3AFrancais&audiotrack=0%3Afra%3AFrancais',
- 'ext': 'mp4',
- 'format_id': '831',
- 'protocol': 'm3u8',
- 'acodec': 'mp4a.40.2',
- 'vcodec': 'avc1.77.30',
- 'tbr': 831,
- 'width': 704,
- 'height': 396,
- }, {
- 'url': 'http://replayftv-vh.akamaihd.net/i/streaming-adaptatif_france-dom-tom/2017/S16/J2/156589847-58f59130c1f52-,standard1,standard2,standard3,standard4,standard5,.mp4.csmil/index_4_av.m3u8?null=0',
- 'manifest_url': 'http://replayftv-vh.akamaihd.net/i/streaming-adaptatif_france-dom-tom/2017/S16/J2/156589847-58f59130c1f52-,standard1,standard2,standard3,standard4,standard5,.mp4.csmil/master.m3u8?caption=2017%2F16%2F156589847-1492488987.m3u8%3Afra%3AFrancais&audiotrack=0%3Afra%3AFrancais',
- 'ext': 'mp4',
- 'protocol': 'm3u8',
- 'format_id': '1467',
- 'acodec': 'mp4a.40.2',
- 'vcodec': 'avc1.77.30',
- 'tbr': 1467,
- 'width': 1024,
- 'height': 576,
- }]
- ),
- (
- # https://github.com/ytdl-org/youtube-dl/issues/11995
- # http://teamcoco.com/video/clueless-gamer-super-bowl-for-honor
- 'teamcoco_11995',
- 'http://ak.storage-w.teamcococdn.com/cdn/2017-02/98599/ed8f/main.m3u8',
- [{
- 'url': 'http://ak.storage-w.teamcococdn.com/cdn/2017-02/98599/ed8f/hls/CONAN_020217_Highlight_show-audio-160k_v4.m3u8',
- 'manifest_url': 'http://ak.storage-w.teamcococdn.com/cdn/2017-02/98599/ed8f/main.m3u8',
- 'ext': 'mp4',
- 'format_id': 'audio-0-Default',
- 'protocol': 'm3u8',
- 'vcodec': 'none',
- }, {
- 'url': 'http://ak.storage-w.teamcococdn.com/cdn/2017-02/98599/ed8f/hls/CONAN_020217_Highlight_show-audio-64k_v4.m3u8',
- 'manifest_url': 'http://ak.storage-w.teamcococdn.com/cdn/2017-02/98599/ed8f/main.m3u8',
- 'ext': 'mp4',
- 'format_id': 'audio-1-Default',
- 'protocol': 'm3u8',
- 'vcodec': 'none',
- }, {
- 'url': 'http://ak.storage-w.teamcococdn.com/cdn/2017-02/98599/ed8f/hls/CONAN_020217_Highlight_show-audio-64k_v4.m3u8',
- 'manifest_url': 'http://ak.storage-w.teamcococdn.com/cdn/2017-02/98599/ed8f/main.m3u8',
- 'ext': 'mp4',
- 'format_id': '71',
- 'protocol': 'm3u8',
- 'acodec': 'mp4a.40.5',
- 'vcodec': 'none',
- 'tbr': 71,
- }, {
- 'url': 'http://ak.storage-w.teamcococdn.com/cdn/2017-02/98599/ed8f/hls/CONAN_020217_Highlight_show-400k_v4.m3u8',
- 'manifest_url': 'http://ak.storage-w.teamcococdn.com/cdn/2017-02/98599/ed8f/main.m3u8',
- 'ext': 'mp4',
- 'format_id': '413',
- 'protocol': 'm3u8',
- 'acodec': 'none',
- 'vcodec': 'avc1.42001e',
- 'tbr': 413,
- 'width': 400,
- 'height': 224,
- }, {
- 'url': 'http://ak.storage-w.teamcococdn.com/cdn/2017-02/98599/ed8f/hls/CONAN_020217_Highlight_show-400k_v4.m3u8',
- 'manifest_url': 'http://ak.storage-w.teamcococdn.com/cdn/2017-02/98599/ed8f/main.m3u8',
- 'ext': 'mp4',
- 'format_id': '522',
- 'protocol': 'm3u8',
- 'acodec': 'none',
- 'vcodec': 'avc1.42001e',
- 'tbr': 522,
- 'width': 400,
- 'height': 224,
- }, {
- 'url': 'http://ak.storage-w.teamcococdn.com/cdn/2017-02/98599/ed8f/hls/CONAN_020217_Highlight_show-1m_v4.m3u8',
- 'manifest_url': 'http://ak.storage-w.teamcococdn.com/cdn/2017-02/98599/ed8f/main.m3u8',
- 'ext': 'mp4',
- 'format_id': '1205',
- 'protocol': 'm3u8',
- 'acodec': 'none',
- 'vcodec': 'avc1.4d001e',
- 'tbr': 1205,
- 'width': 640,
- 'height': 360,
- }, {
- 'url': 'http://ak.storage-w.teamcococdn.com/cdn/2017-02/98599/ed8f/hls/CONAN_020217_Highlight_show-2m_v4.m3u8',
- 'manifest_url': 'http://ak.storage-w.teamcococdn.com/cdn/2017-02/98599/ed8f/main.m3u8',
- 'ext': 'mp4',
- 'format_id': '2374',
- 'protocol': 'm3u8',
- 'acodec': 'none',
- 'vcodec': 'avc1.4d001f',
- 'tbr': 2374,
- 'width': 1024,
- 'height': 576,
- }]
- ),
- (
- # https://github.com/ytdl-org/youtube-dl/issues/12211
- # http://video.toggle.sg/en/series/whoopie-s-world/ep3/478601
- 'toggle_mobile_12211',
- 'http://cdnapi.kaltura.com/p/2082311/sp/208231100/playManifest/protocol/http/entryId/0_89q6e8ku/format/applehttp/tags/mobile_sd/f/a.m3u8',
- [{
- 'url': 'http://k.toggle.sg/fhls/p/2082311/sp/208231100/serveFlavor/entryId/0_89q6e8ku/v/2/pv/1/flavorId/0_sa2ntrdg/name/a.mp4/index.m3u8',
- 'manifest_url': 'http://cdnapi.kaltura.com/p/2082311/sp/208231100/playManifest/protocol/http/entryId/0_89q6e8ku/format/applehttp/tags/mobile_sd/f/a.m3u8',
- 'ext': 'mp4',
- 'format_id': 'audio-English',
- 'protocol': 'm3u8',
- 'language': 'eng',
- 'vcodec': 'none',
- }, {
- 'url': 'http://k.toggle.sg/fhls/p/2082311/sp/208231100/serveFlavor/entryId/0_89q6e8ku/v/2/pv/1/flavorId/0_r7y0nitg/name/a.mp4/index.m3u8',
- 'manifest_url': 'http://cdnapi.kaltura.com/p/2082311/sp/208231100/playManifest/protocol/http/entryId/0_89q6e8ku/format/applehttp/tags/mobile_sd/f/a.m3u8',
- 'ext': 'mp4',
- 'format_id': 'audio-Undefined',
- 'protocol': 'm3u8',
- 'language': 'und',
- 'vcodec': 'none',
- }, {
- 'url': 'http://k.toggle.sg/fhls/p/2082311/sp/208231100/serveFlavor/entryId/0_89q6e8ku/v/2/pv/1/flavorId/0_qlk9hlzr/name/a.mp4/index.m3u8',
- 'manifest_url': 'http://cdnapi.kaltura.com/p/2082311/sp/208231100/playManifest/protocol/http/entryId/0_89q6e8ku/format/applehttp/tags/mobile_sd/f/a.m3u8',
- 'ext': 'mp4',
- 'format_id': '155',
- 'protocol': 'm3u8',
- 'tbr': 155.648,
- 'width': 320,
- 'height': 180,
- }, {
- 'url': 'http://k.toggle.sg/fhls/p/2082311/sp/208231100/serveFlavor/entryId/0_89q6e8ku/v/2/pv/1/flavorId/0_oefackmi/name/a.mp4/index.m3u8',
- 'manifest_url': 'http://cdnapi.kaltura.com/p/2082311/sp/208231100/playManifest/protocol/http/entryId/0_89q6e8ku/format/applehttp/tags/mobile_sd/f/a.m3u8',
- 'ext': 'mp4',
- 'format_id': '502',
- 'protocol': 'm3u8',
- 'tbr': 502.784,
- 'width': 480,
- 'height': 270,
- }, {
- 'url': 'http://k.toggle.sg/fhls/p/2082311/sp/208231100/serveFlavor/entryId/0_89q6e8ku/v/12/pv/1/flavorId/0_vyg9pj7k/name/a.mp4/index.m3u8',
- 'manifest_url': 'http://cdnapi.kaltura.com/p/2082311/sp/208231100/playManifest/protocol/http/entryId/0_89q6e8ku/format/applehttp/tags/mobile_sd/f/a.m3u8',
- 'ext': 'mp4',
- 'format_id': '827',
- 'protocol': 'm3u8',
- 'tbr': 827.392,
- 'width': 640,
- 'height': 360,
- }, {
- 'url': 'http://k.toggle.sg/fhls/p/2082311/sp/208231100/serveFlavor/entryId/0_89q6e8ku/v/12/pv/1/flavorId/0_50n4psvx/name/a.mp4/index.m3u8',
- 'manifest_url': 'http://cdnapi.kaltura.com/p/2082311/sp/208231100/playManifest/protocol/http/entryId/0_89q6e8ku/format/applehttp/tags/mobile_sd/f/a.m3u8',
- 'ext': 'mp4',
- 'format_id': '1396',
- 'protocol': 'm3u8',
- 'tbr': 1396.736,
- 'width': 854,
- 'height': 480,
- }]
- ),
- (
- # http://www.twitch.tv/riotgames/v/6528877
- 'twitch_vod',
- 'https://usher.ttvnw.net/vod/6528877?allow_source=true&allow_audio_only=true&allow_spectre=true&player=twitchweb&nauth=%7B%22user_id%22%3Anull%2C%22vod_id%22%3A6528877%2C%22expires%22%3A1492887874%2C%22chansub%22%3A%7B%22restricted_bitrates%22%3A%5B%5D%7D%2C%22privileged%22%3Afalse%2C%22https_required%22%3Afalse%7D&nauthsig=3e29296a6824a0f48f9e731383f77a614fc79bee',
- [{
- 'url': 'https://vod.edgecast.hls.ttvnw.net/e5da31ab49_riotgames_15001215120_261543898/audio_only/index-muted-HM49I092CC.m3u8',
- 'manifest_url': 'https://usher.ttvnw.net/vod/6528877?allow_source=true&allow_audio_only=true&allow_spectre=true&player=twitchweb&nauth=%7B%22user_id%22%3Anull%2C%22vod_id%22%3A6528877%2C%22expires%22%3A1492887874%2C%22chansub%22%3A%7B%22restricted_bitrates%22%3A%5B%5D%7D%2C%22privileged%22%3Afalse%2C%22https_required%22%3Afalse%7D&nauthsig=3e29296a6824a0f48f9e731383f77a614fc79bee',
- 'ext': 'mp4',
- 'format_id': 'Audio Only',
- 'protocol': 'm3u8',
- 'acodec': 'mp4a.40.2',
- 'vcodec': 'none',
- 'tbr': 182.725,
- }, {
- 'url': 'https://vod.edgecast.hls.ttvnw.net/e5da31ab49_riotgames_15001215120_261543898/mobile/index-muted-HM49I092CC.m3u8',
- 'manifest_url': 'https://usher.ttvnw.net/vod/6528877?allow_source=true&allow_audio_only=true&allow_spectre=true&player=twitchweb&nauth=%7B%22user_id%22%3Anull%2C%22vod_id%22%3A6528877%2C%22expires%22%3A1492887874%2C%22chansub%22%3A%7B%22restricted_bitrates%22%3A%5B%5D%7D%2C%22privileged%22%3Afalse%2C%22https_required%22%3Afalse%7D&nauthsig=3e29296a6824a0f48f9e731383f77a614fc79bee',
- 'ext': 'mp4',
- 'format_id': 'Mobile',
- 'protocol': 'm3u8',
- 'acodec': 'mp4a.40.2',
- 'vcodec': 'avc1.42C00D',
- 'tbr': 280.474,
- 'width': 400,
- 'height': 226,
- }, {
- 'url': 'https://vod.edgecast.hls.ttvnw.net/e5da31ab49_riotgames_15001215120_261543898/low/index-muted-HM49I092CC.m3u8',
- 'manifest_url': 'https://usher.ttvnw.net/vod/6528877?allow_source=true&allow_audio_only=true&allow_spectre=true&player=twitchweb&nauth=%7B%22user_id%22%3Anull%2C%22vod_id%22%3A6528877%2C%22expires%22%3A1492887874%2C%22chansub%22%3A%7B%22restricted_bitrates%22%3A%5B%5D%7D%2C%22privileged%22%3Afalse%2C%22https_required%22%3Afalse%7D&nauthsig=3e29296a6824a0f48f9e731383f77a614fc79bee',
- 'ext': 'mp4',
- 'format_id': 'Low',
- 'protocol': 'm3u8',
- 'acodec': 'mp4a.40.2',
- 'vcodec': 'avc1.42C01E',
- 'tbr': 628.347,
- 'width': 640,
- 'height': 360,
- }, {
- 'url': 'https://vod.edgecast.hls.ttvnw.net/e5da31ab49_riotgames_15001215120_261543898/medium/index-muted-HM49I092CC.m3u8',
- 'manifest_url': 'https://usher.ttvnw.net/vod/6528877?allow_source=true&allow_audio_only=true&allow_spectre=true&player=twitchweb&nauth=%7B%22user_id%22%3Anull%2C%22vod_id%22%3A6528877%2C%22expires%22%3A1492887874%2C%22chansub%22%3A%7B%22restricted_bitrates%22%3A%5B%5D%7D%2C%22privileged%22%3Afalse%2C%22https_required%22%3Afalse%7D&nauthsig=3e29296a6824a0f48f9e731383f77a614fc79bee',
- 'ext': 'mp4',
- 'format_id': 'Medium',
- 'protocol': 'm3u8',
- 'acodec': 'mp4a.40.2',
- 'vcodec': 'avc1.42C01E',
- 'tbr': 893.387,
- 'width': 852,
- 'height': 480,
- }, {
- 'url': 'https://vod.edgecast.hls.ttvnw.net/e5da31ab49_riotgames_15001215120_261543898/high/index-muted-HM49I092CC.m3u8',
- 'manifest_url': 'https://usher.ttvnw.net/vod/6528877?allow_source=true&allow_audio_only=true&allow_spectre=true&player=twitchweb&nauth=%7B%22user_id%22%3Anull%2C%22vod_id%22%3A6528877%2C%22expires%22%3A1492887874%2C%22chansub%22%3A%7B%22restricted_bitrates%22%3A%5B%5D%7D%2C%22privileged%22%3Afalse%2C%22https_required%22%3Afalse%7D&nauthsig=3e29296a6824a0f48f9e731383f77a614fc79bee',
- 'ext': 'mp4',
- 'format_id': 'High',
- 'protocol': 'm3u8',
- 'acodec': 'mp4a.40.2',
- 'vcodec': 'avc1.42C01F',
- 'tbr': 1603.789,
- 'width': 1280,
- 'height': 720,
- }, {
- 'url': 'https://vod.edgecast.hls.ttvnw.net/e5da31ab49_riotgames_15001215120_261543898/chunked/index-muted-HM49I092CC.m3u8',
- 'manifest_url': 'https://usher.ttvnw.net/vod/6528877?allow_source=true&allow_audio_only=true&allow_spectre=true&player=twitchweb&nauth=%7B%22user_id%22%3Anull%2C%22vod_id%22%3A6528877%2C%22expires%22%3A1492887874%2C%22chansub%22%3A%7B%22restricted_bitrates%22%3A%5B%5D%7D%2C%22privileged%22%3Afalse%2C%22https_required%22%3Afalse%7D&nauthsig=3e29296a6824a0f48f9e731383f77a614fc79bee',
- 'ext': 'mp4',
- 'format_id': 'Source',
- 'protocol': 'm3u8',
- 'acodec': 'mp4a.40.2',
- 'vcodec': 'avc1.100.31',
- 'tbr': 3214.134,
- 'width': 1280,
- 'height': 720,
- }]
- ),
- (
- # http://www.vidio.com/watch/165683-dj_ambred-booyah-live-2015
- # EXT-X-STREAM-INF tag with NAME attribute that is not defined
- # in HLS specification
- 'vidio',
- 'https://www.vidio.com/videos/165683/playlist.m3u8',
- [{
- 'url': 'https://cdn1-a.production.vidio.static6.com/uploads/165683/dj_ambred-4383-b300.mp4.m3u8',
- 'manifest_url': 'https://www.vidio.com/videos/165683/playlist.m3u8',
- 'ext': 'mp4',
- 'format_id': '270p 3G',
- 'protocol': 'm3u8',
- 'tbr': 300,
- 'width': 480,
- 'height': 270,
- }, {
- 'url': 'https://cdn1-a.production.vidio.static6.com/uploads/165683/dj_ambred-4383-b600.mp4.m3u8',
- 'manifest_url': 'https://www.vidio.com/videos/165683/playlist.m3u8',
- 'ext': 'mp4',
- 'format_id': '360p SD',
- 'protocol': 'm3u8',
- 'tbr': 600,
- 'width': 640,
- 'height': 360,
- }, {
- 'url': 'https://cdn1-a.production.vidio.static6.com/uploads/165683/dj_ambred-4383-b1200.mp4.m3u8',
- 'manifest_url': 'https://www.vidio.com/videos/165683/playlist.m3u8',
- 'ext': 'mp4',
- 'format_id': '720p HD',
- 'protocol': 'm3u8',
- 'tbr': 1200,
- 'width': 1280,
- 'height': 720,
- }]
- ),
- (
- # https://github.com/ytdl-org/youtube-dl/issues/18923
- # https://www.ted.com/talks/boris_hesser_a_grassroots_healthcare_revolution_in_africa
- 'ted_18923',
- 'http://hls.ted.com/talks/31241.m3u8',
- [{
- 'url': 'http://hls.ted.com/videos/BorisHesser_2018S/audio/600k.m3u8?nobumpers=true&uniqueId=76011e2b',
- 'format_id': '600k-Audio',
- 'vcodec': 'none',
- }, {
- 'url': 'http://hls.ted.com/videos/BorisHesser_2018S/audio/600k.m3u8?nobumpers=true&uniqueId=76011e2b',
- 'format_id': '68',
- 'vcodec': 'none',
- }, {
- 'url': 'http://hls.ted.com/videos/BorisHesser_2018S/video/64k.m3u8?nobumpers=true&uniqueId=76011e2b',
- 'format_id': '163',
- 'acodec': 'none',
- 'width': 320,
- 'height': 180,
- }, {
- 'url': 'http://hls.ted.com/videos/BorisHesser_2018S/video/180k.m3u8?nobumpers=true&uniqueId=76011e2b',
- 'format_id': '481',
- 'acodec': 'none',
- 'width': 512,
- 'height': 288,
- }, {
- 'url': 'http://hls.ted.com/videos/BorisHesser_2018S/video/320k.m3u8?nobumpers=true&uniqueId=76011e2b',
- 'format_id': '769',
- 'acodec': 'none',
- 'width': 512,
- 'height': 288,
- }, {
- 'url': 'http://hls.ted.com/videos/BorisHesser_2018S/video/450k.m3u8?nobumpers=true&uniqueId=76011e2b',
- 'format_id': '984',
- 'acodec': 'none',
- 'width': 512,
- 'height': 288,
- }, {
- 'url': 'http://hls.ted.com/videos/BorisHesser_2018S/video/600k.m3u8?nobumpers=true&uniqueId=76011e2b',
- 'format_id': '1255',
- 'acodec': 'none',
- 'width': 640,
- 'height': 360,
- }, {
- 'url': 'http://hls.ted.com/videos/BorisHesser_2018S/video/950k.m3u8?nobumpers=true&uniqueId=76011e2b',
- 'format_id': '1693',
- 'acodec': 'none',
- 'width': 853,
- 'height': 480,
- }, {
- 'url': 'http://hls.ted.com/videos/BorisHesser_2018S/video/1500k.m3u8?nobumpers=true&uniqueId=76011e2b',
- 'format_id': '2462',
- 'acodec': 'none',
- 'width': 1280,
- 'height': 720,
- }]
- ),
- ]
-
- for m3u8_file, m3u8_url, expected_formats in _TEST_CASES:
- with open('./test/testdata/m3u8/%s.m3u8' % m3u8_file,
- mode='r', encoding='utf-8') as f:
- formats = self.ie._parse_m3u8_formats(
- f.read(), m3u8_url, ext='mp4')
- self.ie._sort_formats(formats)
- expect_value(self, formats, expected_formats, None)
-
- def test_parse_mpd_formats(self):
- _TEST_CASES = [
- (
- # https://github.com/ytdl-org/youtube-dl/issues/13919
- # Also tests duplicate representation ids, see
- # https://github.com/ytdl-org/youtube-dl/issues/15111
- 'float_duration',
- 'http://unknown/manifest.mpd', # mpd_url
- None, # mpd_base_url
- [{
- 'manifest_url': 'http://unknown/manifest.mpd',
- 'ext': 'm4a',
- 'format_id': '318597',
- 'format_note': 'DASH audio',
- 'protocol': 'http_dash_segments',
- 'acodec': 'mp4a.40.2',
- 'vcodec': 'none',
- 'tbr': 61.587,
- }, {
- 'manifest_url': 'http://unknown/manifest.mpd',
- 'ext': 'mp4',
- 'format_id': '318597',
- 'format_note': 'DASH video',
- 'protocol': 'http_dash_segments',
- 'acodec': 'none',
- 'vcodec': 'avc1.42001f',
- 'tbr': 318.597,
- 'width': 340,
- 'height': 192,
- }, {
- 'manifest_url': 'http://unknown/manifest.mpd',
- 'ext': 'mp4',
- 'format_id': '638590',
- 'format_note': 'DASH video',
- 'protocol': 'http_dash_segments',
- 'acodec': 'none',
- 'vcodec': 'avc1.42001f',
- 'tbr': 638.59,
- 'width': 512,
- 'height': 288,
- }, {
- 'manifest_url': 'http://unknown/manifest.mpd',
- 'ext': 'mp4',
- 'format_id': '1022565',
- 'format_note': 'DASH video',
- 'protocol': 'http_dash_segments',
- 'acodec': 'none',
- 'vcodec': 'avc1.4d001f',
- 'tbr': 1022.565,
- 'width': 688,
- 'height': 384,
- }, {
- 'manifest_url': 'http://unknown/manifest.mpd',
- 'ext': 'mp4',
- 'format_id': '2046506',
- 'format_note': 'DASH video',
- 'protocol': 'http_dash_segments',
- 'acodec': 'none',
- 'vcodec': 'avc1.4d001f',
- 'tbr': 2046.506,
- 'width': 1024,
- 'height': 576,
- }, {
- 'manifest_url': 'http://unknown/manifest.mpd',
- 'ext': 'mp4',
- 'format_id': '3998017',
- 'format_note': 'DASH video',
- 'protocol': 'http_dash_segments',
- 'acodec': 'none',
- 'vcodec': 'avc1.640029',
- 'tbr': 3998.017,
- 'width': 1280,
- 'height': 720,
- }, {
- 'manifest_url': 'http://unknown/manifest.mpd',
- 'ext': 'mp4',
- 'format_id': '5997485',
- 'format_note': 'DASH video',
- 'protocol': 'http_dash_segments',
- 'acodec': 'none',
- 'vcodec': 'avc1.640032',
- 'tbr': 5997.485,
- 'width': 1920,
- 'height': 1080,
- }],
- {},
- ), (
- # https://github.com/ytdl-org/youtube-dl/pull/14844
- 'urls_only',
- 'http://unknown/manifest.mpd', # mpd_url
- None, # mpd_base_url
- [{
- 'manifest_url': 'http://unknown/manifest.mpd',
- 'ext': 'mp4',
- 'format_id': 'h264_aac_144p_m4s',
- 'format_note': 'DASH video',
- 'protocol': 'http_dash_segments',
- 'acodec': 'mp4a.40.2',
- 'vcodec': 'avc3.42c01e',
- 'tbr': 200,
- 'width': 256,
- 'height': 144,
- }, {
- 'manifest_url': 'http://unknown/manifest.mpd',
- 'ext': 'mp4',
- 'format_id': 'h264_aac_240p_m4s',
- 'format_note': 'DASH video',
- 'protocol': 'http_dash_segments',
- 'acodec': 'mp4a.40.2',
- 'vcodec': 'avc3.42c01e',
- 'tbr': 400,
- 'width': 424,
- 'height': 240,
- }, {
- 'manifest_url': 'http://unknown/manifest.mpd',
- 'ext': 'mp4',
- 'format_id': 'h264_aac_360p_m4s',
- 'format_note': 'DASH video',
- 'protocol': 'http_dash_segments',
- 'acodec': 'mp4a.40.2',
- 'vcodec': 'avc3.42c01e',
- 'tbr': 800,
- 'width': 640,
- 'height': 360,
- }, {
- 'manifest_url': 'http://unknown/manifest.mpd',
- 'ext': 'mp4',
- 'format_id': 'h264_aac_480p_m4s',
- 'format_note': 'DASH video',
- 'protocol': 'http_dash_segments',
- 'acodec': 'mp4a.40.2',
- 'vcodec': 'avc3.42c01e',
- 'tbr': 1200,
- 'width': 856,
- 'height': 480,
- }, {
- 'manifest_url': 'http://unknown/manifest.mpd',
- 'ext': 'mp4',
- 'format_id': 'h264_aac_576p_m4s',
- 'format_note': 'DASH video',
- 'protocol': 'http_dash_segments',
- 'acodec': 'mp4a.40.2',
- 'vcodec': 'avc3.42c01e',
- 'tbr': 1600,
- 'width': 1024,
- 'height': 576,
- }, {
- 'manifest_url': 'http://unknown/manifest.mpd',
- 'ext': 'mp4',
- 'format_id': 'h264_aac_720p_m4s',
- 'format_note': 'DASH video',
- 'protocol': 'http_dash_segments',
- 'acodec': 'mp4a.40.2',
- 'vcodec': 'avc3.42c01e',
- 'tbr': 2400,
- 'width': 1280,
- 'height': 720,
- }, {
- 'manifest_url': 'http://unknown/manifest.mpd',
- 'ext': 'mp4',
- 'format_id': 'h264_aac_1080p_m4s',
- 'format_note': 'DASH video',
- 'protocol': 'http_dash_segments',
- 'acodec': 'mp4a.40.2',
- 'vcodec': 'avc3.42c01e',
- 'tbr': 4400,
- 'width': 1920,
- 'height': 1080,
- }],
- {},
- ), (
- # https://github.com/ytdl-org/youtube-dl/issues/20346
- # Media considered unfragmented even though it contains
- # Initialization tag
- 'unfragmented',
- 'https://v.redd.it/hw1x7rcg7zl21/DASHPlaylist.mpd', # mpd_url
- 'https://v.redd.it/hw1x7rcg7zl21', # mpd_base_url
- [{
- 'url': 'https://v.redd.it/hw1x7rcg7zl21/audio',
- 'manifest_url': 'https://v.redd.it/hw1x7rcg7zl21/DASHPlaylist.mpd',
- 'ext': 'm4a',
- 'format_id': 'AUDIO-1',
- 'format_note': 'DASH audio',
- 'container': 'm4a_dash',
- 'acodec': 'mp4a.40.2',
- 'vcodec': 'none',
- 'tbr': 129.87,
- 'asr': 48000,
-
- }, {
- 'url': 'https://v.redd.it/hw1x7rcg7zl21/DASH_240',
- 'manifest_url': 'https://v.redd.it/hw1x7rcg7zl21/DASHPlaylist.mpd',
- 'ext': 'mp4',
- 'format_id': 'VIDEO-2',
- 'format_note': 'DASH video',
- 'container': 'mp4_dash',
- 'acodec': 'none',
- 'vcodec': 'avc1.4d401e',
- 'tbr': 608.0,
- 'width': 240,
- 'height': 240,
- 'fps': 30,
- }, {
- 'url': 'https://v.redd.it/hw1x7rcg7zl21/DASH_360',
- 'manifest_url': 'https://v.redd.it/hw1x7rcg7zl21/DASHPlaylist.mpd',
- 'ext': 'mp4',
- 'format_id': 'VIDEO-1',
- 'format_note': 'DASH video',
- 'container': 'mp4_dash',
- 'acodec': 'none',
- 'vcodec': 'avc1.4d401e',
- 'tbr': 804.261,
- 'width': 360,
- 'height': 360,
- 'fps': 30,
- }],
- {},
- ), (
- # https://github.com/ytdl-org/youtube-dl/issues/30235
- # Bento4 generated test mpd
- # mp4dash --mpd-name=manifest.mpd --no-split --use-segment-list mediafiles
- 'url_and_range',
- 'http://unknown/manifest.mpd', # mpd_url
- 'http://unknown/', # mpd_base_url
- [{
- 'manifest_url': 'http://unknown/manifest.mpd',
- 'fragment_base_url': 'http://unknown/',
- 'ext': 'm4a',
- 'format_id': 'audio-und-mp4a.40.2',
- 'format_note': 'DASH audio',
- 'container': 'm4a_dash',
- 'protocol': 'http_dash_segments',
- 'acodec': 'mp4a.40.2',
- 'vcodec': 'none',
- 'tbr': 98.808,
- }, {
- 'manifest_url': 'http://unknown/manifest.mpd',
- 'fragment_base_url': 'http://unknown/',
- 'ext': 'mp4',
- 'format_id': 'video-avc1',
- 'format_note': 'DASH video',
- 'container': 'mp4_dash',
- 'protocol': 'http_dash_segments',
- 'acodec': 'none',
- 'vcodec': 'avc1.4D401E',
- 'tbr': 699.597,
- 'width': 768,
- 'height': 432
- }],
- {},
- ), (
- # https://github.com/ytdl-org/youtube-dl/issues/27575
- # GPAC generated test mpd
- # MP4Box -dash 10000 -single-file -out manifest.mpd mediafiles
- 'range_only',
- 'http://unknown/manifest.mpd', # mpd_url
- 'http://unknown/', # mpd_base_url
- [{
- 'manifest_url': 'http://unknown/manifest.mpd',
- 'fragment_base_url': 'http://unknown/audio_dashinit.mp4',
- 'ext': 'm4a',
- 'format_id': '2',
- 'format_note': 'DASH audio',
- 'container': 'm4a_dash',
- 'protocol': 'http_dash_segments',
- 'acodec': 'mp4a.40.2',
- 'vcodec': 'none',
- 'tbr': 98.096,
- }, {
- 'manifest_url': 'http://unknown/manifest.mpd',
- 'fragment_base_url': 'http://unknown/video_dashinit.mp4',
- 'ext': 'mp4',
- 'format_id': '1',
- 'format_note': 'DASH video',
- 'container': 'mp4_dash',
- 'protocol': 'http_dash_segments',
- 'acodec': 'none',
- 'vcodec': 'avc1.4D401E',
- 'tbr': 526.987,
- 'width': 768,
- 'height': 432
- }],
- {},
- ), (
- 'subtitles',
- 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
- 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/',
- [{
- 'format_id': 'audio=128001',
- 'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
- 'ext': 'm4a',
- 'tbr': 128.001,
- 'asr': 48000,
- 'format_note': 'DASH audio',
- 'container': 'm4a_dash',
- 'vcodec': 'none',
- 'acodec': 'mp4a.40.2',
- 'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
- 'fragment_base_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/dash/',
- 'protocol': 'http_dash_segments',
- }, {
- 'format_id': 'video=100000',
- 'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
- 'ext': 'mp4',
- 'width': 336,
- 'height': 144,
- 'tbr': 100,
- 'format_note': 'DASH video',
- 'container': 'mp4_dash',
- 'vcodec': 'avc1.4D401F',
- 'acodec': 'none',
- 'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
- 'fragment_base_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/dash/',
- 'protocol': 'http_dash_segments',
- }, {
- 'format_id': 'video=326000',
- 'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
- 'ext': 'mp4',
- 'width': 562,
- 'height': 240,
- 'tbr': 326,
- 'format_note': 'DASH video',
- 'container': 'mp4_dash',
- 'vcodec': 'avc1.4D401F',
- 'acodec': 'none',
- 'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
- 'fragment_base_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/dash/',
- 'protocol': 'http_dash_segments',
- }, {
- 'format_id': 'video=698000',
- 'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
- 'ext': 'mp4',
- 'width': 844,
- 'height': 360,
- 'tbr': 698,
- 'format_note': 'DASH video',
- 'container': 'mp4_dash',
- 'vcodec': 'avc1.4D401F',
- 'acodec': 'none',
- 'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
- 'fragment_base_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/dash/',
- 'protocol': 'http_dash_segments',
- }, {
- 'format_id': 'video=1493000',
- 'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
- 'ext': 'mp4',
- 'width': 1126,
- 'height': 480,
- 'tbr': 1493,
- 'format_note': 'DASH video',
- 'container': 'mp4_dash',
- 'vcodec': 'avc1.4D401F',
- 'acodec': 'none',
- 'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
- 'fragment_base_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/dash/',
- 'protocol': 'http_dash_segments',
- }, {
- 'format_id': 'video=4482000',
- 'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
- 'ext': 'mp4',
- 'width': 1688,
- 'height': 720,
- 'tbr': 4482,
- 'format_note': 'DASH video',
- 'container': 'mp4_dash',
- 'vcodec': 'avc1.4D401F',
- 'acodec': 'none',
- 'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
- 'fragment_base_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/dash/',
- 'protocol': 'http_dash_segments',
- }],
- {
- 'en': [
- {
- 'ext': 'mp4',
- 'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
- 'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
- 'fragment_base_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/dash/',
- 'protocol': 'http_dash_segments',
- }
- ]
- },
- )
- ]
-
- for mpd_file, mpd_url, mpd_base_url, expected_formats, expected_subtitles in _TEST_CASES:
- with open('./test/testdata/mpd/%s.mpd' % mpd_file,
- mode='r', encoding='utf-8') as f:
- formats, subtitles = self.ie._parse_mpd_formats_and_subtitles(
- compat_etree_fromstring(f.read().encode('utf-8')),
- mpd_base_url=mpd_base_url, mpd_url=mpd_url)
- self.ie._sort_formats(formats)
- expect_value(self, formats, expected_formats, None)
- expect_value(self, subtitles, expected_subtitles, None)
-
- def test_parse_f4m_formats(self):
- _TEST_CASES = [
- (
- # https://github.com/ytdl-org/youtube-dl/issues/14660
- 'custom_base_url',
- 'http://api.new.livestream.com/accounts/6115179/events/6764928/videos/144884262.f4m',
- [{
- 'manifest_url': 'http://api.new.livestream.com/accounts/6115179/events/6764928/videos/144884262.f4m',
- 'ext': 'flv',
- 'format_id': '2148',
- 'protocol': 'f4m',
- 'tbr': 2148,
- 'width': 1280,
- 'height': 720,
- }]
- ),
- ]
-
- for f4m_file, f4m_url, expected_formats in _TEST_CASES:
- with open('./test/testdata/f4m/%s.f4m' % f4m_file,
- mode='r', encoding='utf-8') as f:
- formats = self.ie._parse_f4m_formats(
- compat_etree_fromstring(f.read().encode('utf-8')),
- f4m_url, None)
- self.ie._sort_formats(formats)
- expect_value(self, formats, expected_formats, None)
-
- def test_parse_xspf(self):
- _TEST_CASES = [
- (
- 'foo_xspf',
- 'https://example.org/src/foo_xspf.xspf',
- [{
- 'id': 'foo_xspf',
- 'title': 'Pandemonium',
- 'description': 'Visit http://bigbrother404.bandcamp.com',
- 'duration': 202.416,
- 'formats': [{
- 'manifest_url': 'https://example.org/src/foo_xspf.xspf',
- 'url': 'https://example.org/src/cd1/track%201.mp3',
- }],
- }, {
- 'id': 'foo_xspf',
- 'title': 'Final Cartridge (Nichico Twelve Remix)',
- 'description': 'Visit http://bigbrother404.bandcamp.com',
- 'duration': 255.857,
- 'formats': [{
- 'manifest_url': 'https://example.org/src/foo_xspf.xspf',
- 'url': 'https://example.org/%E3%83%88%E3%83%A9%E3%83%83%E3%82%AF%E3%80%80%EF%BC%92.mp3',
- }],
- }, {
- 'id': 'foo_xspf',
- 'title': 'Rebuilding Nightingale',
- 'description': 'Visit http://bigbrother404.bandcamp.com',
- 'duration': 287.915,
- 'formats': [{
- 'manifest_url': 'https://example.org/src/foo_xspf.xspf',
- 'url': 'https://example.org/src/track3.mp3',
- }, {
- 'manifest_url': 'https://example.org/src/foo_xspf.xspf',
- 'url': 'https://example.com/track3.mp3',
- }]
- }]
- ),
- ]
-
- for xspf_file, xspf_url, expected_entries in _TEST_CASES:
- with open('./test/testdata/xspf/%s.xspf' % xspf_file,
- mode='r', encoding='utf-8') as f:
- entries = self.ie._parse_xspf(
- compat_etree_fromstring(f.read().encode('utf-8')),
- xspf_file, xspf_url=xspf_url, xspf_base_url=xspf_url)
- expect_value(self, entries, expected_entries, None)
- for i in range(len(entries)):
- expect_dict(self, entries[i], expected_entries[i])
-
- def test_response_with_expected_status_returns_content(self):
- # Checks for mitigations against the effects of
- # that affect Python 3.4.1+, which
- # manifest as `_download_webpage`, `_download_xml`, `_download_json`,
- # or the underlying `_download_webpage_handle` returning no content
- # when a response matches `expected_status`.
-
- httpd = compat_http_server.HTTPServer(
- ('127.0.0.1', 0), InfoExtractorTestRequestHandler)
- port = http_server_port(httpd)
- server_thread = threading.Thread(target=httpd.serve_forever)
- server_thread.daemon = True
- server_thread.start()
-
- (content, urlh) = self.ie._download_webpage_handle(
- 'http://127.0.0.1:%d/teapot' % port, None,
- expected_status=TEAPOT_RESPONSE_STATUS)
- self.assertEqual(content, TEAPOT_RESPONSE_BODY)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/test_YoutubeDL.py b/test/test_YoutubeDL.py
deleted file mode 100644
index d994682b2..000000000
--- a/test/test_YoutubeDL.py
+++ /dev/null
@@ -1,1191 +0,0 @@
-#!/usr/bin/env python
-# coding: utf-8
-
-from __future__ import unicode_literals
-
-# Allow direct execution
-import os
-import sys
-import unittest
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-import copy
-import json
-
-from test.helper import (
- FakeYDL,
- assertRegexpMatches,
- try_rm,
-)
-from youtube_dl import YoutubeDL
-from youtube_dl.compat import (
- compat_http_cookiejar_Cookie,
- compat_http_cookies_SimpleCookie,
- compat_kwargs,
- compat_open as open,
- compat_str,
- compat_urllib_error,
-)
-
-from youtube_dl.extractor import YoutubeIE
-from youtube_dl.extractor.common import InfoExtractor
-from youtube_dl.postprocessor.common import PostProcessor
-from youtube_dl.utils import (
- ExtractorError,
- match_filter_func,
- traverse_obj,
-)
-
-TEST_URL = 'http://localhost/sample.mp4'
-
-
-class YDL(FakeYDL):
- def __init__(self, *args, **kwargs):
- super(YDL, self).__init__(*args, **kwargs)
- self.downloaded_info_dicts = []
- self.msgs = []
-
- def process_info(self, info_dict):
- self.downloaded_info_dicts.append(info_dict.copy())
-
- def to_screen(self, msg):
- self.msgs.append(msg)
-
- def dl(self, *args, **kwargs):
- assert False, 'Downloader must not be invoked for test_YoutubeDL'
-
-
-def _make_result(formats, **kwargs):
- res = {
- 'formats': formats,
- 'id': 'testid',
- 'title': 'testttitle',
- 'extractor': 'testex',
- 'extractor_key': 'TestEx',
- 'webpage_url': 'http://example.com/watch?v=shenanigans',
- }
- res.update(**compat_kwargs(kwargs))
- return res
-
-
-class TestFormatSelection(unittest.TestCase):
- def test_prefer_free_formats(self):
- # Same resolution => download webm
- ydl = YDL()
- ydl.params['prefer_free_formats'] = True
- formats = [
- {'ext': 'webm', 'height': 460, 'url': TEST_URL},
- {'ext': 'mp4', 'height': 460, 'url': TEST_URL},
- ]
- info_dict = _make_result(formats)
- yie = YoutubeIE(ydl)
- yie._sort_formats(info_dict['formats'])
- ydl.process_ie_result(info_dict)
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['ext'], 'webm')
-
- # Different resolution => download best quality (mp4)
- ydl = YDL()
- ydl.params['prefer_free_formats'] = True
- formats = [
- {'ext': 'webm', 'height': 720, 'url': TEST_URL},
- {'ext': 'mp4', 'height': 1080, 'url': TEST_URL},
- ]
- info_dict['formats'] = formats
- yie = YoutubeIE(ydl)
- yie._sort_formats(info_dict['formats'])
- ydl.process_ie_result(info_dict)
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['ext'], 'mp4')
-
- # No prefer_free_formats => prefer mp4 and flv for greater compatibility
- ydl = YDL()
- ydl.params['prefer_free_formats'] = False
- formats = [
- {'ext': 'webm', 'height': 720, 'url': TEST_URL},
- {'ext': 'mp4', 'height': 720, 'url': TEST_URL},
- {'ext': 'flv', 'height': 720, 'url': TEST_URL},
- ]
- info_dict['formats'] = formats
- yie = YoutubeIE(ydl)
- yie._sort_formats(info_dict['formats'])
- ydl.process_ie_result(info_dict)
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['ext'], 'mp4')
-
- ydl = YDL()
- ydl.params['prefer_free_formats'] = False
- formats = [
- {'ext': 'flv', 'height': 720, 'url': TEST_URL},
- {'ext': 'webm', 'height': 720, 'url': TEST_URL},
- ]
- info_dict['formats'] = formats
- yie = YoutubeIE(ydl)
- yie._sort_formats(info_dict['formats'])
- ydl.process_ie_result(info_dict)
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['ext'], 'flv')
-
- def test_format_selection(self):
- formats = [
- {'format_id': '35', 'ext': 'mp4', 'preference': 1, 'url': TEST_URL},
- {'format_id': 'example-with-dashes', 'ext': 'webm', 'preference': 1, 'url': TEST_URL},
- {'format_id': '45', 'ext': 'webm', 'preference': 2, 'url': TEST_URL},
- {'format_id': '47', 'ext': 'webm', 'preference': 3, 'url': TEST_URL},
- {'format_id': '2', 'ext': 'flv', 'preference': 4, 'url': TEST_URL},
- ]
- info_dict = _make_result(formats)
-
- ydl = YDL({'format': '20/47'})
- ydl.process_ie_result(info_dict.copy())
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], '47')
-
- ydl = YDL({'format': '20/71/worst'})
- ydl.process_ie_result(info_dict.copy())
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], '35')
-
- ydl = YDL()
- ydl.process_ie_result(info_dict.copy())
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], '2')
-
- ydl = YDL({'format': 'webm/mp4'})
- ydl.process_ie_result(info_dict.copy())
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], '47')
-
- ydl = YDL({'format': '3gp/40/mp4'})
- ydl.process_ie_result(info_dict.copy())
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], '35')
-
- ydl = YDL({'format': 'example-with-dashes'})
- ydl.process_ie_result(info_dict.copy())
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'example-with-dashes')
-
- def test_format_selection_audio(self):
- formats = [
- {'format_id': 'audio-low', 'ext': 'webm', 'preference': 1, 'vcodec': 'none', 'url': TEST_URL},
- {'format_id': 'audio-mid', 'ext': 'webm', 'preference': 2, 'vcodec': 'none', 'url': TEST_URL},
- {'format_id': 'audio-high', 'ext': 'flv', 'preference': 3, 'vcodec': 'none', 'url': TEST_URL},
- {'format_id': 'vid', 'ext': 'mp4', 'preference': 4, 'url': TEST_URL},
- ]
- info_dict = _make_result(formats)
-
- ydl = YDL({'format': 'bestaudio'})
- ydl.process_ie_result(info_dict.copy())
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'audio-high')
-
- ydl = YDL({'format': 'worstaudio'})
- ydl.process_ie_result(info_dict.copy())
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'audio-low')
-
- formats = [
- {'format_id': 'vid-low', 'ext': 'mp4', 'preference': 1, 'url': TEST_URL},
- {'format_id': 'vid-high', 'ext': 'mp4', 'preference': 2, 'url': TEST_URL},
- ]
- info_dict = _make_result(formats)
-
- ydl = YDL({'format': 'bestaudio/worstaudio/best'})
- ydl.process_ie_result(info_dict.copy())
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'vid-high')
-
- def test_format_selection_audio_exts(self):
- formats = [
- {'format_id': 'mp3-64', 'ext': 'mp3', 'abr': 64, 'url': 'http://_', 'vcodec': 'none'},
- {'format_id': 'ogg-64', 'ext': 'ogg', 'abr': 64, 'url': 'http://_', 'vcodec': 'none'},
- {'format_id': 'aac-64', 'ext': 'aac', 'abr': 64, 'url': 'http://_', 'vcodec': 'none'},
- {'format_id': 'mp3-32', 'ext': 'mp3', 'abr': 32, 'url': 'http://_', 'vcodec': 'none'},
- {'format_id': 'aac-32', 'ext': 'aac', 'abr': 32, 'url': 'http://_', 'vcodec': 'none'},
- ]
-
- info_dict = _make_result(formats)
- ydl = YDL({'format': 'best'})
- ie = YoutubeIE(ydl)
- ie._sort_formats(info_dict['formats'])
- ydl.process_ie_result(copy.deepcopy(info_dict))
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'aac-64')
-
- ydl = YDL({'format': 'mp3'})
- ie = YoutubeIE(ydl)
- ie._sort_formats(info_dict['formats'])
- ydl.process_ie_result(copy.deepcopy(info_dict))
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'mp3-64')
-
- ydl = YDL({'prefer_free_formats': True})
- ie = YoutubeIE(ydl)
- ie._sort_formats(info_dict['formats'])
- ydl.process_ie_result(copy.deepcopy(info_dict))
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'ogg-64')
-
- def test_format_selection_video(self):
- formats = [
- {'format_id': 'dash-video-low', 'ext': 'mp4', 'preference': 1, 'acodec': 'none', 'url': TEST_URL},
- {'format_id': 'dash-video-high', 'ext': 'mp4', 'preference': 2, 'acodec': 'none', 'url': TEST_URL},
- {'format_id': 'vid', 'ext': 'mp4', 'preference': 3, 'url': TEST_URL},
- ]
- info_dict = _make_result(formats)
-
- ydl = YDL({'format': 'bestvideo'})
- ydl.process_ie_result(info_dict.copy())
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'dash-video-high')
-
- ydl = YDL({'format': 'worstvideo'})
- ydl.process_ie_result(info_dict.copy())
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'dash-video-low')
-
- ydl = YDL({'format': 'bestvideo[format_id^=dash][format_id$=low]'})
- ydl.process_ie_result(info_dict.copy())
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'dash-video-low')
-
- formats = [
- {'format_id': 'vid-vcodec-dot', 'ext': 'mp4', 'preference': 1, 'vcodec': 'avc1.123456', 'acodec': 'none', 'url': TEST_URL},
- ]
- info_dict = _make_result(formats)
-
- ydl = YDL({'format': 'bestvideo[vcodec=avc1.123456]'})
- ydl.process_ie_result(info_dict.copy())
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'vid-vcodec-dot')
-
- def test_format_selection_string_ops(self):
- formats = [
- {'format_id': 'abc-cba', 'ext': 'mp4', 'url': TEST_URL},
- {'format_id': 'zxc-cxz', 'ext': 'webm', 'url': TEST_URL},
- ]
- info_dict = _make_result(formats)
-
- # equals (=)
- ydl = YDL({'format': '[format_id=abc-cba]'})
- ydl.process_ie_result(info_dict.copy())
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'abc-cba')
-
- # does not equal (!=)
- ydl = YDL({'format': '[format_id!=abc-cba]'})
- ydl.process_ie_result(info_dict.copy())
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'zxc-cxz')
-
- ydl = YDL({'format': '[format_id!=abc-cba][format_id!=zxc-cxz]'})
- self.assertRaises(ExtractorError, ydl.process_ie_result, info_dict.copy())
-
- # starts with (^=)
- ydl = YDL({'format': '[format_id^=abc]'})
- ydl.process_ie_result(info_dict.copy())
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'abc-cba')
-
- # does not start with (!^=)
- ydl = YDL({'format': '[format_id!^=abc]'})
- ydl.process_ie_result(info_dict.copy())
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'zxc-cxz')
-
- ydl = YDL({'format': '[format_id!^=abc][format_id!^=zxc]'})
- self.assertRaises(ExtractorError, ydl.process_ie_result, info_dict.copy())
-
- # ends with ($=)
- ydl = YDL({'format': '[format_id$=cba]'})
- ydl.process_ie_result(info_dict.copy())
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'abc-cba')
-
- # does not end with (!$=)
- ydl = YDL({'format': '[format_id!$=cba]'})
- ydl.process_ie_result(info_dict.copy())
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'zxc-cxz')
-
- ydl = YDL({'format': '[format_id!$=cba][format_id!$=cxz]'})
- self.assertRaises(ExtractorError, ydl.process_ie_result, info_dict.copy())
-
- # contains (*=)
- ydl = YDL({'format': '[format_id*=bc-cb]'})
- ydl.process_ie_result(info_dict.copy())
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'abc-cba')
-
- # does not contain (!*=)
- ydl = YDL({'format': '[format_id!*=bc-cb]'})
- ydl.process_ie_result(info_dict.copy())
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'zxc-cxz')
-
- ydl = YDL({'format': '[format_id!*=abc][format_id!*=zxc]'})
- self.assertRaises(ExtractorError, ydl.process_ie_result, info_dict.copy())
-
- ydl = YDL({'format': '[format_id!*=-]'})
- self.assertRaises(ExtractorError, ydl.process_ie_result, info_dict.copy())
-
- def test_youtube_format_selection(self):
- order = [
- '38', '37', '46', '22', '45', '35', '44', '18', '34', '43', '6', '5', '17', '36', '13',
- # Apple HTTP Live Streaming
- '96', '95', '94', '93', '92', '132', '151',
- # 3D
- '85', '84', '102', '83', '101', '82', '100',
- # Dash video
- '137', '248', '136', '247', '135', '246',
- '245', '244', '134', '243', '133', '242', '160',
- # Dash audio
- '141', '172', '140', '171', '139',
- ]
-
- def format_info(f_id):
- info = YoutubeIE._formats[f_id].copy()
-
- # XXX: In real cases InfoExtractor._parse_mpd_formats() fills up 'acodec'
- # and 'vcodec', while in tests such information is incomplete since
- # commit a6c2c24479e5f4827ceb06f64d855329c0a6f593
- # test_YoutubeDL.test_youtube_format_selection is broken without
- # this fix
- if 'acodec' in info and 'vcodec' not in info:
- info['vcodec'] = 'none'
- elif 'vcodec' in info and 'acodec' not in info:
- info['acodec'] = 'none'
-
- info['format_id'] = f_id
- info['url'] = 'url:' + f_id
- return info
- formats_order = [format_info(f_id) for f_id in order]
-
- info_dict = _make_result(list(formats_order), extractor='youtube')
- ydl = YDL({'format': 'bestvideo+bestaudio'})
- yie = YoutubeIE(ydl)
- yie._sort_formats(info_dict['formats'])
- ydl.process_ie_result(info_dict)
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], '137+141')
- self.assertEqual(downloaded['ext'], 'mp4')
-
- info_dict = _make_result(list(formats_order), extractor='youtube')
- ydl = YDL({'format': 'bestvideo[height>=999999]+bestaudio/best'})
- yie = YoutubeIE(ydl)
- yie._sort_formats(info_dict['formats'])
- ydl.process_ie_result(info_dict)
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], '38')
-
- info_dict = _make_result(list(formats_order), extractor='youtube')
- ydl = YDL({'format': 'bestvideo/best,bestaudio'})
- yie = YoutubeIE(ydl)
- yie._sort_formats(info_dict['formats'])
- ydl.process_ie_result(info_dict)
- downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
- self.assertEqual(downloaded_ids, ['137', '141'])
-
- info_dict = _make_result(list(formats_order), extractor='youtube')
- ydl = YDL({'format': '(bestvideo[ext=mp4],bestvideo[ext=webm])+bestaudio'})
- yie = YoutubeIE(ydl)
- yie._sort_formats(info_dict['formats'])
- ydl.process_ie_result(info_dict)
- downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
- self.assertEqual(downloaded_ids, ['137+141', '248+141'])
-
- info_dict = _make_result(list(formats_order), extractor='youtube')
- ydl = YDL({'format': '(bestvideo[ext=mp4],bestvideo[ext=webm])[height<=720]+bestaudio'})
- yie = YoutubeIE(ydl)
- yie._sort_formats(info_dict['formats'])
- ydl.process_ie_result(info_dict)
- downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
- self.assertEqual(downloaded_ids, ['136+141', '247+141'])
-
- info_dict = _make_result(list(formats_order), extractor='youtube')
- ydl = YDL({'format': '(bestvideo[ext=none]/bestvideo[ext=webm])+bestaudio'})
- yie = YoutubeIE(ydl)
- yie._sort_formats(info_dict['formats'])
- ydl.process_ie_result(info_dict)
- downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
- self.assertEqual(downloaded_ids, ['248+141'])
-
- for f1, f2 in zip(formats_order, formats_order[1:]):
- info_dict = _make_result([f1, f2], extractor='youtube')
- ydl = YDL({'format': 'best/bestvideo'})
- yie = YoutubeIE(ydl)
- yie._sort_formats(info_dict['formats'])
- ydl.process_ie_result(info_dict)
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], f1['format_id'])
-
- info_dict = _make_result([f2, f1], extractor='youtube')
- ydl = YDL({'format': 'best/bestvideo'})
- yie = YoutubeIE(ydl)
- yie._sort_formats(info_dict['formats'])
- ydl.process_ie_result(info_dict)
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], f1['format_id'])
-
- def test_audio_only_extractor_format_selection(self):
- # For extractors with incomplete formats (all formats are audio-only or
- # video-only) best and worst should fallback to corresponding best/worst
- # video-only or audio-only formats (as per
- # https://github.com/ytdl-org/youtube-dl/pull/5556)
- formats = [
- {'format_id': 'low', 'ext': 'mp3', 'preference': 1, 'vcodec': 'none', 'url': TEST_URL},
- {'format_id': 'high', 'ext': 'mp3', 'preference': 2, 'vcodec': 'none', 'url': TEST_URL},
- ]
- info_dict = _make_result(formats)
-
- ydl = YDL({'format': 'best'})
- ydl.process_ie_result(info_dict.copy())
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'high')
-
- ydl = YDL({'format': 'worst'})
- ydl.process_ie_result(info_dict.copy())
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'low')
-
- def test_format_not_available(self):
- formats = [
- {'format_id': 'regular', 'ext': 'mp4', 'height': 360, 'url': TEST_URL},
- {'format_id': 'video', 'ext': 'mp4', 'height': 720, 'acodec': 'none', 'url': TEST_URL},
- ]
- info_dict = _make_result(formats)
-
- # This must fail since complete video-audio format does not match filter
- # and extractor does not provide incomplete only formats (i.e. only
- # video-only or audio-only).
- ydl = YDL({'format': 'best[height>360]'})
- self.assertRaises(ExtractorError, ydl.process_ie_result, info_dict.copy())
-
- def test_format_selection_issue_10083(self):
- # See https://github.com/ytdl-org/youtube-dl/issues/10083
- formats = [
- {'format_id': 'regular', 'height': 360, 'url': TEST_URL},
- {'format_id': 'video', 'height': 720, 'acodec': 'none', 'url': TEST_URL},
- {'format_id': 'audio', 'vcodec': 'none', 'url': TEST_URL},
- ]
- info_dict = _make_result(formats)
-
- ydl = YDL({'format': 'best[height>360]/bestvideo[height>360]+bestaudio'})
- ydl.process_ie_result(info_dict.copy())
- self.assertEqual(ydl.downloaded_info_dicts[0]['format_id'], 'video+audio')
-
- def test_invalid_format_specs(self):
- def assert_syntax_error(format_spec):
- ydl = YDL({'format': format_spec})
- info_dict = _make_result([{'format_id': 'foo', 'url': TEST_URL}])
- self.assertRaises(SyntaxError, ydl.process_ie_result, info_dict)
-
- assert_syntax_error('bestvideo,,best')
- assert_syntax_error('+bestaudio')
- assert_syntax_error('bestvideo+')
- assert_syntax_error('/')
- assert_syntax_error('bestvideo+bestvideo+bestaudio')
-
- def test_format_filtering(self):
- formats = [
- {'format_id': 'A', 'filesize': 500, 'width': 1000},
- {'format_id': 'B', 'filesize': 1000, 'width': 500},
- {'format_id': 'C', 'filesize': 1000, 'width': 400},
- {'format_id': 'D', 'filesize': 2000, 'width': 600},
- {'format_id': 'E', 'filesize': 3000},
- {'format_id': 'F'},
- {'format_id': 'G', 'filesize': 1000000},
- ]
- for f in formats:
- f['url'] = 'http://_/'
- f['ext'] = 'unknown'
- info_dict = _make_result(formats)
-
- ydl = YDL({'format': 'best[filesize<3000]'})
- ydl.process_ie_result(info_dict)
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'D')
-
- ydl = YDL({'format': 'best[filesize<=3000]'})
- ydl.process_ie_result(info_dict)
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'E')
-
- ydl = YDL({'format': 'best[filesize <= ? 3000]'})
- ydl.process_ie_result(info_dict)
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'F')
-
- ydl = YDL({'format': 'best [filesize = 1000] [width>450]'})
- ydl.process_ie_result(info_dict)
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'B')
-
- ydl = YDL({'format': 'best [filesize = 1000] [width!=450]'})
- ydl.process_ie_result(info_dict)
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'C')
-
- ydl = YDL({'format': '[filesize>?1]'})
- ydl.process_ie_result(info_dict)
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'G')
-
- ydl = YDL({'format': '[filesize<1M]'})
- ydl.process_ie_result(info_dict)
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'E')
-
- ydl = YDL({'format': '[filesize<1MiB]'})
- ydl.process_ie_result(info_dict)
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['format_id'], 'G')
-
- ydl = YDL({'format': 'all[width>=400][width<=600]'})
- ydl.process_ie_result(info_dict)
- downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
- self.assertEqual(downloaded_ids, ['B', 'C', 'D'])
-
- ydl = YDL({'format': 'best[height<40]'})
- try:
- ydl.process_ie_result(info_dict)
- except ExtractorError:
- pass
- self.assertEqual(ydl.downloaded_info_dicts, [])
-
- def test_default_format_spec(self):
- ydl = YDL({'simulate': True})
- self.assertEqual(ydl._default_format_spec({}), 'bestvideo+bestaudio/best')
-
- ydl = YDL({})
- self.assertEqual(ydl._default_format_spec({'is_live': True}), 'best/bestvideo+bestaudio')
-
- ydl = YDL({'simulate': True})
- self.assertEqual(ydl._default_format_spec({'is_live': True}), 'bestvideo+bestaudio/best')
-
- ydl = YDL({'outtmpl': '-'})
- self.assertEqual(ydl._default_format_spec({}), 'best/bestvideo+bestaudio')
-
- ydl = YDL({})
- self.assertEqual(ydl._default_format_spec({}, download=False), 'bestvideo+bestaudio/best')
- self.assertEqual(ydl._default_format_spec({'is_live': True}), 'best/bestvideo+bestaudio')
-
-
-class TestYoutubeDL(unittest.TestCase):
- def test_subtitles(self):
- def s_formats(lang, autocaption=False):
- return [{
- 'ext': ext,
- 'url': 'http://localhost/video.%s.%s' % (lang, ext),
- '_auto': autocaption,
- } for ext in ['vtt', 'srt', 'ass']]
- subtitles = dict((l, s_formats(l)) for l in ['en', 'fr', 'es'])
- auto_captions = dict((l, s_formats(l, True)) for l in ['it', 'pt', 'es'])
- info_dict = {
- 'id': 'test',
- 'title': 'Test',
- 'url': 'http://localhost/video.mp4',
- 'subtitles': subtitles,
- 'automatic_captions': auto_captions,
- 'extractor': 'TEST',
- }
-
- def get_info(params={}):
- params.setdefault('simulate', True)
- ydl = YDL(params)
- ydl.report_warning = lambda *args, **kargs: None
- return ydl.process_video_result(info_dict, download=False)
-
- result = get_info()
- self.assertFalse(result.get('requested_subtitles'))
- self.assertEqual(result['subtitles'], subtitles)
- self.assertEqual(result['automatic_captions'], auto_captions)
-
- result = get_info({'writesubtitles': True})
- subs = result['requested_subtitles']
- self.assertTrue(subs)
- self.assertEqual(set(subs.keys()), set(['en']))
- self.assertTrue(subs['en'].get('data') is None)
- self.assertEqual(subs['en']['ext'], 'ass')
-
- result = get_info({'writesubtitles': True, 'subtitlesformat': 'foo/srt'})
- subs = result['requested_subtitles']
- self.assertEqual(subs['en']['ext'], 'srt')
-
- result = get_info({'writesubtitles': True, 'subtitleslangs': ['es', 'fr', 'it']})
- subs = result['requested_subtitles']
- self.assertTrue(subs)
- self.assertEqual(set(subs.keys()), set(['es', 'fr']))
-
- result = get_info({'writesubtitles': True, 'writeautomaticsub': True, 'subtitleslangs': ['es', 'pt']})
- subs = result['requested_subtitles']
- self.assertTrue(subs)
- self.assertEqual(set(subs.keys()), set(['es', 'pt']))
- self.assertFalse(subs['es']['_auto'])
- self.assertTrue(subs['pt']['_auto'])
-
- result = get_info({'writeautomaticsub': True, 'subtitleslangs': ['es', 'pt']})
- subs = result['requested_subtitles']
- self.assertTrue(subs)
- self.assertEqual(set(subs.keys()), set(['es', 'pt']))
- self.assertTrue(subs['es']['_auto'])
- self.assertTrue(subs['pt']['_auto'])
-
- def test_add_extra_info(self):
- test_dict = {
- 'extractor': 'Foo',
- }
- extra_info = {
- 'extractor': 'Bar',
- 'playlist': 'funny videos',
- }
- YDL.add_extra_info(test_dict, extra_info)
- self.assertEqual(test_dict['extractor'], 'Foo')
- self.assertEqual(test_dict['playlist'], 'funny videos')
-
- def test_prepare_filename(self):
- info = {
- 'id': '1234',
- 'ext': 'mp4',
- 'width': None,
- 'height': 1080,
- 'title1': '$PATH',
- 'title2': '%PATH%',
- }
-
- def fname(templ, na_placeholder='NA'):
- params = {'outtmpl': templ}
- if na_placeholder != 'NA':
- params['outtmpl_na_placeholder'] = na_placeholder
- ydl = YoutubeDL(params)
- return ydl.prepare_filename(info)
- self.assertEqual(fname('%(id)s.%(ext)s'), '1234.mp4')
- self.assertEqual(fname('%(id)s-%(width)s.%(ext)s'), '1234-NA.mp4')
- NA_TEST_OUTTMPL = '%(uploader_date)s-%(width)d-%(id)s.%(ext)s'
- # Replace missing fields with 'NA' by default
- self.assertEqual(fname(NA_TEST_OUTTMPL), 'NA-NA-1234.mp4')
- # Or by provided placeholder
- self.assertEqual(fname(NA_TEST_OUTTMPL, na_placeholder='none'), 'none-none-1234.mp4')
- self.assertEqual(fname(NA_TEST_OUTTMPL, na_placeholder=''), '--1234.mp4')
- self.assertEqual(fname('%(height)d.%(ext)s'), '1080.mp4')
- self.assertEqual(fname('%(height)6d.%(ext)s'), ' 1080.mp4')
- self.assertEqual(fname('%(height)-6d.%(ext)s'), '1080 .mp4')
- self.assertEqual(fname('%(height)06d.%(ext)s'), '001080.mp4')
- self.assertEqual(fname('%(height) 06d.%(ext)s'), ' 01080.mp4')
- self.assertEqual(fname('%(height) 06d.%(ext)s'), ' 01080.mp4')
- self.assertEqual(fname('%(height)0 6d.%(ext)s'), ' 01080.mp4')
- self.assertEqual(fname('%(height)0 6d.%(ext)s'), ' 01080.mp4')
- self.assertEqual(fname('%(height) 0 6d.%(ext)s'), ' 01080.mp4')
- self.assertEqual(fname('%%'), '%')
- self.assertEqual(fname('%%%%'), '%%')
- self.assertEqual(fname('%%(height)06d.%(ext)s'), '%(height)06d.mp4')
- self.assertEqual(fname('%(width)06d.%(ext)s'), 'NA.mp4')
- self.assertEqual(fname('%(width)06d.%%(ext)s'), 'NA.%(ext)s')
- self.assertEqual(fname('%%(width)06d.%(ext)s'), '%(width)06d.mp4')
- self.assertEqual(fname('Hello %(title1)s'), 'Hello $PATH')
- self.assertEqual(fname('Hello %(title2)s'), 'Hello %PATH%')
-
- def test_format_note(self):
- ydl = YoutubeDL()
- self.assertEqual(ydl._format_note({}), '')
- assertRegexpMatches(self, ydl._format_note({
- 'vbr': 10,
- }), r'^\s*10k$')
- assertRegexpMatches(self, ydl._format_note({
- 'fps': 30,
- }), r'^30fps$')
-
- def test_postprocessors(self):
- filename = 'post-processor-testfile.mp4'
- audiofile = filename + '.mp3'
-
- class SimplePP(PostProcessor):
- def run(self, info):
- with open(audiofile, 'w') as f:
- f.write('EXAMPLE')
- return [info['filepath']], info
-
- def run_pp(params, PP):
- with open(filename, 'w') as f:
- f.write('EXAMPLE')
- ydl = YoutubeDL(params)
- ydl.add_post_processor(PP())
- ydl.post_process(filename, {'filepath': filename})
-
- run_pp({'keepvideo': True}, SimplePP)
- self.assertTrue(os.path.exists(filename), '%s doesn\'t exist' % filename)
- self.assertTrue(os.path.exists(audiofile), '%s doesn\'t exist' % audiofile)
- os.unlink(filename)
- os.unlink(audiofile)
-
- run_pp({'keepvideo': False}, SimplePP)
- self.assertFalse(os.path.exists(filename), '%s exists' % filename)
- self.assertTrue(os.path.exists(audiofile), '%s doesn\'t exist' % audiofile)
- os.unlink(audiofile)
-
- class ModifierPP(PostProcessor):
- def run(self, info):
- with open(info['filepath'], 'w') as f:
- f.write('MODIFIED')
- return [], info
-
- run_pp({'keepvideo': False}, ModifierPP)
- self.assertTrue(os.path.exists(filename), '%s doesn\'t exist' % filename)
- os.unlink(filename)
-
- def test_match_filter(self):
- class FilterYDL(YDL):
- def __init__(self, *args, **kwargs):
- super(FilterYDL, self).__init__(*args, **kwargs)
- self.params['simulate'] = True
-
- def process_info(self, info_dict):
- super(YDL, self).process_info(info_dict)
-
- def _match_entry(self, info_dict, incomplete):
- res = super(FilterYDL, self)._match_entry(info_dict, incomplete)
- if res is None:
- self.downloaded_info_dicts.append(info_dict)
- return res
-
- first = {
- 'id': '1',
- 'url': TEST_URL,
- 'title': 'one',
- 'extractor': 'TEST',
- 'duration': 30,
- 'filesize': 10 * 1024,
- 'playlist_id': '42',
- 'uploader': "變態妍字幕版 太妍 тест",
- 'creator': "тест ' 123 ' тест--",
- }
- second = {
- 'id': '2',
- 'url': TEST_URL,
- 'title': 'two',
- 'extractor': 'TEST',
- 'duration': 10,
- 'description': 'foo',
- 'filesize': 5 * 1024,
- 'playlist_id': '43',
- 'uploader': "тест 123",
- }
- videos = [first, second]
-
- def get_videos(filter_=None):
- ydl = FilterYDL({'match_filter': filter_})
- for v in videos:
- ydl.process_ie_result(v, download=True)
- return [v['id'] for v in ydl.downloaded_info_dicts]
-
- res = get_videos()
- self.assertEqual(res, ['1', '2'])
-
- def f(v):
- if v['id'] == '1':
- return None
- else:
- return 'Video id is not 1'
- res = get_videos(f)
- self.assertEqual(res, ['1'])
-
- f = match_filter_func('duration < 30')
- res = get_videos(f)
- self.assertEqual(res, ['2'])
-
- f = match_filter_func('description = foo')
- res = get_videos(f)
- self.assertEqual(res, ['2'])
-
- f = match_filter_func('description =? foo')
- res = get_videos(f)
- self.assertEqual(res, ['1', '2'])
-
- f = match_filter_func('filesize > 5KiB')
- res = get_videos(f)
- self.assertEqual(res, ['1'])
-
- f = match_filter_func('playlist_id = 42')
- res = get_videos(f)
- self.assertEqual(res, ['1'])
-
- f = match_filter_func('uploader = "變態妍字幕版 太妍 тест"')
- res = get_videos(f)
- self.assertEqual(res, ['1'])
-
- f = match_filter_func('uploader != "變態妍字幕版 太妍 тест"')
- res = get_videos(f)
- self.assertEqual(res, ['2'])
-
- f = match_filter_func('creator = "тест \' 123 \' тест--"')
- res = get_videos(f)
- self.assertEqual(res, ['1'])
-
- f = match_filter_func("creator = 'тест \\' 123 \\' тест--'")
- res = get_videos(f)
- self.assertEqual(res, ['1'])
-
- f = match_filter_func(r"creator = 'тест \' 123 \' тест--' & duration > 30")
- res = get_videos(f)
- self.assertEqual(res, [])
-
- def test_playlist_items_selection(self):
- entries = [{
- 'id': compat_str(i),
- 'title': compat_str(i),
- 'url': TEST_URL,
- } for i in range(1, 5)]
- playlist = {
- '_type': 'playlist',
- 'id': 'test',
- 'entries': entries,
- 'extractor': 'test:playlist',
- 'extractor_key': 'test:playlist',
- 'webpage_url': 'http://example.com',
- }
-
- def get_downloaded_info_dicts(params):
- ydl = YDL(params)
- # make a deep copy because the dictionary and nested entries
- # can be modified
- ydl.process_ie_result(copy.deepcopy(playlist))
- return ydl.downloaded_info_dicts
-
- def get_ids(params):
- return [int(v['id']) for v in get_downloaded_info_dicts(params)]
-
- result = get_ids({})
- self.assertEqual(result, [1, 2, 3, 4])
-
- result = get_ids({'playlistend': 10})
- self.assertEqual(result, [1, 2, 3, 4])
-
- result = get_ids({'playlistend': 2})
- self.assertEqual(result, [1, 2])
-
- result = get_ids({'playliststart': 10})
- self.assertEqual(result, [])
-
- result = get_ids({'playliststart': 2})
- self.assertEqual(result, [2, 3, 4])
-
- result = get_ids({'playlist_items': '2-4'})
- self.assertEqual(result, [2, 3, 4])
-
- result = get_ids({'playlist_items': '2,4'})
- self.assertEqual(result, [2, 4])
-
- result = get_ids({'playlist_items': '10'})
- self.assertEqual(result, [])
-
- result = get_ids({'playlist_items': '3-10'})
- self.assertEqual(result, [3, 4])
-
- result = get_ids({'playlist_items': '2-4,3-4,3'})
- self.assertEqual(result, [2, 3, 4])
-
- # Tests for https://github.com/ytdl-org/youtube-dl/issues/10591
- # @{
- result = get_downloaded_info_dicts({'playlist_items': '2-4,3-4,3'})
- self.assertEqual(result[0]['playlist_index'], 2)
- self.assertEqual(result[1]['playlist_index'], 3)
-
- result = get_downloaded_info_dicts({'playlist_items': '2-4,3-4,3'})
- self.assertEqual(result[0]['playlist_index'], 2)
- self.assertEqual(result[1]['playlist_index'], 3)
- self.assertEqual(result[2]['playlist_index'], 4)
-
- result = get_downloaded_info_dicts({'playlist_items': '4,2'})
- self.assertEqual(result[0]['playlist_index'], 4)
- self.assertEqual(result[1]['playlist_index'], 2)
- # @}
-
- def test_urlopen_no_file_protocol(self):
- # see https://github.com/ytdl-org/youtube-dl/issues/8227
- ydl = YDL()
- self.assertRaises(compat_urllib_error.URLError, ydl.urlopen, 'file:///etc/passwd')
-
- def test_do_not_override_ie_key_in_url_transparent(self):
- ydl = YDL()
-
- class Foo1IE(InfoExtractor):
- _VALID_URL = r'foo1:'
-
- def _real_extract(self, url):
- return {
- '_type': 'url_transparent',
- 'url': 'foo2:',
- 'ie_key': 'Foo2',
- 'title': 'foo1 title',
- 'id': 'foo1_id',
- }
-
- class Foo2IE(InfoExtractor):
- _VALID_URL = r'foo2:'
-
- def _real_extract(self, url):
- return {
- '_type': 'url',
- 'url': 'foo3:',
- 'ie_key': 'Foo3',
- }
-
- class Foo3IE(InfoExtractor):
- _VALID_URL = r'foo3:'
-
- def _real_extract(self, url):
- return _make_result([{'url': TEST_URL}], title='foo3 title')
-
- ydl.add_info_extractor(Foo1IE(ydl))
- ydl.add_info_extractor(Foo2IE(ydl))
- ydl.add_info_extractor(Foo3IE(ydl))
- ydl.extract_info('foo1:')
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(downloaded['url'], TEST_URL)
- self.assertEqual(downloaded['title'], 'foo1 title')
- self.assertEqual(downloaded['id'], 'testid')
- self.assertEqual(downloaded['extractor'], 'testex')
- self.assertEqual(downloaded['extractor_key'], 'TestEx')
-
- # Test case for https://github.com/ytdl-org/youtube-dl/issues/27064
- def test_ignoreerrors_for_playlist_with_url_transparent_iterable_entries(self):
-
- ydl = YDL({
- 'format': 'extra',
- 'ignoreerrors': True,
- })
- ydl.trouble = lambda *_, **__: None
-
- class VideoIE(InfoExtractor):
- _VALID_URL = r'video:(?P\d+)'
-
- def _real_extract(self, url):
- video_id = self._match_id(url)
- formats = [{
- 'format_id': 'default',
- 'url': 'url:',
- }]
- if video_id == '0':
- raise ExtractorError('foo')
- if video_id == '2':
- formats.append({
- 'format_id': 'extra',
- 'url': TEST_URL,
- })
- return {
- 'id': video_id,
- 'title': 'Video %s' % video_id,
- 'formats': formats,
- }
-
- class PlaylistIE(InfoExtractor):
- _VALID_URL = r'playlist:'
-
- def _entries(self):
- for n in range(3):
- video_id = compat_str(n)
- yield {
- '_type': 'url_transparent',
- 'ie_key': VideoIE.ie_key(),
- 'id': video_id,
- 'url': 'video:%s' % video_id,
- 'title': 'Video Transparent %s' % video_id,
- }
-
- def _real_extract(self, url):
- return self.playlist_result(self._entries())
-
- ydl.add_info_extractor(VideoIE(ydl))
- ydl.add_info_extractor(PlaylistIE(ydl))
- info = ydl.extract_info('playlist:')
- entries = info['entries']
- self.assertEqual(len(entries), 3)
- self.assertTrue(entries[0] is None)
- self.assertTrue(entries[1] is None)
- self.assertEqual(len(ydl.downloaded_info_dicts), 1)
- downloaded = ydl.downloaded_info_dicts[0]
- self.assertEqual(entries[2], downloaded)
- self.assertEqual(downloaded['url'], TEST_URL)
- self.assertEqual(downloaded['title'], 'Video Transparent 2')
- self.assertEqual(downloaded['id'], '2')
- self.assertEqual(downloaded['extractor'], 'Video')
- self.assertEqual(downloaded['extractor_key'], 'Video')
-
- def test_default_times(self):
- """Test addition of missing upload/release/_date from /release_/timestamp"""
- info = {
- 'id': '1234',
- 'url': TEST_URL,
- 'title': 'Title',
- 'ext': 'mp4',
- 'timestamp': 1631352900,
- 'release_timestamp': 1632995931,
- }
-
- params = {'simulate': True, }
- ydl = FakeYDL(params)
- out_info = ydl.process_ie_result(info)
- self.assertTrue(isinstance(out_info['upload_date'], compat_str))
- self.assertEqual(out_info['upload_date'], '20210911')
- self.assertTrue(isinstance(out_info['release_date'], compat_str))
- self.assertEqual(out_info['release_date'], '20210930')
-
-
-class TestYoutubeDLCookies(unittest.TestCase):
-
- @staticmethod
- def encode_cookie(cookie):
- if not isinstance(cookie, dict):
- cookie = vars(cookie)
- for name, value in cookie.items():
- yield name, compat_str(value)
-
- @classmethod
- def comparable_cookies(cls, cookies):
- # Work around cookiejar cookies not being unicode strings
- return sorted(map(tuple, map(sorted, map(cls.encode_cookie, cookies))))
-
- def assertSameCookies(self, c1, c2, msg=None):
- return self.assertEqual(
- *map(self.comparable_cookies, (c1, c2)),
- msg=msg)
-
- def assertSameCookieStrings(self, c1, c2, msg=None):
- return self.assertSameCookies(
- *map(lambda c: compat_http_cookies_SimpleCookie(c).values(), (c1, c2)),
- msg=msg)
-
- def test_header_cookies(self):
-
- ydl = FakeYDL()
- ydl.report_warning = lambda *_, **__: None
-
- def cookie(name, value, version=None, domain='', path='', secure=False, expires=None):
- return compat_http_cookiejar_Cookie(
- version or 0, name, value, None, False,
- domain, bool(domain), bool(domain), path, bool(path),
- secure, expires, False, None, None, rest={})
-
- test_url, test_domain = (t % ('yt.dl',) for t in ('https://%s/test', '.%s'))
-
- def test(encoded_cookies, cookies, headers=False, round_trip=None, error_re=None):
- def _test():
- ydl.cookiejar.clear()
- ydl._load_cookies(encoded_cookies, autoscope=headers)
- if headers:
- ydl._apply_header_cookies(test_url)
- data = {'url': test_url}
- ydl._calc_headers(data)
- self.assertSameCookies(
- cookies, ydl.cookiejar,
- 'Extracted cookiejar.Cookie is not the same')
- if not headers:
- self.assertSameCookieStrings(
- data.get('cookies'), round_trip or encoded_cookies,
- msg='Cookie is not the same as round trip')
- ydl.__dict__['_YoutubeDL__header_cookies'] = []
-
- try:
- _test()
- except AssertionError:
- raise
- except Exception as e:
- if not error_re:
- raise
- assertRegexpMatches(self, e.args[0], error_re.join(('.*',) * 2))
-
- test('test=value; Domain=' + test_domain, [cookie('test', 'value', domain=test_domain)])
- test('test=value', [cookie('test', 'value')], error_re='Unscoped cookies are not allowed')
- test('cookie1=value1; Domain={0}; Path=/test; cookie2=value2; Domain={0}; Path=/'.format(test_domain), [
- cookie('cookie1', 'value1', domain=test_domain, path='/test'),
- cookie('cookie2', 'value2', domain=test_domain, path='/')])
- cookie_kw = compat_kwargs(
- {'domain': test_domain, 'path': '/test', 'secure': True, 'expires': '9999999999', })
- test('test=value; Domain={domain}; Path={path}; Secure; Expires={expires}'.format(**cookie_kw), [
- cookie('test', 'value', **cookie_kw)])
- test('test="value; "; path=/test; domain=' + test_domain, [
- cookie('test', 'value; ', domain=test_domain, path='/test')],
- round_trip='test="value\\073 "; Domain={0}; Path=/test'.format(test_domain))
- test('name=; Domain=' + test_domain, [cookie('name', '', domain=test_domain)],
- round_trip='name=""; Domain=' + test_domain)
- test('test=value', [cookie('test', 'value', domain=test_domain)], headers=True)
- test('cookie1=value; Domain={0}; cookie2=value'.format(test_domain), [],
- headers=True, error_re='Invalid syntax')
- ydl.report_warning = ydl.report_error
- test('test=value', [], headers=True, error_re='Passing cookies as a header is a potential security risk')
-
- def test_infojson_cookies(self):
- TEST_FILE = 'test_infojson_cookies.info.json'
- TEST_URL = 'https://example.com/example.mp4'
- COOKIES = 'a=b; Domain=.example.com; c=d; Domain=.example.com'
- COOKIE_HEADER = {'Cookie': 'a=b; c=d'}
-
- ydl = FakeYDL()
- ydl.process_info = lambda x: ydl._write_info_json('test', x, TEST_FILE)
-
- def make_info(info_header_cookies=False, fmts_header_cookies=False, cookies_field=False):
- fmt = {'url': TEST_URL}
- if fmts_header_cookies:
- fmt['http_headers'] = COOKIE_HEADER
- if cookies_field:
- fmt['cookies'] = COOKIES
- return _make_result([fmt], http_headers=COOKIE_HEADER if info_header_cookies else None)
-
- def test(initial_info, note):
-
- def failure_msg(why):
- return ' when '.join((why, note))
-
- result = {}
- result['processed'] = ydl.process_ie_result(initial_info)
- self.assertTrue(ydl.cookiejar.get_cookies_for_url(TEST_URL),
- msg=failure_msg('No cookies set in cookiejar after initial process'))
- ydl.cookiejar.clear()
- with open(TEST_FILE) as infojson:
- result['loaded'] = ydl.sanitize_info(json.load(infojson), True)
- result['final'] = ydl.process_ie_result(result['loaded'].copy(), download=False)
- self.assertTrue(ydl.cookiejar.get_cookies_for_url(TEST_URL),
- msg=failure_msg('No cookies set in cookiejar after final process'))
- ydl.cookiejar.clear()
- for key in ('processed', 'loaded', 'final'):
- info = result[key]
- self.assertIsNone(
- traverse_obj(info, ((None, ('formats', 0)), 'http_headers', 'Cookie'), casesense=False, get_all=False),
- msg=failure_msg('Cookie header not removed in {0} result'.format(key)))
- self.assertSameCookieStrings(
- traverse_obj(info, ((None, ('formats', 0)), 'cookies'), get_all=False), COOKIES,
- msg=failure_msg('No cookies field found in {0} result'.format(key)))
-
- test({'url': TEST_URL, 'http_headers': COOKIE_HEADER, 'id': '1', 'title': 'x'}, 'no formats field')
- test(make_info(info_header_cookies=True), 'info_dict header cokies')
- test(make_info(fmts_header_cookies=True), 'format header cookies')
- test(make_info(info_header_cookies=True, fmts_header_cookies=True), 'info_dict and format header cookies')
- test(make_info(info_header_cookies=True, fmts_header_cookies=True, cookies_field=True), 'all cookies fields')
- test(make_info(cookies_field=True), 'cookies format field')
- test({'url': TEST_URL, 'cookies': COOKIES, 'id': '1', 'title': 'x'}, 'info_dict cookies field only')
-
- try_rm(TEST_FILE)
-
- def test_add_headers_cookie(self):
- def check_for_cookie_header(result):
- return traverse_obj(result, ((None, ('formats', 0)), 'http_headers', 'Cookie'), casesense=False, get_all=False)
-
- ydl = FakeYDL({'http_headers': {'Cookie': 'a=b'}})
- ydl._apply_header_cookies(_make_result([])['webpage_url']) # Scope to input webpage URL: .example.com
-
- fmt = {'url': 'https://example.com/video.mp4'}
- result = ydl.process_ie_result(_make_result([fmt]), download=False)
- self.assertIsNone(check_for_cookie_header(result), msg='http_headers cookies in result info_dict')
- self.assertEqual(result.get('cookies'), 'a=b; Domain=.example.com', msg='No cookies were set in cookies field')
- self.assertIn('a=b', ydl.cookiejar.get_cookie_header(fmt['url']), msg='No cookies were set in cookiejar')
-
- fmt = {'url': 'https://wrong.com/video.mp4'}
- result = ydl.process_ie_result(_make_result([fmt]), download=False)
- self.assertIsNone(check_for_cookie_header(result), msg='http_headers cookies for wrong domain')
- self.assertFalse(result.get('cookies'), msg='Cookies set in cookies field for wrong domain')
- self.assertFalse(ydl.cookiejar.get_cookie_header(fmt['url']), msg='Cookies set in cookiejar for wrong domain')
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/test_YoutubeDLCookieJar.py b/test/test_YoutubeDLCookieJar.py
deleted file mode 100644
index 4f9dd71ae..000000000
--- a/test/test_YoutubeDLCookieJar.py
+++ /dev/null
@@ -1,65 +0,0 @@
-#!/usr/bin/env python
-# coding: utf-8
-
-from __future__ import unicode_literals
-
-import os
-import re
-import sys
-import tempfile
-import unittest
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-from youtube_dl.utils import YoutubeDLCookieJar
-
-
-class TestYoutubeDLCookieJar(unittest.TestCase):
- def test_keep_session_cookies(self):
- cookiejar = YoutubeDLCookieJar('./test/testdata/cookies/session_cookies.txt')
- cookiejar.load(ignore_discard=True, ignore_expires=True)
- tf = tempfile.NamedTemporaryFile(delete=False)
- try:
- cookiejar.save(filename=tf.name, ignore_discard=True, ignore_expires=True)
- temp = tf.read().decode('utf-8')
- self.assertTrue(re.search(
- r'www\.foobar\.foobar\s+FALSE\s+/\s+TRUE\s+0\s+YoutubeDLExpiresEmpty\s+YoutubeDLExpiresEmptyValue', temp))
- self.assertTrue(re.search(
- r'www\.foobar\.foobar\s+FALSE\s+/\s+TRUE\s+0\s+YoutubeDLExpires0\s+YoutubeDLExpires0Value', temp))
- finally:
- tf.close()
- os.remove(tf.name)
-
- def test_strip_httponly_prefix(self):
- cookiejar = YoutubeDLCookieJar('./test/testdata/cookies/httponly_cookies.txt')
- cookiejar.load(ignore_discard=True, ignore_expires=True)
-
- def assert_cookie_has_value(key):
- self.assertEqual(cookiejar._cookies['www.foobar.foobar']['/'][key].value, key + '_VALUE')
-
- assert_cookie_has_value('HTTPONLY_COOKIE')
- assert_cookie_has_value('JS_ACCESSIBLE_COOKIE')
-
- def test_malformed_cookies(self):
- cookiejar = YoutubeDLCookieJar('./test/testdata/cookies/malformed_cookies.txt')
- cookiejar.load(ignore_discard=True, ignore_expires=True)
- # Cookies should be empty since all malformed cookie file entries
- # will be ignored
- self.assertFalse(cookiejar._cookies)
-
- def test_get_cookie_header(self):
- cookiejar = YoutubeDLCookieJar('./test/testdata/cookies/httponly_cookies.txt')
- cookiejar.load(ignore_discard=True, ignore_expires=True)
- header = cookiejar.get_cookie_header('https://www.foobar.foobar')
- self.assertIn('HTTPONLY_COOKIE', header)
-
- def test_get_cookies_for_url(self):
- cookiejar = YoutubeDLCookieJar('./test/testdata/cookies/session_cookies.txt')
- cookiejar.load(ignore_discard=True, ignore_expires=True)
- cookies = cookiejar.get_cookies_for_url('https://www.foobar.foobar/')
- self.assertEqual(len(cookies), 2)
- cookies = cookiejar.get_cookies_for_url('https://foobar.foobar/')
- self.assertFalse(cookies)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/test_aes.py b/test/test_aes.py
deleted file mode 100644
index 0f181466b..000000000
--- a/test/test_aes.py
+++ /dev/null
@@ -1,70 +0,0 @@
-#!/usr/bin/env python
-
-from __future__ import unicode_literals
-
-# Allow direct execution
-import os
-import sys
-import unittest
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-from youtube_dl.aes import aes_decrypt, aes_encrypt, aes_cbc_decrypt, aes_cbc_encrypt, aes_decrypt_text, aes_ecb_encrypt
-from youtube_dl.utils import bytes_to_intlist, intlist_to_bytes
-import base64
-
-# the encrypted data can be generate with 'devscripts/generate_aes_testdata.py'
-
-
-class TestAES(unittest.TestCase):
- def setUp(self):
- self.key = self.iv = [0x20, 0x15] + 14 * [0]
- self.secret_msg = b'Secret message goes here'
-
- def test_encrypt(self):
- msg = b'message'
- key = list(range(16))
- encrypted = aes_encrypt(bytes_to_intlist(msg), key)
- decrypted = intlist_to_bytes(aes_decrypt(encrypted, key))
- self.assertEqual(decrypted, msg)
-
- def test_cbc_decrypt(self):
- data = bytes_to_intlist(
- b"\x97\x92+\xe5\x0b\xc3\x18\x91ky9m&\xb3\xb5@\xe6'\xc2\x96.\xc8u\x88\xab9-[\x9e|\xf1\xcd"
- )
- decrypted = intlist_to_bytes(aes_cbc_decrypt(data, self.key, self.iv))
- self.assertEqual(decrypted.rstrip(b'\x08'), self.secret_msg)
-
- def test_cbc_encrypt(self):
- data = bytes_to_intlist(self.secret_msg)
- encrypted = intlist_to_bytes(aes_cbc_encrypt(data, self.key, self.iv))
- self.assertEqual(
- encrypted,
- b"\x97\x92+\xe5\x0b\xc3\x18\x91ky9m&\xb3\xb5@\xe6'\xc2\x96.\xc8u\x88\xab9-[\x9e|\xf1\xcd")
-
- def test_decrypt_text(self):
- password = intlist_to_bytes(self.key).decode('utf-8')
- encrypted = base64.b64encode(
- intlist_to_bytes(self.iv[:8])
- + b'\x17\x15\x93\xab\x8d\x80V\xcdV\xe0\t\xcdo\xc2\xa5\xd8ksM\r\xe27N\xae'
- ).decode('utf-8')
- decrypted = (aes_decrypt_text(encrypted, password, 16))
- self.assertEqual(decrypted, self.secret_msg)
-
- password = intlist_to_bytes(self.key).decode('utf-8')
- encrypted = base64.b64encode(
- intlist_to_bytes(self.iv[:8])
- + b'\x0b\xe6\xa4\xd9z\x0e\xb8\xb9\xd0\xd4i_\x85\x1d\x99\x98_\xe5\x80\xe7.\xbf\xa5\x83'
- ).decode('utf-8')
- decrypted = (aes_decrypt_text(encrypted, password, 32))
- self.assertEqual(decrypted, self.secret_msg)
-
- def test_ecb_encrypt(self):
- data = bytes_to_intlist(self.secret_msg)
- encrypted = intlist_to_bytes(aes_ecb_encrypt(data, self.key))
- self.assertEqual(
- encrypted,
- b'\xaa\x86]\x81\x97>\x02\x92\x9d\x1bR[[L/u\xd3&\xd1(h\xde{\x81\x94\xba\x02\xae\xbd\xa6\xd0:')
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/test_age_restriction.py b/test/test_age_restriction.py
deleted file mode 100644
index db98494ab..000000000
--- a/test/test_age_restriction.py
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/usr/bin/env python
-from __future__ import unicode_literals
-
-# Allow direct execution
-import os
-import sys
-import unittest
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-from test.helper import try_rm
-
-
-from youtube_dl import YoutubeDL
-from youtube_dl.utils import DownloadError
-
-
-def _download_restricted(url, filename, age):
- """ Returns true if the file has been downloaded """
-
- params = {
- 'age_limit': age,
- 'skip_download': True,
- 'writeinfojson': True,
- 'outtmpl': '%(id)s.%(ext)s',
- }
- ydl = YoutubeDL(params)
- ydl.add_default_info_extractors()
- json_filename = os.path.splitext(filename)[0] + '.info.json'
- try_rm(json_filename)
- try:
- ydl.download([url])
- except DownloadError:
- try_rm(json_filename)
- res = os.path.exists(json_filename)
- try_rm(json_filename)
- return res
-
-
-class TestAgeRestriction(unittest.TestCase):
- def _assert_restricted(self, url, filename, age, old_age=None):
- self.assertTrue(_download_restricted(url, filename, old_age))
- self.assertFalse(_download_restricted(url, filename, age))
-
- def test_youtube(self):
- self._assert_restricted('HtVdAasjOgU', 'HtVdAasjOgU.mp4', 10)
-
- def test_youporn(self):
- self._assert_restricted(
- 'https://www.youporn.com/watch/16715086/sex-ed-in-detention-18-asmr/',
- '16715086.mp4', 2, old_age=25)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/test_all_urls.py b/test/test_all_urls.py
deleted file mode 100644
index 26df356b4..000000000
--- a/test/test_all_urls.py
+++ /dev/null
@@ -1,126 +0,0 @@
-#!/usr/bin/env python
-
-from __future__ import unicode_literals
-
-# Allow direct execution
-import os
-import sys
-import unittest
-import collections
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-
-from test.helper import gettestcases
-
-from youtube_dl.extractor import (
- FacebookIE,
- gen_extractors,
- YoutubeIE,
-)
-
-
-class TestAllURLsMatching(unittest.TestCase):
- def setUp(self):
- self.ies = gen_extractors()
-
- def matching_ies(self, url):
- return [ie.IE_NAME for ie in self.ies if ie.suitable(url) and ie.IE_NAME != 'generic']
-
- def assertMatch(self, url, ie_list):
- self.assertEqual(self.matching_ies(url), ie_list)
-
- def test_youtube_playlist_matching(self):
- assertPlaylist = lambda url: self.assertMatch(url, ['youtube:playlist'])
- assertTab = lambda url: self.assertMatch(url, ['youtube:tab'])
- assertPlaylist('ECUl4u3cNGP61MdtwGTqZA0MreSaDybji8')
- assertPlaylist('UUBABnxM4Ar9ten8Mdjj1j0Q') # 585
- assertPlaylist('PL63F0C78739B09958')
- assertTab('https://www.youtube.com/playlist?list=UUBABnxM4Ar9ten8Mdjj1j0Q')
- assertTab('https://www.youtube.com/course?list=ECUl4u3cNGP61MdtwGTqZA0MreSaDybji8')
- assertTab('https://www.youtube.com/playlist?list=PLwP_SiAcdui0KVebT0mU9Apz359a4ubsC')
- assertTab('https://www.youtube.com/watch?v=AV6J6_AeFEQ&playnext=1&list=PL4023E734DA416012') # 668
- self.assertFalse('youtube:playlist' in self.matching_ies('PLtS2H6bU1M'))
- # Top tracks
- assertTab('https://www.youtube.com/playlist?list=MCUS.20142101')
-
- def test_youtube_matching(self):
- self.assertTrue(YoutubeIE.suitable('PLtS2H6bU1M'))
- self.assertFalse(YoutubeIE.suitable('https://www.youtube.com/watch?v=AV6J6_AeFEQ&playnext=1&list=PL4023E734DA416012')) # 668
- self.assertMatch('http://youtu.be/BaW_jenozKc', ['youtube'])
- self.assertMatch('http://www.youtube.com/v/BaW_jenozKc', ['youtube'])
- self.assertMatch('https://youtube.googleapis.com/v/BaW_jenozKc', ['youtube'])
- self.assertMatch('http://www.cleanvideosearch.com/media/action/yt/watch?videoId=8v_4O44sfjM', ['youtube'])
-
- def test_youtube_channel_matching(self):
- assertChannel = lambda url: self.assertMatch(url, ['youtube:tab'])
- assertChannel('https://www.youtube.com/channel/HCtnHdj3df7iM')
- assertChannel('https://www.youtube.com/channel/HCtnHdj3df7iM?feature=gb_ch_rec')
- assertChannel('https://www.youtube.com/channel/HCtnHdj3df7iM/videos')
-
- def test_youtube_user_matching(self):
- self.assertMatch('http://www.youtube.com/NASAgovVideo/videos', ['youtube:tab'])
-
- def test_youtube_feeds(self):
- self.assertMatch('https://www.youtube.com/feed/library', ['youtube:tab'])
- self.assertMatch('https://www.youtube.com/feed/history', ['youtube:tab'])
- self.assertMatch('https://www.youtube.com/feed/watch_later', ['youtube:tab'])
- self.assertMatch('https://www.youtube.com/feed/subscriptions', ['youtube:tab'])
-
- def test_youtube_search_matching(self):
- self.assertMatch('http://www.youtube.com/results?search_query=making+mustard', ['youtube:search_url'])
- self.assertMatch('https://www.youtube.com/results?baz=bar&search_query=youtube-dl+test+video&filters=video&lclk=video', ['youtube:search_url'])
-
- def test_facebook_matching(self):
- self.assertTrue(FacebookIE.suitable('https://www.facebook.com/Shiniknoh#!/photo.php?v=10153317450565268'))
- self.assertTrue(FacebookIE.suitable('https://www.facebook.com/cindyweather?fref=ts#!/photo.php?v=10152183998945793'))
-
- def test_no_duplicates(self):
- ies = gen_extractors()
- for tc in gettestcases(include_onlymatching=True):
- url = tc['url']
- for ie in ies:
- if type(ie).__name__ in ('GenericIE', tc['name'] + 'IE'):
- self.assertTrue(ie.suitable(url), '%s should match URL %r' % (type(ie).__name__, url))
- else:
- self.assertFalse(
- ie.suitable(url),
- '%s should not match URL %r . That URL belongs to %s.' % (type(ie).__name__, url, tc['name']))
-
- def test_keywords(self):
- self.assertMatch(':ytsubs', ['youtube:subscriptions'])
- self.assertMatch(':ytsubscriptions', ['youtube:subscriptions'])
- self.assertMatch(':ythistory', ['youtube:history'])
-
- def test_vimeo_matching(self):
- self.assertMatch('https://vimeo.com/channels/tributes', ['vimeo:channel'])
- self.assertMatch('https://vimeo.com/channels/31259', ['vimeo:channel'])
- self.assertMatch('https://vimeo.com/channels/31259/53576664', ['vimeo'])
- self.assertMatch('https://vimeo.com/user7108434', ['vimeo:user'])
- self.assertMatch('https://vimeo.com/user7108434/videos', ['vimeo:user'])
- self.assertMatch('https://vimeo.com/user21297594/review/75524534/3c257a1b5d', ['vimeo:review'])
-
- # https://github.com/ytdl-org/youtube-dl/issues/1930
- def test_soundcloud_not_matching_sets(self):
- self.assertMatch('http://soundcloud.com/floex/sets/gone-ep', ['soundcloud:set'])
-
- def test_tumblr(self):
- self.assertMatch('http://tatianamaslanydaily.tumblr.com/post/54196191430/orphan-black-dvd-extra-behind-the-scenes', ['Tumblr'])
- self.assertMatch('http://tatianamaslanydaily.tumblr.com/post/54196191430', ['Tumblr'])
-
- def test_pbs(self):
- # https://github.com/ytdl-org/youtube-dl/issues/2350
- self.assertMatch('http://video.pbs.org/viralplayer/2365173446/', ['pbs'])
- self.assertMatch('http://video.pbs.org/widget/partnerplayer/980042464/', ['pbs'])
-
- def test_no_duplicated_ie_names(self):
- name_accu = collections.defaultdict(list)
- for ie in self.ies:
- name_accu[ie.IE_NAME.lower()].append(type(ie).__name__)
- for (ie_name, ie_list) in name_accu.items():
- self.assertEqual(
- len(ie_list), 1,
- 'Multiple extractors with the same IE_NAME "%s" (%s)' % (ie_name, ', '.join(ie_list)))
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/test_cache.py b/test/test_cache.py
deleted file mode 100644
index 931074aa1..000000000
--- a/test/test_cache.py
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/usr/bin/env python
-# coding: utf-8
-
-from __future__ import unicode_literals
-
-# Allow direct execution
-import os
-import sys
-import unittest
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-import shutil
-
-from test.helper import FakeYDL
-from youtube_dl.cache import Cache
-from youtube_dl.utils import version_tuple
-from youtube_dl.version import __version__
-
-
-def _is_empty(d):
- return not bool(os.listdir(d))
-
-
-def _mkdir(d):
- if not os.path.exists(d):
- os.mkdir(d)
-
-
-class TestCache(unittest.TestCase):
- def setUp(self):
- TEST_DIR = os.path.dirname(os.path.abspath(__file__))
- TESTDATA_DIR = os.path.join(TEST_DIR, 'testdata')
- _mkdir(TESTDATA_DIR)
- self.test_dir = os.path.join(TESTDATA_DIR, 'cache_test')
- self.tearDown()
-
- def tearDown(self):
- if os.path.exists(self.test_dir):
- shutil.rmtree(self.test_dir)
-
- def test_cache(self):
- ydl = FakeYDL({
- 'cachedir': self.test_dir,
- })
- c = Cache(ydl)
- obj = {'x': 1, 'y': ['ä', '\\a', True]}
- self.assertEqual(c.load('test_cache', 'k.'), None)
- c.store('test_cache', 'k.', obj)
- self.assertEqual(c.load('test_cache', 'k2'), None)
- self.assertFalse(_is_empty(self.test_dir))
- self.assertEqual(c.load('test_cache', 'k.'), obj)
- self.assertEqual(c.load('test_cache', 'y'), None)
- self.assertEqual(c.load('test_cache2', 'k.'), None)
- c.remove()
- self.assertFalse(os.path.exists(self.test_dir))
- self.assertEqual(c.load('test_cache', 'k.'), None)
-
- def test_cache_validation(self):
- ydl = FakeYDL({
- 'cachedir': self.test_dir,
- })
- c = Cache(ydl)
- obj = {'x': 1, 'y': ['ä', '\\a', True]}
- c.store('test_cache', 'k.', obj)
- self.assertEqual(c.load('test_cache', 'k.', min_ver='1970.01.01'), obj)
- new_version = '.'.join(('%d' % ((v + 1) if i == 0 else v, )) for i, v in enumerate(version_tuple(__version__)))
- self.assertIs(c.load('test_cache', 'k.', min_ver=new_version), None)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/test_compat.py b/test/test_compat.py
deleted file mode 100644
index b83c8cb41..000000000
--- a/test/test_compat.py
+++ /dev/null
@@ -1,154 +0,0 @@
-#!/usr/bin/env python
-# coding: utf-8
-
-from __future__ import unicode_literals
-
-# Allow direct execution
-import os
-import sys
-import unittest
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-
-from youtube_dl.compat import (
- compat_casefold,
- compat_getenv,
- compat_setenv,
- compat_etree_Element,
- compat_etree_fromstring,
- compat_expanduser,
- compat_shlex_split,
- compat_str,
- compat_struct_unpack,
- compat_urllib_parse_unquote,
- compat_urllib_parse_unquote_plus,
- compat_urllib_parse_urlencode,
- compat_urllib_request,
-)
-
-
-class TestCompat(unittest.TestCase):
- def test_compat_getenv(self):
- test_str = 'тест'
- compat_setenv('YOUTUBE_DL_COMPAT_GETENV', test_str)
- self.assertEqual(compat_getenv('YOUTUBE_DL_COMPAT_GETENV'), test_str)
-
- def test_compat_setenv(self):
- test_var = 'YOUTUBE_DL_COMPAT_SETENV'
- test_str = 'тест'
- compat_setenv(test_var, test_str)
- compat_getenv(test_var)
- self.assertEqual(compat_getenv(test_var), test_str)
-
- def test_compat_expanduser(self):
- old_home = os.environ.get('HOME')
- test_str = r'C:\Documents and Settings\тест\Application Data'
- compat_setenv('HOME', test_str)
- self.assertEqual(compat_expanduser('~'), test_str)
- compat_setenv('HOME', old_home or '')
-
- def test_all_present(self):
- import youtube_dl.compat
- all_names = sorted(
- youtube_dl.compat.__all__ + youtube_dl.compat.legacy)
- present_names = set(map(compat_str, filter(
- lambda c: '_' in c and not c.startswith('_'),
- dir(youtube_dl.compat)))) - set(['unicode_literals'])
- self.assertEqual(all_names, sorted(present_names))
-
- def test_compat_urllib_parse_unquote(self):
- self.assertEqual(compat_urllib_parse_unquote('abc%20def'), 'abc def')
- self.assertEqual(compat_urllib_parse_unquote('%7e/abc+def'), '~/abc+def')
- self.assertEqual(compat_urllib_parse_unquote(''), '')
- self.assertEqual(compat_urllib_parse_unquote('%'), '%')
- self.assertEqual(compat_urllib_parse_unquote('%%'), '%%')
- self.assertEqual(compat_urllib_parse_unquote('%%%'), '%%%')
- self.assertEqual(compat_urllib_parse_unquote('%2F'), '/')
- self.assertEqual(compat_urllib_parse_unquote('%2f'), '/')
- self.assertEqual(compat_urllib_parse_unquote('%E6%B4%A5%E6%B3%A2'), '津波')
- self.assertEqual(
- compat_urllib_parse_unquote('''
-%%a'''),
- '''
-%%a''')
- self.assertEqual(
- compat_urllib_parse_unquote('''%28%5E%E2%97%A3_%E2%97%A2%5E%29%E3%81%A3%EF%B8%BB%E3%83%87%E2%95%90%E4%B8%80 %E2%87%80 %E2%87%80 %E2%87%80 %E2%87%80 %E2%87%80 %E2%86%B6%I%Break%25Things%'''),
- '''(^◣_◢^)っ︻デ═一 ⇀ ⇀ ⇀ ⇀ ⇀ ↶%I%Break%Things%''')
-
- def test_compat_urllib_parse_unquote_plus(self):
- self.assertEqual(compat_urllib_parse_unquote_plus('abc%20def'), 'abc def')
- self.assertEqual(compat_urllib_parse_unquote_plus('%7e/abc+def'), '~/abc def')
-
- def test_compat_urllib_parse_urlencode(self):
- self.assertEqual(compat_urllib_parse_urlencode({'abc': 'def'}), 'abc=def')
- self.assertEqual(compat_urllib_parse_urlencode({'abc': b'def'}), 'abc=def')
- self.assertEqual(compat_urllib_parse_urlencode({b'abc': 'def'}), 'abc=def')
- self.assertEqual(compat_urllib_parse_urlencode({b'abc': b'def'}), 'abc=def')
- self.assertEqual(compat_urllib_parse_urlencode([('abc', 'def')]), 'abc=def')
- self.assertEqual(compat_urllib_parse_urlencode([('abc', b'def')]), 'abc=def')
- self.assertEqual(compat_urllib_parse_urlencode([(b'abc', 'def')]), 'abc=def')
- self.assertEqual(compat_urllib_parse_urlencode([(b'abc', b'def')]), 'abc=def')
-
- def test_compat_shlex_split(self):
- self.assertEqual(compat_shlex_split('-option "one two"'), ['-option', 'one two'])
- self.assertEqual(compat_shlex_split('-option "one\ntwo" \n -flag'), ['-option', 'one\ntwo', '-flag'])
- self.assertEqual(compat_shlex_split('-val 中文'), ['-val', '中文'])
-
- def test_compat_etree_Element(self):
- try:
- compat_etree_Element.items
- except AttributeError:
- self.fail('compat_etree_Element is not a type')
-
- def test_compat_etree_fromstring(self):
- xml = '''
-
- foo
- 中文
- spam
-
- '''
- doc = compat_etree_fromstring(xml.encode('utf-8'))
- self.assertTrue(isinstance(doc.attrib['foo'], compat_str))
- self.assertTrue(isinstance(doc.attrib['spam'], compat_str))
- self.assertTrue(isinstance(doc.find('normal').text, compat_str))
- self.assertTrue(isinstance(doc.find('chinese').text, compat_str))
- self.assertTrue(isinstance(doc.find('foo/bar').text, compat_str))
-
- def test_compat_etree_fromstring_doctype(self):
- xml = '''
-
-'''
- compat_etree_fromstring(xml)
-
- def test_compat_struct_unpack(self):
- self.assertEqual(compat_struct_unpack('!B', b'\x00'), (0,))
-
- def test_compat_casefold(self):
- if hasattr(compat_str, 'casefold'):
- # don't bother to test str.casefold() (again)
- return
- # thanks https://bugs.python.org/file24232/casefolding.patch
- self.assertEqual(compat_casefold('hello'), 'hello')
- self.assertEqual(compat_casefold('hELlo'), 'hello')
- self.assertEqual(compat_casefold('ß'), 'ss')
- self.assertEqual(compat_casefold('fi'), 'fi')
- self.assertEqual(compat_casefold('\u03a3'), '\u03c3')
- self.assertEqual(compat_casefold('A\u0345\u03a3'), 'a\u03b9\u03c3')
-
- def test_compat_urllib_request_Request(self):
- self.assertEqual(
- compat_urllib_request.Request('http://127.0.0.1', method='PUT').get_method(),
- 'PUT')
-
- class PUTrequest(compat_urllib_request.Request):
- def get_method(self):
- return 'PUT'
-
- self.assertEqual(
- PUTrequest('http://127.0.0.1').get_method(),
- 'PUT')
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/test_download.py b/test/test_download.py
deleted file mode 100644
index f7d6a23bc..000000000
--- a/test/test_download.py
+++ /dev/null
@@ -1,294 +0,0 @@
-#!/usr/bin/env python
-
-from __future__ import unicode_literals
-
-# Allow direct execution
-import os
-import sys
-import unittest
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-from test.helper import (
- expect_warnings,
- get_params,
- gettestcases,
- expect_info_dict,
- try_rm,
- report_warning,
-)
-
-
-import hashlib
-import json
-import socket
-
-import youtube_dl.YoutubeDL
-from youtube_dl.compat import (
- compat_http_client,
- compat_HTTPError,
- compat_open as open,
- compat_urllib_error,
-)
-from youtube_dl.utils import (
- DownloadError,
- ExtractorError,
- error_to_compat_str,
- format_bytes,
- IDENTITY,
- preferredencoding,
- UnavailableVideoError,
-)
-from youtube_dl.extractor import get_info_extractor
-
-RETRIES = 3
-
-# Some unittest APIs require actual str
-if not isinstance('TEST', str):
- _encode_str = lambda s: s.encode(preferredencoding())
-else:
- _encode_str = IDENTITY
-
-
-class YoutubeDL(youtube_dl.YoutubeDL):
- def __init__(self, *args, **kwargs):
- self.to_stderr = self.to_screen
- self.processed_info_dicts = []
- super(YoutubeDL, self).__init__(*args, **kwargs)
-
- def report_warning(self, message):
- # Don't accept warnings during tests
- raise ExtractorError(message)
-
- def process_info(self, info_dict):
- self.processed_info_dicts.append(info_dict)
- return super(YoutubeDL, self).process_info(info_dict)
-
-
-def _file_md5(fn):
- with open(fn, 'rb') as f:
- return hashlib.md5(f.read()).hexdigest()
-
-
-defs = gettestcases()
-
-
-class TestDownload(unittest.TestCase):
- # Parallel testing in nosetests. See
- # http://nose.readthedocs.org/en/latest/doc_tests/test_multiprocess/multiprocess.html
- _multiprocess_shared_ = True
-
- maxDiff = None
-
- def __str__(self):
- """Identify each test with the `add_ie` attribute, if available."""
-
- def strclass(cls):
- """From 2.7's unittest; 2.6 had _strclass so we can't import it."""
- return '%s.%s' % (cls.__module__, cls.__name__)
-
- add_ie = getattr(self, self._testMethodName).add_ie
- return '%s (%s)%s:' % (self._testMethodName,
- strclass(self.__class__),
- ' [%s]' % add_ie if add_ie else '')
-
- def setUp(self):
- self.defs = defs
-
-# Dynamically generate tests
-
-
-def generator(test_case, tname):
-
- def test_template(self):
- ie = youtube_dl.extractor.get_info_extractor(test_case['name'])()
- other_ies = [get_info_extractor(ie_key)() for ie_key in test_case.get('add_ie', [])]
- is_playlist = any(k.startswith('playlist') for k in test_case)
- test_cases = test_case.get(
- 'playlist', [] if is_playlist else [test_case])
-
- def print_skipping(reason):
- print('Skipping %s: %s' % (test_case['name'], reason))
- self.skipTest(_encode_str(reason))
-
- if not ie.working():
- print_skipping('IE marked as not _WORKING')
-
- for tc in test_cases:
- info_dict = tc.get('info_dict', {})
- if not (info_dict.get('id') and info_dict.get('ext')):
- raise Exception('Test definition (%s) requires both \'id\' and \'ext\' keys present to define the output file' % (tname, ))
-
- if 'skip' in test_case:
- print_skipping(test_case['skip'])
-
- for other_ie in other_ies:
- if not other_ie.working():
- print_skipping('test depends on %sIE, marked as not WORKING' % other_ie.ie_key())
-
- params = get_params(test_case.get('params', {}))
- params['outtmpl'] = tname + '_' + params['outtmpl']
- if is_playlist and 'playlist' not in test_case:
- params.setdefault('extract_flat', 'in_playlist')
- params.setdefault('playlistend',
- test_case['playlist_maxcount'] + 1
- if test_case.get('playlist_maxcount')
- else test_case.get('playlist_mincount'))
- params.setdefault('skip_download', True)
-
- ydl = YoutubeDL(params, auto_init=False)
- ydl.add_default_info_extractors()
- finished_hook_called = set()
-
- def _hook(status):
- if status['status'] == 'finished':
- finished_hook_called.add(status['filename'])
- ydl.add_progress_hook(_hook)
- expect_warnings(ydl, test_case.get('expected_warnings', []))
-
- def get_tc_filename(tc):
- return ydl.prepare_filename(tc.get('info_dict', {}))
-
- res_dict = None
-
- def try_rm_tcs_files(tcs=None):
- if tcs is None:
- tcs = test_cases
- for tc in tcs:
- tc_filename = get_tc_filename(tc)
- try_rm(tc_filename)
- try_rm(tc_filename + '.part')
- try_rm(os.path.splitext(tc_filename)[0] + '.info.json')
-
- try_rm_tcs_files()
- try:
- try_num = 1
- while True:
- try:
- # We're not using .download here since that is just a shim
- # for outside error handling, and returns the exit code
- # instead of the result dict.
- res_dict = ydl.extract_info(
- test_case['url'],
- force_generic_extractor=params.get('force_generic_extractor', False))
- except (DownloadError, ExtractorError) as err:
- # Check if the exception is not a network related one
- if not err.exc_info[0] in (compat_urllib_error.URLError, socket.timeout, UnavailableVideoError, compat_http_client.BadStatusLine) or (err.exc_info[0] == compat_HTTPError and err.exc_info[1].code == 503):
- msg = getattr(err, 'msg', error_to_compat_str(err))
- err.msg = '%s (%s)' % (msg, tname, )
- raise err
-
- if try_num == RETRIES:
- report_warning('%s failed due to network errors, skipping...' % tname)
- return
-
- print('Retrying: {0} failed tries\n\n##########\n\n'.format(try_num))
-
- try_num += 1
- else:
- break
-
- if is_playlist:
- self.assertTrue(res_dict['_type'] in ['playlist', 'multi_video'])
- self.assertTrue('entries' in res_dict)
- expect_info_dict(self, res_dict, test_case.get('info_dict', {}))
-
- if 'playlist_mincount' in test_case:
- self.assertGreaterEqual(
- len(res_dict['entries']),
- test_case['playlist_mincount'],
- 'Expected at least %d in playlist %s, but got only %d' % (
- test_case['playlist_mincount'], test_case['url'],
- len(res_dict['entries'])))
- if 'playlist_maxcount' in test_case:
- self.assertLessEqual(
- len(res_dict['entries']),
- test_case['playlist_maxcount'],
- 'Expected at most %d in playlist %s, but got %d' % (
- test_case['playlist_maxcount'], test_case['url'],
- len(res_dict['entries'])))
- if 'playlist_count' in test_case:
- self.assertEqual(
- len(res_dict['entries']),
- test_case['playlist_count'],
- 'Expected %d entries in playlist %s, but got %d.' % (
- test_case['playlist_count'],
- test_case['url'],
- len(res_dict['entries']),
- ))
- if 'playlist_duration_sum' in test_case:
- got_duration = sum(e['duration'] for e in res_dict['entries'])
- self.assertEqual(
- test_case['playlist_duration_sum'], got_duration)
-
- # Generalize both playlists and single videos to unified format for
- # simplicity
- if 'entries' not in res_dict:
- res_dict['entries'] = [res_dict]
-
- for tc_num, tc in enumerate(test_cases):
- tc_res_dict = res_dict['entries'][tc_num]
- # First, check test cases' data against extracted data alone
- expect_info_dict(self, tc_res_dict, tc.get('info_dict', {}))
- # Now, check downloaded file consistency
- # support test-case with volatile ID, signalled by regexp value
- if tc.get('info_dict', {}).get('id', '').startswith('re:'):
- test_id = tc['info_dict']['id']
- tc['info_dict']['id'] = tc_res_dict['id']
- else:
- test_id = None
- tc_filename = get_tc_filename(tc)
- if test_id:
- tc['info_dict']['id'] = test_id
- if not test_case.get('params', {}).get('skip_download', False):
- self.assertTrue(os.path.exists(tc_filename), msg='Missing file ' + tc_filename)
- self.assertTrue(tc_filename in finished_hook_called)
- expected_minsize = tc.get('file_minsize', 10000)
- if expected_minsize is not None:
- if params.get('test'):
- expected_minsize = max(expected_minsize, 10000)
- got_fsize = os.path.getsize(tc_filename)
- self.assertGreaterEqual(
- got_fsize, expected_minsize,
- 'Expected %s to be at least %s, but it\'s only %s ' %
- (tc_filename, format_bytes(expected_minsize),
- format_bytes(got_fsize)))
- if 'md5' in tc:
- md5_for_file = _file_md5(tc_filename)
- self.assertEqual(tc['md5'], md5_for_file)
- # Finally, check test cases' data again but this time against
- # extracted data from info JSON file written during processing
- info_json_fn = os.path.splitext(tc_filename)[0] + '.info.json'
- self.assertTrue(
- os.path.exists(info_json_fn),
- 'Missing info file %s' % info_json_fn)
- with open(info_json_fn, encoding='utf-8') as infof:
- info_dict = json.load(infof)
- expect_info_dict(self, info_dict, tc.get('info_dict', {}))
- finally:
- try_rm_tcs_files()
- if is_playlist and res_dict is not None and res_dict.get('entries'):
- # Remove all other files that may have been extracted if the
- # extractor returns full results even with extract_flat
- res_tcs = [{'info_dict': e} for e in res_dict['entries']]
- try_rm_tcs_files(res_tcs)
-
- return test_template
-
-
-# And add them to TestDownload
-for n, test_case in enumerate(defs):
- tname = 'test_' + str(test_case['name'])
- i = 1
- while hasattr(TestDownload, tname):
- tname = 'test_%s_%d' % (test_case['name'], i)
- i += 1
- test_method = generator(test_case, tname)
- test_method.__name__ = str(tname)
- ie_list = test_case.get('add_ie')
- test_method.add_ie = ie_list and ','.join(ie_list)
- setattr(TestDownload, test_method.__name__, test_method)
- del test_method
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/test_downloader_external.py b/test/test_downloader_external.py
deleted file mode 100644
index 4491bd9de..000000000
--- a/test/test_downloader_external.py
+++ /dev/null
@@ -1,272 +0,0 @@
-#!/usr/bin/env python
-# coding: utf-8
-from __future__ import unicode_literals
-
-# Allow direct execution
-import os
-import re
-import sys
-import subprocess
-import unittest
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-from test.helper import (
- FakeLogger,
- FakeYDL,
- http_server_port,
- try_rm,
-)
-from youtube_dl import YoutubeDL
-from youtube_dl.compat import (
- compat_contextlib_suppress,
- compat_http_cookiejar_Cookie,
- compat_http_server,
- compat_kwargs,
-)
-from youtube_dl.utils import (
- encodeFilename,
- join_nonempty,
-)
-from youtube_dl.downloader.external import (
- Aria2cFD,
- Aria2pFD,
- AxelFD,
- CurlFD,
- FFmpegFD,
- HttpieFD,
- WgetFD,
-)
-from youtube_dl.postprocessor import (
- FFmpegPostProcessor,
-)
-import threading
-
-TEST_SIZE = 10 * 1024
-
-TEST_COOKIE = {
- 'version': 0,
- 'name': 'test',
- 'value': 'ytdlp',
- 'port': None,
- 'port_specified': False,
- 'domain': '.example.com',
- 'domain_specified': True,
- 'domain_initial_dot': False,
- 'path': '/',
- 'path_specified': True,
- 'secure': False,
- 'expires': None,
- 'discard': False,
- 'comment': None,
- 'comment_url': None,
- 'rest': {},
-}
-
-TEST_COOKIE_VALUE = join_nonempty('name', 'value', delim='=', from_dict=TEST_COOKIE)
-
-TEST_INFO = {'url': 'http://www.example.com/'}
-
-
-def cookiejar_Cookie(**cookie_args):
- return compat_http_cookiejar_Cookie(**compat_kwargs(cookie_args))
-
-
-def ifExternalFDAvailable(externalFD):
- return unittest.skipUnless(externalFD.available(),
- externalFD.get_basename() + ' not found')
-
-
-class HTTPTestRequestHandler(compat_http_server.BaseHTTPRequestHandler):
- def log_message(self, format, *args):
- pass
-
- def send_content_range(self, total=None):
- range_header = self.headers.get('Range')
- start = end = None
- if range_header:
- mobj = re.match(r'bytes=(\d+)-(\d+)', range_header)
- if mobj:
- start, end = (int(mobj.group(i)) for i in (1, 2))
- valid_range = start is not None and end is not None
- if valid_range:
- content_range = 'bytes %d-%d' % (start, end)
- if total:
- content_range += '/%d' % total
- self.send_header('Content-Range', content_range)
- return (end - start + 1) if valid_range else total
-
- def serve(self, range=True, content_length=True):
- self.send_response(200)
- self.send_header('Content-Type', 'video/mp4')
- size = TEST_SIZE
- if range:
- size = self.send_content_range(TEST_SIZE)
- if content_length:
- self.send_header('Content-Length', size)
- self.end_headers()
- self.wfile.write(b'#' * size)
-
- def do_GET(self):
- if self.path == '/regular':
- self.serve()
- elif self.path == '/no-content-length':
- self.serve(content_length=False)
- elif self.path == '/no-range':
- self.serve(range=False)
- elif self.path == '/no-range-no-content-length':
- self.serve(range=False, content_length=False)
- else:
- assert False, 'unrecognised server path'
-
-
-@ifExternalFDAvailable(Aria2pFD)
-class TestAria2pFD(unittest.TestCase):
- def setUp(self):
- self.httpd = compat_http_server.HTTPServer(
- ('127.0.0.1', 0), HTTPTestRequestHandler)
- self.port = http_server_port(self.httpd)
- self.server_thread = threading.Thread(target=self.httpd.serve_forever)
- self.server_thread.daemon = True
- self.server_thread.start()
-
- def download(self, params, ep):
- with subprocess.Popen(
- ['aria2c', '--enable-rpc'],
- stdout=subprocess.DEVNULL,
- stderr=subprocess.DEVNULL
- ) as process:
- if not process.poll():
- filename = 'testfile.mp4'
- params['logger'] = FakeLogger()
- params['outtmpl'] = filename
- ydl = YoutubeDL(params)
- try_rm(encodeFilename(filename))
- self.assertEqual(ydl.download(['http://127.0.0.1:%d/%s' % (self.port, ep)]), 0)
- self.assertEqual(os.path.getsize(encodeFilename(filename)), TEST_SIZE)
- try_rm(encodeFilename(filename))
- process.kill()
-
- def download_all(self, params):
- for ep in ('regular', 'no-content-length', 'no-range', 'no-range-no-content-length'):
- self.download(params, ep)
-
- def test_regular(self):
- self.download_all({'external_downloader': 'aria2p'})
-
- def test_chunked(self):
- self.download_all({
- 'external_downloader': 'aria2p',
- 'http_chunk_size': 1000,
- })
-
-
-@ifExternalFDAvailable(HttpieFD)
-class TestHttpieFD(unittest.TestCase):
- def test_make_cmd(self):
- with FakeYDL() as ydl:
- downloader = HttpieFD(ydl, {})
- self.assertEqual(
- downloader._make_cmd('test', TEST_INFO),
- ['http', '--download', '--output', 'test', 'http://www.example.com/'])
-
- # Test cookie header is added
- ydl.cookiejar.set_cookie(cookiejar_Cookie(**TEST_COOKIE))
- self.assertEqual(
- downloader._make_cmd('test', TEST_INFO),
- ['http', '--download', '--output', 'test',
- 'http://www.example.com/', 'Cookie:' + TEST_COOKIE_VALUE])
-
-
-@ifExternalFDAvailable(AxelFD)
-class TestAxelFD(unittest.TestCase):
- def test_make_cmd(self):
- with FakeYDL() as ydl:
- downloader = AxelFD(ydl, {})
- self.assertEqual(
- downloader._make_cmd('test', TEST_INFO),
- ['axel', '-o', 'test', '--', 'http://www.example.com/'])
-
- # Test cookie header is added
- ydl.cookiejar.set_cookie(cookiejar_Cookie(**TEST_COOKIE))
- self.assertEqual(
- downloader._make_cmd('test', TEST_INFO),
- ['axel', '-o', 'test', '-H', 'Cookie: ' + TEST_COOKIE_VALUE,
- '--max-redirect=0', '--', 'http://www.example.com/'])
-
-
-@ifExternalFDAvailable(WgetFD)
-class TestWgetFD(unittest.TestCase):
- def test_make_cmd(self):
- with FakeYDL() as ydl:
- downloader = WgetFD(ydl, {})
- self.assertNotIn('--load-cookies', downloader._make_cmd('test', TEST_INFO))
- # Test cookiejar tempfile arg is added
- ydl.cookiejar.set_cookie(cookiejar_Cookie(**TEST_COOKIE))
- self.assertIn('--load-cookies', downloader._make_cmd('test', TEST_INFO))
-
-
-@ifExternalFDAvailable(CurlFD)
-class TestCurlFD(unittest.TestCase):
- def test_make_cmd(self):
- with FakeYDL() as ydl:
- downloader = CurlFD(ydl, {})
- self.assertNotIn('--cookie', downloader._make_cmd('test', TEST_INFO))
- # Test cookie header is added
- ydl.cookiejar.set_cookie(cookiejar_Cookie(**TEST_COOKIE))
- self.assertIn('--cookie', downloader._make_cmd('test', TEST_INFO))
- self.assertIn(TEST_COOKIE_VALUE, downloader._make_cmd('test', TEST_INFO))
-
-
-@ifExternalFDAvailable(Aria2cFD)
-class TestAria2cFD(unittest.TestCase):
- def test_make_cmd(self):
- with FakeYDL() as ydl:
- downloader = Aria2cFD(ydl, {})
- downloader._make_cmd('test', TEST_INFO)
- self.assertFalse(hasattr(downloader, '_cookies_tempfile'))
-
- # Test cookiejar tempfile arg is added
- ydl.cookiejar.set_cookie(cookiejar_Cookie(**TEST_COOKIE))
- cmd = downloader._make_cmd('test', TEST_INFO)
- self.assertIn('--load-cookies=%s' % downloader._cookies_tempfile, cmd)
-
-
-# Handle delegated availability
-def ifFFmpegFDAvailable(externalFD):
- # raise SkipTest, or set False!
- avail = ifExternalFDAvailable(externalFD) and False
- with compat_contextlib_suppress(Exception):
- avail = FFmpegPostProcessor(downloader=None).available
- return unittest.skipUnless(
- avail, externalFD.get_basename() + ' not found')
-
-
-@ifFFmpegFDAvailable(FFmpegFD)
-class TestFFmpegFD(unittest.TestCase):
- _args = []
-
- def _test_cmd(self, args):
- self._args = args
-
- def test_make_cmd(self):
- with FakeYDL() as ydl:
- downloader = FFmpegFD(ydl, {})
- downloader._debug_cmd = self._test_cmd
- info_dict = TEST_INFO.copy()
- info_dict['ext'] = 'mp4'
-
- downloader._call_downloader('test', info_dict)
- self.assertEqual(self._args, [
- 'ffmpeg', '-y', '-i', 'http://www.example.com/',
- '-c', 'copy', '-f', 'mp4', 'file:test'])
-
- # Test cookies arg is added
- ydl.cookiejar.set_cookie(cookiejar_Cookie(**TEST_COOKIE))
- downloader._call_downloader('test', info_dict)
- self.assertEqual(self._args, [
- 'ffmpeg', '-y', '-cookies', TEST_COOKIE_VALUE + '; path=/; domain=.example.com;\r\n',
- '-i', 'http://www.example.com/', '-c', 'copy', '-f', 'mp4', 'file:test'])
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/test_downloader_http.py b/test/test_downloader_http.py
deleted file mode 100644
index 6af86ae48..000000000
--- a/test/test_downloader_http.py
+++ /dev/null
@@ -1,108 +0,0 @@
-#!/usr/bin/env python
-# coding: utf-8
-from __future__ import unicode_literals
-
-# Allow direct execution
-import os
-import re
-import sys
-import unittest
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-from test.helper import (
- FakeLogger,
- http_server_port,
- try_rm,
-)
-from youtube_dl import YoutubeDL
-from youtube_dl.compat import compat_http_server
-from youtube_dl.downloader.http import HttpFD
-from youtube_dl.utils import encodeFilename
-import threading
-
-TEST_DIR = os.path.dirname(os.path.abspath(__file__))
-
-
-TEST_SIZE = 10 * 1024
-
-
-class HTTPTestRequestHandler(compat_http_server.BaseHTTPRequestHandler):
- def log_message(self, format, *args):
- pass
-
- def send_content_range(self, total=None):
- range_header = self.headers.get('Range')
- start = end = None
- if range_header:
- mobj = re.search(r'^bytes=(\d+)-(\d+)', range_header)
- if mobj:
- start = int(mobj.group(1))
- end = int(mobj.group(2))
- valid_range = start is not None and end is not None
- if valid_range:
- content_range = 'bytes %d-%d' % (start, end)
- if total:
- content_range += '/%d' % total
- self.send_header('Content-Range', content_range)
- return (end - start + 1) if valid_range else total
-
- def serve(self, range=True, content_length=True):
- self.send_response(200)
- self.send_header('Content-Type', 'video/mp4')
- size = TEST_SIZE
- if range:
- size = self.send_content_range(TEST_SIZE)
- if content_length:
- self.send_header('Content-Length', size)
- self.end_headers()
- self.wfile.write(b'#' * size)
-
- def do_GET(self):
- if self.path == '/regular':
- self.serve()
- elif self.path == '/no-content-length':
- self.serve(content_length=False)
- elif self.path == '/no-range':
- self.serve(range=False)
- elif self.path == '/no-range-no-content-length':
- self.serve(range=False, content_length=False)
- else:
- assert False
-
-
-class TestHttpFD(unittest.TestCase):
- def setUp(self):
- self.httpd = compat_http_server.HTTPServer(
- ('127.0.0.1', 0), HTTPTestRequestHandler)
- self.port = http_server_port(self.httpd)
- self.server_thread = threading.Thread(target=self.httpd.serve_forever)
- self.server_thread.daemon = True
- self.server_thread.start()
-
- def download(self, params, ep):
- params['logger'] = FakeLogger()
- ydl = YoutubeDL(params)
- downloader = HttpFD(ydl, params)
- filename = 'testfile.mp4'
- try_rm(encodeFilename(filename))
- self.assertTrue(downloader.real_download(filename, {
- 'url': 'http://127.0.0.1:%d/%s' % (self.port, ep),
- }))
- self.assertEqual(os.path.getsize(encodeFilename(filename)), TEST_SIZE, ep)
- try_rm(encodeFilename(filename))
-
- def download_all(self, params):
- for ep in ('regular', 'no-content-length', 'no-range', 'no-range-no-content-length'):
- self.download(params, ep)
-
- def test_regular(self):
- self.download_all({})
-
- def test_chunked(self):
- self.download_all({
- 'http_chunk_size': 1000,
- })
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/test_execution.py b/test/test_execution.py
deleted file mode 100644
index 9daaafa6c..000000000
--- a/test/test_execution.py
+++ /dev/null
@@ -1,62 +0,0 @@
-#!/usr/bin/env python
-# coding: utf-8
-
-from __future__ import unicode_literals
-
-import unittest
-
-import sys
-import os
-import subprocess
-
-rootDir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-
-sys.path.insert(0, rootDir)
-
-from youtube_dl.compat import compat_register_utf8, compat_subprocess_get_DEVNULL
-from youtube_dl.utils import encodeArgument
-
-compat_register_utf8()
-
-
-_DEV_NULL = compat_subprocess_get_DEVNULL()
-
-
-class TestExecution(unittest.TestCase):
- def setUp(self):
- self.module = 'youtube_dl'
- if sys.version_info < (2, 7):
- self.module += '.__main__'
-
- def test_import(self):
- subprocess.check_call([sys.executable, '-c', 'import youtube_dl'], cwd=rootDir)
-
- def test_module_exec(self):
- subprocess.check_call([sys.executable, '-m', self.module, '--version'], cwd=rootDir, stdout=_DEV_NULL)
-
- def test_main_exec(self):
- subprocess.check_call([sys.executable, os.path.normpath('youtube_dl/__main__.py'), '--version'], cwd=rootDir, stdout=_DEV_NULL)
-
- def test_cmdline_umlauts(self):
- os.environ['PYTHONIOENCODING'] = 'utf-8'
- p = subprocess.Popen(
- [sys.executable, '-m', self.module, encodeArgument('ä'), '--version'],
- cwd=rootDir, stdout=_DEV_NULL, stderr=subprocess.PIPE)
- _, stderr = p.communicate()
- self.assertFalse(stderr)
-
- def test_lazy_extractors(self):
- lazy_extractors = os.path.normpath('youtube_dl/extractor/lazy_extractors.py')
- try:
- subprocess.check_call([sys.executable, os.path.normpath('devscripts/make_lazy_extractors.py'), lazy_extractors], cwd=rootDir, stdout=_DEV_NULL)
- subprocess.check_call([sys.executable, os.path.normpath('test/test_all_urls.py')], cwd=rootDir, stdout=_DEV_NULL)
- finally:
- for x in ('', 'c') if sys.version_info[0] < 3 else ('',):
- try:
- os.remove(lazy_extractors + x)
- except OSError:
- pass
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/test_http.py b/test/test_http.py
deleted file mode 100644
index 485c4c6fc..000000000
--- a/test/test_http.py
+++ /dev/null
@@ -1,604 +0,0 @@
-#!/usr/bin/env python
-# coding: utf-8
-from __future__ import unicode_literals
-
-# Allow direct execution
-import os
-import sys
-import unittest
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-import contextlib
-import gzip
-import io
-import ssl
-import tempfile
-import threading
-import zlib
-
-# avoid deprecated alias assertRaisesRegexp
-if hasattr(unittest.TestCase, 'assertRaisesRegex'):
- unittest.TestCase.assertRaisesRegexp = unittest.TestCase.assertRaisesRegex
-
-try:
- import brotli
-except ImportError:
- brotli = None
-try:
- from urllib.request import pathname2url
-except ImportError:
- from urllib import pathname2url
-
-from youtube_dl.compat import (
- compat_http_cookiejar_Cookie,
- compat_http_server,
- compat_str as str,
- compat_urllib_error,
- compat_urllib_HTTPError,
- compat_urllib_parse,
- compat_urllib_request,
-)
-
-from youtube_dl.utils import (
- sanitized_Request,
- update_Request,
- urlencode_postdata,
-)
-
-from test.helper import (
- expectedFailureIf,
- FakeYDL,
- FakeLogger,
- http_server_port,
-)
-from youtube_dl import YoutubeDL
-
-TEST_DIR = os.path.dirname(os.path.abspath(__file__))
-
-
-class HTTPTestRequestHandler(compat_http_server.BaseHTTPRequestHandler):
- protocol_version = 'HTTP/1.1'
-
- # work-around old/new -style class inheritance
- def super(self, meth_name, *args, **kwargs):
- from types import MethodType
- try:
- super()
- fn = lambda s, m, *a, **k: getattr(super(), m)(*a, **k)
- except TypeError:
- fn = lambda s, m, *a, **k: getattr(compat_http_server.BaseHTTPRequestHandler, m)(s, *a, **k)
- self.super = MethodType(fn, self)
- return self.super(meth_name, *args, **kwargs)
-
- def log_message(self, format, *args):
- pass
-
- def _headers(self):
- payload = str(self.headers).encode('utf-8')
- self.send_response(200)
- self.send_header('Content-Type', 'application/json')
- self.send_header('Content-Length', str(len(payload)))
- self.end_headers()
- self.wfile.write(payload)
-
- def _redirect(self):
- self.send_response(int(self.path[len('/redirect_'):]))
- self.send_header('Location', '/method')
- self.send_header('Content-Length', '0')
- self.end_headers()
-
- def _method(self, method, payload=None):
- self.send_response(200)
- self.send_header('Content-Length', str(len(payload or '')))
- self.send_header('Method', method)
- self.end_headers()
- if payload:
- self.wfile.write(payload)
-
- def _status(self, status):
- payload = '{0} NOT FOUND'.format(status).encode('utf-8')
- self.send_response(int(status))
- self.send_header('Content-Type', 'text/html; charset=utf-8')
- self.send_header('Content-Length', str(len(payload)))
- self.end_headers()
- self.wfile.write(payload)
-
- def _read_data(self):
- if 'Content-Length' in self.headers:
- return self.rfile.read(int(self.headers['Content-Length']))
-
- def _test_url(self, path, host='127.0.0.1', scheme='http', port=None):
- return '{0}://{1}:{2}/{3}'.format(
- scheme, host,
- port if port is not None
- else http_server_port(self.server), path)
-
- def do_POST(self):
- data = self._read_data()
- if self.path.startswith('/redirect_'):
- self._redirect()
- elif self.path.startswith('/method'):
- self._method('POST', data)
- elif self.path.startswith('/headers'):
- self._headers()
- else:
- self._status(404)
-
- def do_HEAD(self):
- if self.path.startswith('/redirect_'):
- self._redirect()
- elif self.path.startswith('/method'):
- self._method('HEAD')
- else:
- self._status(404)
-
- def do_PUT(self):
- data = self._read_data()
- if self.path.startswith('/redirect_'):
- self._redirect()
- elif self.path.startswith('/method'):
- self._method('PUT', data)
- else:
- self._status(404)
-
- def do_GET(self):
-
- def respond(payload=b'',
- payload_type='text/html; charset=utf-8',
- payload_encoding=None,
- resp_code=200):
- self.send_response(resp_code)
- self.send_header('Content-Type', payload_type)
- if payload_encoding:
- self.send_header('Content-Encoding', payload_encoding)
- self.send_header('Content-Length', str(len(payload))) # required for persistent connections
- self.end_headers()
- self.wfile.write(payload)
-
- def gzip_compress(p):
- buf = io.BytesIO()
- with contextlib.closing(gzip.GzipFile(fileobj=buf, mode='wb')) as f:
- f.write(p)
- return buf.getvalue()
-
- if self.path == '/video.html':
- respond()
- elif self.path == '/vid.mp4':
- respond(b'\x00\x00\x00\x00\x20\x66\x74[video]', 'video/mp4')
- elif self.path == '/302':
- if sys.version_info[0] == 3:
- # XXX: Python 3 http server does not allow non-ASCII header values
- self.send_response(404)
- self.end_headers()
- return
-
- new_url = self._test_url('中文.html')
- self.send_response(302)
- self.send_header(b'Location', new_url.encode('utf-8'))
- self.end_headers()
- elif self.path == '/%E4%B8%AD%E6%96%87.html':
- respond()
- elif self.path == '/%c7%9f':
- respond()
- elif self.path == '/redirect_dotsegments':
- self.send_response(301)
- # redirect to /headers but with dot segments before
- self.send_header('Location', '/a/b/./../../headers')
- self.send_header('Content-Length', '0')
- self.end_headers()
- elif self.path.startswith('/redirect_'):
- self._redirect()
- elif self.path.startswith('/method'):
- self._method('GET')
- elif self.path.startswith('/headers'):
- self._headers()
- elif self.path.startswith('/308-to-headers'):
- self.send_response(308)
- self.send_header('Location', '/headers')
- self.send_header('Content-Length', '0')
- self.end_headers()
- elif self.path == '/trailing_garbage':
- payload = b''
- compressed = gzip_compress(payload) + b'trailing garbage'
- respond(compressed, payload_encoding='gzip')
- elif self.path == '/302-non-ascii-redirect':
- new_url = self._test_url('中文.html')
- # actually respond with permanent redirect
- self.send_response(301)
- self.send_header('Location', new_url)
- self.send_header('Content-Length', '0')
- self.end_headers()
- elif self.path == '/content-encoding':
- encodings = self.headers.get('ytdl-encoding', '')
- payload = b''
- for encoding in filter(None, (e.strip() for e in encodings.split(','))):
- if encoding == 'br' and brotli:
- payload = brotli.compress(payload)
- elif encoding == 'gzip':
- payload = gzip_compress(payload)
- elif encoding == 'deflate':
- payload = zlib.compress(payload)
- elif encoding == 'unsupported':
- payload = b'raw'
- break
- else:
- self._status(415)
- return
- respond(payload, payload_encoding=encodings)
-
- else:
- self._status(404)
-
- def send_header(self, keyword, value):
- """
- Forcibly allow HTTP server to send non percent-encoded non-ASCII characters in headers.
- This is against what is defined in RFC 3986: but we need to test that we support this
- since some sites incorrectly do this.
- """
- if keyword.lower() == 'connection':
- return self.super('send_header', keyword, value)
-
- if not hasattr(self, '_headers_buffer'):
- self._headers_buffer = []
-
- self._headers_buffer.append('{0}: {1}\r\n'.format(keyword, value).encode('utf-8'))
-
- def end_headers(self):
- if hasattr(self, '_headers_buffer'):
- self.wfile.write(b''.join(self._headers_buffer))
- self._headers_buffer = []
- self.super('end_headers')
-
-
-class TestHTTP(unittest.TestCase):
- # when does it make sense to check the SSL certificate?
- _check_cert = (
- sys.version_info >= (3, 2)
- or (sys.version_info[0] == 2 and sys.version_info[1:] >= (7, 19)))
-
- def setUp(self):
- # HTTP server
- self.http_httpd = compat_http_server.HTTPServer(
- ('127.0.0.1', 0), HTTPTestRequestHandler)
- self.http_port = http_server_port(self.http_httpd)
-
- self.http_server_thread = threading.Thread(target=self.http_httpd.serve_forever)
- self.http_server_thread.daemon = True
- self.http_server_thread.start()
-
- try:
- from http.server import ThreadingHTTPServer
- except ImportError:
- try:
- from socketserver import ThreadingMixIn
- except ImportError:
- from SocketServer import ThreadingMixIn
-
- class ThreadingHTTPServer(ThreadingMixIn, compat_http_server.HTTPServer):
- pass
-
- # HTTPS server
- certfn = os.path.join(TEST_DIR, 'testcert.pem')
- self.https_httpd = ThreadingHTTPServer(
- ('127.0.0.1', 0), HTTPTestRequestHandler)
- try:
- sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
- sslctx.verify_mode = ssl.CERT_NONE
- sslctx.check_hostname = False
- sslctx.load_cert_chain(certfn, None)
- self.https_httpd.socket = sslctx.wrap_socket(
- self.https_httpd.socket, server_side=True)
- except AttributeError:
- self.https_httpd.socket = ssl.wrap_socket(
- self.https_httpd.socket, certfile=certfn, server_side=True)
-
- self.https_port = http_server_port(self.https_httpd)
- self.https_server_thread = threading.Thread(target=self.https_httpd.serve_forever)
- self.https_server_thread.daemon = True
- self.https_server_thread.start()
-
- def tearDown(self):
-
- def closer(svr):
- def _closer():
- svr.shutdown()
- svr.server_close()
- return _closer
-
- shutdown_thread = threading.Thread(target=closer(self.http_httpd))
- shutdown_thread.start()
- self.http_server_thread.join(2.0)
-
- shutdown_thread = threading.Thread(target=closer(self.https_httpd))
- shutdown_thread.start()
- self.https_server_thread.join(2.0)
-
- def _test_url(self, path, host='127.0.0.1', scheme='http', port=None):
- return '{0}://{1}:{2}/{3}'.format(
- scheme, host,
- port if port is not None
- else self.https_port if scheme == 'https'
- else self.http_port, path)
-
- @unittest.skipUnless(_check_cert, 'No support for certificate check in SSL')
- def test_nocheckcertificate(self):
- with FakeYDL({'logger': FakeLogger()}) as ydl:
- with self.assertRaises(compat_urllib_error.URLError):
- ydl.urlopen(sanitized_Request(self._test_url('headers', scheme='https')))
-
- with FakeYDL({'logger': FakeLogger(), 'nocheckcertificate': True}) as ydl:
- r = ydl.urlopen(sanitized_Request(self._test_url('headers', scheme='https')))
- self.assertEqual(r.getcode(), 200)
- r.close()
-
- def test_percent_encode(self):
- with FakeYDL() as ydl:
- # Unicode characters should be encoded with uppercase percent-encoding
- res = ydl.urlopen(sanitized_Request(self._test_url('中文.html')))
- self.assertEqual(res.getcode(), 200)
- res.close()
- # don't normalize existing percent encodings
- res = ydl.urlopen(sanitized_Request(self._test_url('%c7%9f')))
- self.assertEqual(res.getcode(), 200)
- res.close()
-
- def test_unicode_path_redirection(self):
- with FakeYDL() as ydl:
- r = ydl.urlopen(sanitized_Request(self._test_url('302-non-ascii-redirect')))
- self.assertEqual(r.url, self._test_url('%E4%B8%AD%E6%96%87.html'))
- r.close()
-
- def test_redirect(self):
- with FakeYDL() as ydl:
- def do_req(redirect_status, method, check_no_content=False):
- data = b'testdata' if method in ('POST', 'PUT') else None
- res = ydl.urlopen(sanitized_Request(
- self._test_url('redirect_{0}'.format(redirect_status)),
- method=method, data=data))
- if check_no_content:
- self.assertNotIn('Content-Type', res.headers)
- return res.read().decode('utf-8'), res.headers.get('method', '')
- # A 303 must either use GET or HEAD for subsequent request
- self.assertEqual(do_req(303, 'POST'), ('', 'GET'))
- self.assertEqual(do_req(303, 'HEAD'), ('', 'HEAD'))
-
- self.assertEqual(do_req(303, 'PUT'), ('', 'GET'))
-
- # 301 and 302 turn POST only into a GET, with no Content-Type
- self.assertEqual(do_req(301, 'POST', True), ('', 'GET'))
- self.assertEqual(do_req(301, 'HEAD'), ('', 'HEAD'))
- self.assertEqual(do_req(302, 'POST', True), ('', 'GET'))
- self.assertEqual(do_req(302, 'HEAD'), ('', 'HEAD'))
-
- self.assertEqual(do_req(301, 'PUT'), ('testdata', 'PUT'))
- self.assertEqual(do_req(302, 'PUT'), ('testdata', 'PUT'))
-
- # 307 and 308 should not change method
- for m in ('POST', 'PUT'):
- self.assertEqual(do_req(307, m), ('testdata', m))
- self.assertEqual(do_req(308, m), ('testdata', m))
-
- self.assertEqual(do_req(307, 'HEAD'), ('', 'HEAD'))
- self.assertEqual(do_req(308, 'HEAD'), ('', 'HEAD'))
-
- # These should not redirect and instead raise an HTTPError
- for code in (300, 304, 305, 306):
- with self.assertRaises(compat_urllib_HTTPError):
- do_req(code, 'GET')
-
- # Jython 2.7.1 times out for some reason
- @expectedFailureIf(sys.platform.startswith('java') and sys.version_info < (2, 7, 2))
- def test_content_type(self):
- # https://github.com/yt-dlp/yt-dlp/commit/379a4f161d4ad3e40932dcf5aca6e6fb9715ab28
- with FakeYDL({'nocheckcertificate': True}) as ydl:
- # method should be auto-detected as POST
- r = sanitized_Request(self._test_url('headers', scheme='https'), data=urlencode_postdata({'test': 'test'}))
-
- headers = ydl.urlopen(r).read().decode('utf-8')
- self.assertIn('Content-Type: application/x-www-form-urlencoded', headers)
-
- # test http
- r = sanitized_Request(self._test_url('headers'), data=urlencode_postdata({'test': 'test'}))
- headers = ydl.urlopen(r).read().decode('utf-8')
- self.assertIn('Content-Type: application/x-www-form-urlencoded', headers)
-
- def test_update_req(self):
- req = sanitized_Request('http://example.com')
- assert req.data is None
- assert req.get_method() == 'GET'
- assert not req.has_header('Content-Type')
- # Test that zero-byte payloads will be sent
- req = update_Request(req, data=b'')
- assert req.data == b''
- assert req.get_method() == 'POST'
- # yt-dl expects data to be encoded and Content-Type to be added by sender
- # assert req.get_header('Content-Type') == 'application/x-www-form-urlencoded'
-
- def test_cookiejar(self):
- with FakeYDL() as ydl:
- ydl.cookiejar.set_cookie(compat_http_cookiejar_Cookie(
- 0, 'test', 'ytdl', None, False, '127.0.0.1', True,
- False, '/headers', True, False, None, False, None, None, {}))
- data = ydl.urlopen(sanitized_Request(
- self._test_url('headers'))).read().decode('utf-8')
- self.assertIn('Cookie: test=ytdl', data)
-
- def test_passed_cookie_header(self):
- # We should accept a Cookie header being passed as in normal headers and handle it appropriately.
- with FakeYDL() as ydl:
- # Specified Cookie header should be used
- res = ydl.urlopen(sanitized_Request(
- self._test_url('headers'), headers={'Cookie': 'test=test'})).read().decode('utf-8')
- self.assertIn('Cookie: test=test', res)
-
- # Specified Cookie header should be removed on any redirect
- res = ydl.urlopen(sanitized_Request(
- self._test_url('308-to-headers'), headers={'Cookie': 'test=test'})).read().decode('utf-8')
- self.assertNotIn('Cookie: test=test', res)
-
- # Specified Cookie header should override global cookiejar for that request
- ydl.cookiejar.set_cookie(compat_http_cookiejar_Cookie(
- 0, 'test', 'ytdlp', None, False, '127.0.0.1', True,
- False, '/headers', True, False, None, False, None, None, {}))
- data = ydl.urlopen(sanitized_Request(
- self._test_url('headers'), headers={'Cookie': 'test=test'})).read().decode('utf-8')
- self.assertNotIn('Cookie: test=ytdlp', data)
- self.assertIn('Cookie: test=test', data)
-
- def test_no_compression_compat_header(self):
- with FakeYDL() as ydl:
- data = ydl.urlopen(
- sanitized_Request(
- self._test_url('headers'),
- headers={'Youtubedl-no-compression': True})).read()
- self.assertIn(b'Accept-Encoding: identity', data)
- self.assertNotIn(b'youtubedl-no-compression', data.lower())
-
- def test_gzip_trailing_garbage(self):
- # https://github.com/ytdl-org/youtube-dl/commit/aa3e950764337ef9800c936f4de89b31c00dfcf5
- # https://github.com/ytdl-org/youtube-dl/commit/6f2ec15cee79d35dba065677cad9da7491ec6e6f
- with FakeYDL() as ydl:
- data = ydl.urlopen(sanitized_Request(self._test_url('trailing_garbage'))).read().decode('utf-8')
- self.assertEqual(data, '')
-
- def __test_compression(self, encoding):
- with FakeYDL() as ydl:
- res = ydl.urlopen(
- sanitized_Request(
- self._test_url('content-encoding'),
- headers={'ytdl-encoding': encoding}))
- # decoded encodings are removed: only check for valid decompressed data
- self.assertEqual(res.read(), b'')
-
- @unittest.skipUnless(brotli, 'brotli support is not installed')
- def test_brotli(self):
- self.__test_compression('br')
-
- def test_deflate(self):
- self.__test_compression('deflate')
-
- def test_gzip(self):
- self.__test_compression('gzip')
-
- def test_multiple_encodings(self):
- # https://www.rfc-editor.org/rfc/rfc9110.html#section-8.4
- for pair in ('gzip,deflate', 'deflate, gzip', 'gzip, gzip', 'deflate, deflate'):
- self.__test_compression(pair)
-
- def test_unsupported_encoding(self):
- # it should return the raw content
- with FakeYDL() as ydl:
- res = ydl.urlopen(
- sanitized_Request(
- self._test_url('content-encoding'),
- headers={'ytdl-encoding': 'unsupported'}))
- self.assertEqual(res.headers.get('Content-Encoding'), 'unsupported')
- self.assertEqual(res.read(), b'raw')
-
- def test_remove_dot_segments(self):
- with FakeYDL() as ydl:
- res = ydl.urlopen(sanitized_Request(self._test_url('a/b/./../../headers')))
- self.assertEqual(compat_urllib_parse.urlparse(res.geturl()).path, '/headers')
-
- res = ydl.urlopen(sanitized_Request(self._test_url('redirect_dotsegments')))
- self.assertEqual(compat_urllib_parse.urlparse(res.geturl()).path, '/headers')
-
-
-def _build_proxy_handler(name):
- class HTTPTestRequestHandler(compat_http_server.BaseHTTPRequestHandler):
- proxy_name = name
-
- def log_message(self, format, *args):
- pass
-
- def do_GET(self):
- self.send_response(200)
- self.send_header('Content-Type', 'text/plain; charset=utf-8')
- self.end_headers()
- self.wfile.write('{0}: {1}'.format(self.proxy_name, self.path).encode('utf-8'))
- return HTTPTestRequestHandler
-
-
-class TestProxy(unittest.TestCase):
- def setUp(self):
- self.proxy = compat_http_server.HTTPServer(
- ('127.0.0.1', 0), _build_proxy_handler('normal'))
- self.port = http_server_port(self.proxy)
- self.proxy_thread = threading.Thread(target=self.proxy.serve_forever)
- self.proxy_thread.daemon = True
- self.proxy_thread.start()
-
- self.geo_proxy = compat_http_server.HTTPServer(
- ('127.0.0.1', 0), _build_proxy_handler('geo'))
- self.geo_port = http_server_port(self.geo_proxy)
- self.geo_proxy_thread = threading.Thread(target=self.geo_proxy.serve_forever)
- self.geo_proxy_thread.daemon = True
- self.geo_proxy_thread.start()
-
- def tearDown(self):
-
- def closer(svr):
- def _closer():
- svr.shutdown()
- svr.server_close()
- return _closer
-
- shutdown_thread = threading.Thread(target=closer(self.proxy))
- shutdown_thread.start()
- self.proxy_thread.join(2.0)
-
- shutdown_thread = threading.Thread(target=closer(self.geo_proxy))
- shutdown_thread.start()
- self.geo_proxy_thread.join(2.0)
-
- def _test_proxy(self, host='127.0.0.1', port=None):
- return '{0}:{1}'.format(
- host, port if port is not None else self.port)
-
- def test_proxy(self):
- geo_proxy = self._test_proxy(port=self.geo_port)
- ydl = YoutubeDL({
- 'proxy': self._test_proxy(),
- 'geo_verification_proxy': geo_proxy,
- })
- url = 'http://foo.com/bar'
- response = ydl.urlopen(url).read().decode('utf-8')
- self.assertEqual(response, 'normal: {0}'.format(url))
-
- req = compat_urllib_request.Request(url)
- req.add_header('Ytdl-request-proxy', geo_proxy)
- response = ydl.urlopen(req).read().decode('utf-8')
- self.assertEqual(response, 'geo: {0}'.format(url))
-
- def test_proxy_with_idn(self):
- ydl = YoutubeDL({
- 'proxy': self._test_proxy(),
- })
- url = 'http://中文.tw/'
- response = ydl.urlopen(url).read().decode('utf-8')
- # b'xn--fiq228c' is '中文'.encode('idna')
- self.assertEqual(response, 'normal: http://xn--fiq228c.tw/')
-
-
-class TestFileURL(unittest.TestCase):
- # See https://github.com/ytdl-org/youtube-dl/issues/8227
- def test_file_urls(self):
- tf = tempfile.NamedTemporaryFile(delete=False)
- tf.write(b'foobar')
- tf.close()
- url = compat_urllib_parse.urljoin('file://', pathname2url(tf.name))
- with FakeYDL() as ydl:
- self.assertRaisesRegexp(
- compat_urllib_error.URLError, 'file:// scheme is explicitly disabled in youtube-dl for security reasons', ydl.urlopen, url)
- # not yet implemented
- """
- with FakeYDL({'enable_file_urls': True}) as ydl:
- res = ydl.urlopen(url)
- self.assertEqual(res.read(), b'foobar')
- res.close()
- """
- os.unlink(tf.name)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/test_iqiyi_sdk_interpreter.py b/test/test_iqiyi_sdk_interpreter.py
deleted file mode 100644
index 789059dbe..000000000
--- a/test/test_iqiyi_sdk_interpreter.py
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/env python
-
-from __future__ import unicode_literals
-
-# Allow direct execution
-import os
-import sys
-import unittest
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-from test.helper import FakeYDL
-from youtube_dl.extractor import IqiyiIE
-
-
-class IqiyiIEWithCredentials(IqiyiIE):
- def _get_login_info(self):
- return 'foo', 'bar'
-
-
-class WarningLogger(object):
- def __init__(self):
- self.messages = []
-
- def warning(self, msg):
- self.messages.append(msg)
-
- def debug(self, msg):
- pass
-
- def error(self, msg):
- pass
-
-
-class TestIqiyiSDKInterpreter(unittest.TestCase):
- def test_iqiyi_sdk_interpreter(self):
- '''
- Test the functionality of IqiyiSDKInterpreter by trying to log in
-
- If `sign` is incorrect, /validate call throws an HTTP 556 error
- '''
- logger = WarningLogger()
- ie = IqiyiIEWithCredentials(FakeYDL({'logger': logger}))
- ie._login()
- self.assertTrue('unable to log in:' in logger.messages[0])
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/test_jsinterp.py b/test/test_jsinterp.py
deleted file mode 100644
index 6c34bc896..000000000
--- a/test/test_jsinterp.py
+++ /dev/null
@@ -1,595 +0,0 @@
-#!/usr/bin/env python
-# coding: utf-8
-
-from __future__ import unicode_literals
-
-# Allow direct execution
-import os
-import sys
-import unittest
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-import math
-import re
-
-from youtube_dl.compat import compat_str as str
-from youtube_dl.jsinterp import JS_Undefined, JSInterpreter
-
-NaN = object()
-
-
-class TestJSInterpreter(unittest.TestCase):
- def _test(self, jsi_or_code, expected, func='f', args=()):
- if isinstance(jsi_or_code, str):
- jsi_or_code = JSInterpreter(jsi_or_code)
- got = jsi_or_code.call_function(func, *args)
- if expected is NaN:
- self.assertTrue(math.isnan(got), '{0} is not NaN'.format(got))
- else:
- self.assertEqual(got, expected)
-
- def test_basic(self):
- jsi = JSInterpreter('function f(){;}')
- self.assertEqual(repr(jsi.extract_function('f')), 'F')
- self._test(jsi, None)
-
- self._test('function f(){return 42;}', 42)
- self._test('function f(){42}', None)
- self._test('var f = function(){return 42;}', 42)
-
- def test_add(self):
- self._test('function f(){return 42 + 7;}', 49)
- self._test('function f(){return 42 + undefined;}', NaN)
- self._test('function f(){return 42 + null;}', 42)
- self._test('function f(){return 1 + "";}', '1')
- self._test('function f(){return 42 + "7";}', '427')
- self._test('function f(){return false + true;}', 1)
- self._test('function f(){return "false" + true;}', 'falsetrue')
- self._test('function f(){return '
- '1 + "2" + [3,4] + {k: 56} + null + undefined + Infinity;}',
- '123,4[object Object]nullundefinedInfinity')
-
- def test_sub(self):
- self._test('function f(){return 42 - 7;}', 35)
- self._test('function f(){return 42 - undefined;}', NaN)
- self._test('function f(){return 42 - null;}', 42)
- self._test('function f(){return 42 - "7";}', 35)
- self._test('function f(){return 42 - "spam";}', NaN)
-
- def test_mul(self):
- self._test('function f(){return 42 * 7;}', 294)
- self._test('function f(){return 42 * undefined;}', NaN)
- self._test('function f(){return 42 * null;}', 0)
- self._test('function f(){return 42 * "7";}', 294)
- self._test('function f(){return 42 * "eggs";}', NaN)
-
- def test_div(self):
- jsi = JSInterpreter('function f(a, b){return a / b;}')
- self._test(jsi, NaN, args=(0, 0))
- self._test(jsi, NaN, args=(JS_Undefined, 1))
- self._test(jsi, float('inf'), args=(2, 0))
- self._test(jsi, 0, args=(0, 3))
- self._test(jsi, 6, args=(42, 7))
- self._test(jsi, 0, args=(42, float('inf')))
- self._test(jsi, 6, args=("42", 7))
- self._test(jsi, NaN, args=("spam", 7))
-
- def test_mod(self):
- self._test('function f(){return 42 % 7;}', 0)
- self._test('function f(){return 42 % 0;}', NaN)
- self._test('function f(){return 42 % undefined;}', NaN)
- self._test('function f(){return 42 % "7";}', 0)
- self._test('function f(){return 42 % "beans";}', NaN)
-
- def test_exp(self):
- self._test('function f(){return 42 ** 2;}', 1764)
- self._test('function f(){return 42 ** undefined;}', NaN)
- self._test('function f(){return 42 ** null;}', 1)
- self._test('function f(){return undefined ** 0;}', 1)
- self._test('function f(){return undefined ** 42;}', NaN)
- self._test('function f(){return 42 ** "2";}', 1764)
- self._test('function f(){return 42 ** "spam";}', NaN)
-
- def test_calc(self):
- self._test('function f(a){return 2*a+1;}', 7, args=[3])
-
- def test_empty_return(self):
- self._test('function f(){return; y()}', None)
-
- def test_morespace(self):
- self._test('function f (a) { return 2 * a + 1 ; }', 7, args=[3])
- self._test('function f () { x = 2 ; return x; }', 2)
-
- def test_strange_chars(self):
- self._test('function $_xY1 ($_axY1) { var $_axY2 = $_axY1 + 1; return $_axY2; }',
- 21, args=[20], func='$_xY1')
-
- def test_operators(self):
- self._test('function f(){return 1 << 5;}', 32)
- self._test('function f(){return 2 ** 5}', 32)
- self._test('function f(){return 19 & 21;}', 17)
- self._test('function f(){return 11 >> 2;}', 2)
- self._test('function f(){return []? 2+3: 4;}', 5)
- # equality
- self._test('function f(){return 1 == 1}', True)
- self._test('function f(){return 1 == 1.0}', True)
- self._test('function f(){return 1 == "1"}', True)
- self._test('function f(){return 1 == 2}', False)
- self._test('function f(){return 1 != "1"}', False)
- self._test('function f(){return 1 != 2}', True)
- self._test('function f(){var x = {a: 1}; var y = x; return x == y}', True)
- self._test('function f(){var x = {a: 1}; return x == {a: 1}}', False)
- self._test('function f(){return NaN == NaN}', False)
- self._test('function f(){return null == undefined}', True)
- self._test('function f(){return "spam, eggs" == "spam, eggs"}', True)
- # strict equality
- self._test('function f(){return 1 === 1}', True)
- self._test('function f(){return 1 === 1.0}', True)
- self._test('function f(){return 1 === "1"}', False)
- self._test('function f(){return 1 === 2}', False)
- self._test('function f(){var x = {a: 1}; var y = x; return x === y}', True)
- self._test('function f(){var x = {a: 1}; return x === {a: 1}}', False)
- self._test('function f(){return NaN === NaN}', False)
- self._test('function f(){return null === undefined}', False)
- self._test('function f(){return null === null}', True)
- self._test('function f(){return undefined === undefined}', True)
- self._test('function f(){return "uninterned" === "uninterned"}', True)
- self._test('function f(){return 1 === 1}', True)
- self._test('function f(){return 1 === "1"}', False)
- self._test('function f(){return 1 !== 1}', False)
- self._test('function f(){return 1 !== "1"}', True)
- # expressions
- self._test('function f(){return 0 && 1 || 2;}', 2)
- self._test('function f(){return 0 ?? 42;}', 0)
- self._test('function f(){return "life, the universe and everything" < 42;}', False)
- # https://github.com/ytdl-org/youtube-dl/issues/32815
- self._test('function f(){return 0 - 7 * - 6;}', 42)
-
- def test_array_access(self):
- self._test('function f(){var x = [1,2,3]; x[0] = 4; x[0] = 5; x[2.0] = 7; return x;}', [5, 2, 7])
-
- def test_parens(self):
- self._test('function f(){return (1) + (2) * ((( (( (((((3)))))) )) ));}', 7)
- self._test('function f(){return (1 + 2) * 3;}', 9)
-
- def test_quotes(self):
- self._test(r'function f(){return "a\"\\("}', r'a"\(')
-
- def test_assignments(self):
- self._test('function f(){var x = 20; x = 30 + 1; return x;}', 31)
- self._test('function f(){var x = 20; x += 30 + 1; return x;}', 51)
- self._test('function f(){var x = 20; x -= 30 + 1; return x;}', -11)
-
- def test_comments(self):
- self._test('''
- function f() {
- var x = /* 1 + */ 2;
- var y = /* 30
- * 40 */ 50;
- return x + y;
- }
- ''', 52)
-
- self._test('''
- function f() {
- var x = "/*";
- var y = 1 /* comment */ + 2;
- return y;
- }
- ''', 3)
-
- self._test('''
- function f() {
- var x = ( /* 1 + */ 2 +
- /* 30 * 40 */
- 50);
- return x;
- }
- ''', 52)
-
- def test_precedence(self):
- self._test('''
- function f() {
- var a = [10, 20, 30, 40, 50];
- var b = 6;
- a[0]=a[b%a.length];
- return a;
- }
- ''', [20, 20, 30, 40, 50])
-
- def test_builtins(self):
- self._test('function f() { return NaN }', NaN)
-
- def test_Date(self):
- self._test('function f() { return new Date("Wednesday 31 December 1969 18:01:26 MDT") - 0; }', 86000)
-
- jsi = JSInterpreter('function f(dt) { return new Date(dt) - 0; }')
- # date format m/d/y
- self._test(jsi, 86000, args=['12/31/1969 18:01:26 MDT'])
- # epoch 0
- self._test(jsi, 0, args=['1 January 1970 00:00:00 UTC'])
-
- def test_call(self):
- jsi = JSInterpreter('''
- function x() { return 2; }
- function y(a) { return x() + (a?a:0); }
- function z() { return y(3); }
- ''')
- self._test(jsi, 5, func='z')
- self._test(jsi, 2, func='y')
-
- def test_if(self):
- self._test('''
- function f() {
- let a = 9;
- if (0==0) {a++}
- return a
- }
- ''', 10)
-
- self._test('''
- function f() {
- if (0==0) {return 10}
- }
- ''', 10)
-
- self._test('''
- function f() {
- if (0!=0) {return 1}
- else {return 10}
- }
- ''', 10)
-
- def test_elseif(self):
- self._test('''
- function f() {
- if (0!=0) {return 1}
- else if (1==0) {return 2}
- else {return 10}
- }
- ''', 10)
-
- def test_for_loop(self):
- self._test('function f() { a=0; for (i=0; i-10; i++) {a++} return a }', 10)
-
- def test_while_loop(self):
- self._test('function f() { a=0; while (a<10) {a++} return a }', 10)
-
- def test_switch(self):
- jsi = JSInterpreter('''
- function f(x) { switch(x){
- case 1:x+=1;
- case 2:x+=2;
- case 3:x+=3;break;
- case 4:x+=4;
- default:x=0;
- } return x }
- ''')
- self._test(jsi, 7, args=[1])
- self._test(jsi, 6, args=[3])
- self._test(jsi, 0, args=[5])
-
- def test_switch_default(self):
- jsi = JSInterpreter('''
- function f(x) { switch(x){
- case 2: x+=2;
- default: x-=1;
- case 5:
- case 6: x+=6;
- case 0: break;
- case 1: x+=1;
- } return x }
- ''')
- self._test(jsi, 2, args=[1])
- self._test(jsi, 11, args=[5])
- self._test(jsi, 14, args=[9])
-
- def test_try(self):
- self._test('function f() { try{return 10} catch(e){return 5} }', 10)
-
- def test_catch(self):
- self._test('function f() { try{throw 10} catch(e){return 5} }', 5)
-
- def test_finally(self):
- self._test('function f() { try{throw 10} finally {return 42} }', 42)
- self._test('function f() { try{throw 10} catch(e){return 5} finally {return 42} }', 42)
-
- def test_nested_try(self):
- self._test('''
- function f() {try {
- try{throw 10} finally {throw 42}
- } catch(e){return 5} }
- ''', 5)
-
- def test_for_loop_continue(self):
- self._test('function f() { a=0; for (i=0; i-10; i++) { continue; a++ } return a }', 0)
-
- def test_for_loop_break(self):
- self._test('function f() { a=0; for (i=0; i-10; i++) { break; a++ } return a }', 0)
-
- def test_for_loop_try(self):
- self._test('''
- function f() {
- for (i=0; i-10; i++) { try { if (i == 5) throw i} catch {return 10} finally {break} };
- return 42 }
- ''', 42)
-
- def test_literal_list(self):
- self._test('function f() { return [1, 2, "asdf", [5, 6, 7]][3] }', [5, 6, 7])
-
- def test_comma(self):
- self._test('function f() { a=5; a -= 1, a+=3; return a }', 7)
- self._test('function f() { a=5; return (a -= 1, a+=3, a); }', 7)
- self._test('function f() { return (l=[0,1,2,3], function(a, b){return a+b})((l[1], l[2]), l[3]) }', 5)
-
- def test_void(self):
- self._test('function f() { return void 42; }', JS_Undefined)
-
- def test_typeof(self):
- self._test('function f() { return typeof undefined; }', 'undefined')
- self._test('function f() { return typeof NaN; }', 'number')
- self._test('function f() { return typeof Infinity; }', 'number')
- self._test('function f() { return typeof true; }', 'boolean')
- self._test('function f() { return typeof null; }', 'object')
- self._test('function f() { return typeof "a string"; }', 'string')
- self._test('function f() { return typeof 42; }', 'number')
- self._test('function f() { return typeof 42.42; }', 'number')
- self._test('function f() { var g = function(){}; return typeof g; }', 'function')
- self._test('function f() { return typeof {key: "value"}; }', 'object')
- # not yet implemented: Symbol, BigInt
-
- def test_return_function(self):
- jsi = JSInterpreter('''
- function x() { return [1, function(){return 1}][1] }
- ''')
- self.assertEqual(jsi.call_function('x')([]), 1)
-
- def test_null(self):
- self._test('function f() { return null; }', None)
- self._test('function f() { return [null > 0, null < 0, null == 0, null === 0]; }',
- [False, False, False, False])
- self._test('function f() { return [null >= 0, null <= 0]; }', [True, True])
-
- def test_undefined(self):
- self._test('function f() { return undefined === undefined; }', True)
- self._test('function f() { return undefined; }', JS_Undefined)
- self._test('function f() { return undefined ?? 42; }', 42)
- self._test('function f() { let v; return v; }', JS_Undefined)
- self._test('function f() { let v; return v**0; }', 1)
- self._test('function f() { let v; return [v>42, v<=42, v&&42, 42&&v]; }',
- [False, False, JS_Undefined, JS_Undefined])
-
- self._test('''
- function f() { return [
- undefined === undefined,
- undefined == undefined,
- undefined == null
- ]; }
- ''', [True] * 3)
- self._test('''
- function f() { return [
- undefined < undefined,
- undefined > undefined,
- undefined === 0,
- undefined == 0,
- undefined < 0,
- undefined > 0,
- undefined >= 0,
- undefined <= 0,
- undefined > null,
- undefined < null,
- undefined === null
- ]; }
- ''', [False] * 11)
-
- jsi = JSInterpreter('''
- function x() { let v; return [42+v, v+42, v**42, 42**v, 0**v]; }
- ''')
- for y in jsi.call_function('x'):
- self.assertTrue(math.isnan(y))
-
- def test_object(self):
- self._test('function f() { return {}; }', {})
- self._test('function f() { let a = {m1: 42, m2: 0 }; return [a["m1"], a.m2]; }', [42, 0])
- self._test('function f() { let a; return a?.qq; }', JS_Undefined)
- self._test('function f() { let a = {m1: 42, m2: 0 }; return a?.qq; }', JS_Undefined)
-
- def test_indexing(self):
- self._test('function f() { return [1, 2, 3, 4][3]}', 4)
- self._test('function f() { return [1, [2, [3, [4]]]][1][1][1][0]}', 4)
- self._test('function f() { var o = {1: 2, 3: 4}; return o[3]}', 4)
- self._test('function f() { var o = {1: 2, 3: 4}; return o["3"]}', 4)
- self._test('function f() { return [1, [2, {3: [4]}]][1][1]["3"][0]}', 4)
- self._test('function f() { return [1, 2, 3, 4].length}', 4)
- self._test('function f() { var o = {1: 2, 3: 4}; return o.length}', JS_Undefined)
- self._test('function f() { var o = {1: 2, 3: 4}; o["length"] = 42; return o.length}', 42)
-
- def test_regex(self):
- self._test('function f() { let a=/,,[/,913,/](,)}/; }', None)
-
- jsi = JSInterpreter('''
- function x() { let a=/,,[/,913,/](,)}/; "".replace(a, ""); return a; }
- ''')
- attrs = set(('findall', 'finditer', 'match', 'scanner', 'search',
- 'split', 'sub', 'subn'))
- if sys.version_info >= (2, 7):
- # documented for 2.6 but may not be found
- attrs.update(('flags', 'groupindex', 'groups', 'pattern'))
- self.assertSetEqual(set(dir(jsi.call_function('x'))) & attrs, attrs)
-
- jsi = JSInterpreter('''
- function x() { let a=/,,[/,913,/](,)}/i; return a; }
- ''')
- self.assertEqual(jsi.call_function('x').flags & ~re.U, re.I)
-
- jsi = JSInterpreter(r'function f() { let a=/,][}",],()}(\[)/; return a; }')
- self.assertEqual(jsi.call_function('f').pattern, r',][}",],()}(\[)')
-
- jsi = JSInterpreter(r'function f() { let a=[/[)\\]/]; return a[0]; }')
- self.assertEqual(jsi.call_function('f').pattern, r'[)\\]')
-
- def test_replace(self):
- self._test('function f() { let a="data-name".replace("data-", ""); return a }',
- 'name')
- self._test('function f() { let a="data-name".replace(new RegExp("^.+-"), ""); return a; }',
- 'name')
- self._test('function f() { let a="data-name".replace(/^.+-/, ""); return a; }',
- 'name')
- self._test('function f() { let a="data-name".replace(/a/g, "o"); return a; }',
- 'doto-nome')
- self._test('function f() { let a="data-name".replaceAll("a", "o"); return a; }',
- 'doto-nome')
-
- def test_char_code_at(self):
- jsi = JSInterpreter('function f(i){return "test".charCodeAt(i)}')
- self._test(jsi, 116, args=[0])
- self._test(jsi, 101, args=[1])
- self._test(jsi, 115, args=[2])
- self._test(jsi, 116, args=[3])
- self._test(jsi, None, args=[4])
- self._test(jsi, 116, args=['not_a_number'])
-
- def test_bitwise_operators_overflow(self):
- self._test('function f(){return -524999584 << 5}', 379882496)
- self._test('function f(){return 1236566549 << 5}', 915423904)
-
- def test_bitwise_operators_typecast(self):
- # madness
- self._test('function f(){return null << 5}', 0)
- self._test('function f(){return undefined >> 5}', 0)
- self._test('function f(){return 42 << NaN}', 42)
- self._test('function f(){return 42 << Infinity}', 42)
- self._test('function f(){return 0.0 << null}', 0)
- self._test('function f(){return NaN << 42}', 0)
- self._test('function f(){return "21.9" << 1}', 42)
- self._test('function f(){return 21 << 4294967297}', 42)
-
- def test_negative(self):
- self._test('function f(){return 2 * -2.0 ;}', -4)
- self._test('function f(){return 2 - - -2 ;}', 0)
- self._test('function f(){return 2 - - - -2 ;}', 4)
- self._test('function f(){return 2 - + + - -2;}', 0)
- self._test('function f(){return 2 + - + - -2;}', 0)
-
- def test_32066(self):
- self._test(
- "function f(){return Math.pow(3, 5) + new Date('1970-01-01T08:01:42.000+08:00') / 1000 * -239 - -24205;}",
- 70)
-
- @unittest.skip('Not yet working')
- def test_packed(self):
- self._test(
- '''function f(p,a,c,k,e,d){while(c--)if(k[c])p=p.replace(new RegExp('\\b'+c.toString(a)+'\\b','g'),k[c]);return p}''',
- '''h 7=g("1j");7.7h({7g:[{33:"w://7f-7e-7d-7c.v.7b/7a/79/78/77/76.74?t=73&s=2s&e=72&f=2t&71=70.0.0.1&6z=6y&6x=6w"}],6v:"w://32.v.u/6u.31",16:"r%",15:"r%",6t:"6s",6r:"",6q:"l",6p:"l",6o:"6n",6m:\'6l\',6k:"6j",9:[{33:"/2u?b=6i&n=50&6h=w://32.v.u/6g.31",6f:"6e"}],1y:{6d:1,6c:\'#6b\',6a:\'#69\',68:"67",66:30,65:r,},"64":{63:"%62 2m%m%61%5z%5y%5x.u%5w%5v%5u.2y%22 2k%m%1o%22 5t%m%1o%22 5s%m%1o%22 2j%m%5r%22 16%m%5q%22 15%m%5p%22 5o%2z%5n%5m%2z",5l:"w://v.u/d/1k/5k.2y",5j:[]},\'5i\':{"5h":"5g"},5f:"5e",5d:"w://v.u",5c:{},5b:l,1x:[0.25,0.50,0.75,1,1.25,1.5,2]});h 1m,1n,5a;h 59=0,58=0;h 7=g("1j");h 2x=0,57=0,56=0;$.55({54:{\'53-52\':\'2i-51\'}});7.j(\'4z\',6(x){c(5>0&&x.1l>=5&&1n!=1){1n=1;$(\'q.4y\').4x(\'4w\')}});7.j(\'13\',6(x){2x=x.1l});7.j(\'2g\',6(x){2w(x)});7.j(\'4v\',6(){$(\'q.2v\').4u()});6 2w(x){$(\'q.2v\').4t();c(1m)19;1m=1;17=0;c(4s.4r===l){17=1}$.4q(\'/2u?b=4p&2l=1k&4o=2t-4n-4m-2s-4l&4k=&4j=&4i=&17=\'+17,6(2r){$(\'#4h\').4g(2r)});$(\'.3-8-4f-4e:4d("4c")\').2h(6(e){2q();g().4b(0);g().4a(l)});6 2q(){h $14=$("").2p({1l:"49",16:"r%",15:"r%",48:0,2n:0,2o:47,46:"45(10%, 10%, 10%, 0.4)","44-43":"42"});$("<41 />").2p({16:"60%",15:"60%",2o:40,"3z-2n":"3y"}).3x({\'2m\':\'/?b=3w&2l=1k\',\'2k\':\'0\',\'2j\':\'2i\'}).2f($14);$14.2h(6(){$(3v).3u();g().2g()});$14.2f($(\'#1j\'))}g().13(0);}6 3t(){h 9=7.1b(2e);2d.2c(9);c(9.n>1){1r(i=0;i<9.n;i++){c(9[i].1a==2e){2d.2c(\'!!=\'+i);7.1p(i)}}}}7.j(\'3s\',6(){g().1h("/2a/3r.29","3q 10 28",6(){g().13(g().27()+10)},"2b");$("q[26=2b]").23().21(\'.3-20-1z\');g().1h("/2a/3p.29","3o 10 28",6(){h 12=g().27()-10;c(12<0)12=0;g().13(12)},"24");$("q[26=24]").23().21(\'.3-20-1z\');});6 1i(){}7.j(\'3n\',6(){1i()});7.j(\'3m\',6(){1i()});7.j("k",6(y){h 9=7.1b();c(9.n<2)19;$(\'.3-8-3l-3k\').3j(6(){$(\'#3-8-a-k\').1e(\'3-8-a-z\');$(\'.3-a-k\').p(\'o-1f\',\'11\')});7.1h("/3i/3h.3g","3f 3e",6(){$(\'.3-1w\').3d(\'3-8-1v\');$(\'.3-8-1y, .3-8-1x\').p(\'o-1g\',\'11\');c($(\'.3-1w\').3c(\'3-8-1v\')){$(\'.3-a-k\').p(\'o-1g\',\'l\');$(\'.3-a-k\').p(\'o-1f\',\'l\');$(\'.3-8-a\').1e(\'3-8-a-z\');$(\'.3-8-a:1u\').3b(\'3-8-a-z\')}3a{$(\'.3-a-k\').p(\'o-1g\',\'11\');$(\'.3-a-k\').p(\'o-1f\',\'11\');$(\'.3-8-a:1u\').1e(\'3-8-a-z\')}},"39");7.j("38",6(y){1d.37(\'1c\',y.9[y.36].1a)});c(1d.1t(\'1c\')){35("1s(1d.1t(\'1c\'));",34)}});h 18;6 1s(1q){h 9=7.1b();c(9.n>1){1r(i=0;i<9.n;i++){c(9[i].1a==1q){c(i==18){19}18=i;7.1p(i)}}}}',36,270,'|||jw|||function|player|settings|tracks|submenu||if||||jwplayer|var||on|audioTracks|true|3D|length|aria|attr|div|100|||sx|filemoon|https||event|active||false|tt|seek|dd|height|width|adb|current_audio|return|name|getAudioTracks|default_audio|localStorage|removeClass|expanded|checked|addButton|callMeMaybe|vplayer|0fxcyc2ajhp1|position|vvplay|vvad|220|setCurrentAudioTrack|audio_name|for|audio_set|getItem|last|open|controls|playbackRates|captions|rewind|icon|insertAfter||detach|ff00||button|getPosition|sec|png|player8|ff11|log|console|track_name|appendTo|play|click|no|scrolling|frameborder|file_code|src|top|zIndex|css|showCCform|data|1662367683|383371|dl|video_ad|doPlay|prevt|mp4|3E||jpg|thumbs|file|300|setTimeout|currentTrack|setItem|audioTrackChanged|dualSound|else|addClass|hasClass|toggleClass|Track|Audio|svg|dualy|images|mousedown|buttons|topbar|playAttemptFailed|beforePlay|Rewind|fr|Forward|ff|ready|set_audio_track|remove|this|upload_srt|prop|50px|margin|1000001|iframe|center|align|text|rgba|background|1000000|left|absolute|pause|setCurrentCaptions|Upload|contains|item|content|html|fviews|referer|prem|embed|3e57249ef633e0d03bf76ceb8d8a4b65|216|83|hash|view|get|TokenZir|window|hide|show|complete|slow|fadeIn|video_ad_fadein|time||cache|Cache|Content|headers|ajaxSetup|v2done|tott|vastdone2|vastdone1|vvbefore|playbackRateControls|cast|aboutlink|FileMoon|abouttext|UHD|1870|qualityLabels|sites|GNOME_POWER|link|2Fiframe|3C|allowfullscreen|22360|22640|22no|marginheight|marginwidth|2FGNOME_POWER|2F0fxcyc2ajhp1|2Fe|2Ffilemoon|2F|3A||22https|3Ciframe|code|sharing|fontOpacity|backgroundOpacity|Tahoma|fontFamily|303030|backgroundColor|FFFFFF|color|userFontScale|thumbnails|kind|0fxcyc2ajhp10000|url|get_slides|start|startparam|none|preload|html5|primary|hlshtml|androidhls|duration|uniform|stretching|0fxcyc2ajhp1_xt|image|2048|sp|6871|asn|127|srv|43200|_g3XlBcu2lmD9oDexD2NLWSmah2Nu3XcDrl93m9PwXY|m3u8||master|0fxcyc2ajhp1_x|00076|01|hls2|to|s01|delivery|storage|moon|sources|setup'''.split('|'))
-
- def test_join(self):
- test_input = list('test')
- tests = [
- 'function f(a, b){return a.join(b)}',
- 'function f(a, b){return Array.prototype.join.call(a, b)}',
- 'function f(a, b){return Array.prototype.join.apply(a, [b])}',
- ]
- for test in tests:
- jsi = JSInterpreter(test)
- self._test(jsi, 'test', args=[test_input, ''])
- self._test(jsi, 't-e-s-t', args=[test_input, '-'])
- self._test(jsi, '', args=[[], '-'])
-
- self._test('function f(){return '
- '[1, 1.0, "abc", {a: 1}, null, undefined, Infinity, NaN].join()}',
- '1,1,abc,[object Object],,,Infinity,NaN')
- self._test('function f(){return '
- '[1, 1.0, "abc", {a: 1}, null, undefined, Infinity, NaN].join("~")}',
- '1~1~abc~[object Object]~~~Infinity~NaN')
-
- def test_split(self):
- test_result = list('test')
- tests = [
- 'function f(a, b){return a.split(b)}',
- 'function f(a, b){return String.prototype.split.call(a, b)}',
- 'function f(a, b){return String.prototype.split.apply(a, [b])}',
- ]
- for test in tests:
- jsi = JSInterpreter(test)
- self._test(jsi, test_result, args=['test', ''])
- self._test(jsi, test_result, args=['t-e-s-t', '-'])
- self._test(jsi, [''], args=['', '-'])
- self._test(jsi, [], args=['', ''])
- # RegExp split
- self._test('function f(){return "test".split(/(?:)/)}',
- ['t', 'e', 's', 't'])
- self._test('function f(){return "t-e-s-t".split(/[es-]+/)}',
- ['t', 't'])
- # from MDN: surrogate pairs aren't handled: case 1 fails
- # self._test('function f(){return "😄😄".split(/(?:)/)}',
- # ['\ud83d', '\ude04', '\ud83d', '\ude04'])
- # case 2 beats Py3.2: it gets the case 1 result
- if sys.version_info >= (2, 6) and not ((3, 0) <= sys.version_info < (3, 3)):
- self._test('function f(){return "😄😄".split(/(?:)/u)}',
- ['😄', '😄'])
-
- def test_slice(self):
- self._test('function f(){return [0, 1, 2, 3, 4, 5, 6, 7, 8].slice()}', [0, 1, 2, 3, 4, 5, 6, 7, 8])
- self._test('function f(){return [0, 1, 2, 3, 4, 5, 6, 7, 8].slice(0)}', [0, 1, 2, 3, 4, 5, 6, 7, 8])
- self._test('function f(){return [0, 1, 2, 3, 4, 5, 6, 7, 8].slice(5)}', [5, 6, 7, 8])
- self._test('function f(){return [0, 1, 2, 3, 4, 5, 6, 7, 8].slice(99)}', [])
- self._test('function f(){return [0, 1, 2, 3, 4, 5, 6, 7, 8].slice(-2)}', [7, 8])
- self._test('function f(){return [0, 1, 2, 3, 4, 5, 6, 7, 8].slice(-99)}', [0, 1, 2, 3, 4, 5, 6, 7, 8])
- self._test('function f(){return [0, 1, 2, 3, 4, 5, 6, 7, 8].slice(0, 0)}', [])
- self._test('function f(){return [0, 1, 2, 3, 4, 5, 6, 7, 8].slice(1, 0)}', [])
- self._test('function f(){return [0, 1, 2, 3, 4, 5, 6, 7, 8].slice(0, 1)}', [0])
- self._test('function f(){return [0, 1, 2, 3, 4, 5, 6, 7, 8].slice(3, 6)}', [3, 4, 5])
- self._test('function f(){return [0, 1, 2, 3, 4, 5, 6, 7, 8].slice(1, -1)}', [1, 2, 3, 4, 5, 6, 7])
- self._test('function f(){return [0, 1, 2, 3, 4, 5, 6, 7, 8].slice(-1, 1)}', [])
- self._test('function f(){return [0, 1, 2, 3, 4, 5, 6, 7, 8].slice(-3, -1)}', [6, 7])
- self._test('function f(){return "012345678".slice()}', '012345678')
- self._test('function f(){return "012345678".slice(0)}', '012345678')
- self._test('function f(){return "012345678".slice(5)}', '5678')
- self._test('function f(){return "012345678".slice(99)}', '')
- self._test('function f(){return "012345678".slice(-2)}', '78')
- self._test('function f(){return "012345678".slice(-99)}', '012345678')
- self._test('function f(){return "012345678".slice(0, 0)}', '')
- self._test('function f(){return "012345678".slice(1, 0)}', '')
- self._test('function f(){return "012345678".slice(0, 1)}', '0')
- self._test('function f(){return "012345678".slice(3, 6)}', '345')
- self._test('function f(){return "012345678".slice(1, -1)}', '1234567')
- self._test('function f(){return "012345678".slice(-1, 1)}', '')
- self._test('function f(){return "012345678".slice(-3, -1)}', '67')
-
- def test_pop(self):
- # pop
- self._test('function f(){var a = [0, 1, 2, 3, 4, 5, 6, 7, 8]; return [a.pop(), a]}',
- [8, [0, 1, 2, 3, 4, 5, 6, 7]])
- self._test('function f(){return [].pop()}', JS_Undefined)
- # push
- self._test('function f(){var a = [0, 1, 2]; return [a.push(3, 4), a]}',
- [5, [0, 1, 2, 3, 4]])
- self._test('function f(){var a = [0, 1, 2]; return [a.push(), a]}',
- [3, [0, 1, 2]])
-
- def test_shift(self):
- # shift
- self._test('function f(){var a = [0, 1, 2, 3, 4, 5, 6, 7, 8]; return [a.shift(), a]}',
- [0, [1, 2, 3, 4, 5, 6, 7, 8]])
- self._test('function f(){return [].shift()}', JS_Undefined)
- # unshift
- self._test('function f(){var a = [0, 1, 2]; return [a.unshift(3, 4), a]}',
- [5, [3, 4, 0, 1, 2]])
- self._test('function f(){var a = [0, 1, 2]; return [a.unshift(), a]}',
- [3, [0, 1, 2]])
-
- def test_forEach(self):
- self._test('function f(){var ret = []; var l = [4, 2]; '
- 'var log = function(e,i,a){ret.push([e,i,a]);}; '
- 'l.forEach(log); '
- 'return [ret.length, ret[0][0], ret[1][1], ret[0][2]]}',
- [2, 4, 1, [4, 2]])
- self._test('function f(){var ret = []; var l = [4, 2]; '
- 'var log = function(e,i,a){this.push([e,i,a]);}; '
- 'l.forEach(log, ret); '
- 'return [ret.length, ret[0][0], ret[1][1], ret[0][2]]}',
- [2, 4, 1, [4, 2]])
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/test_netrc.py b/test/test_netrc.py
deleted file mode 100644
index 7cf3a6a2e..000000000
--- a/test/test_netrc.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# coding: utf-8
-from __future__ import unicode_literals
-
-import os
-import sys
-import unittest
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-
-from youtube_dl.extractor import (
- gen_extractors,
-)
-
-
-class TestNetRc(unittest.TestCase):
- def test_netrc_present(self):
- for ie in gen_extractors():
- if not hasattr(ie, '_login'):
- continue
- self.assertTrue(
- hasattr(ie, '_NETRC_MACHINE'),
- 'Extractor %s supports login, but is missing a _NETRC_MACHINE property' % ie.IE_NAME)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/test_options.py b/test/test_options.py
deleted file mode 100644
index 3a25a6ba3..000000000
--- a/test/test_options.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# coding: utf-8
-
-from __future__ import unicode_literals
-
-# Allow direct execution
-import os
-import sys
-import unittest
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-from youtube_dl.options import _hide_login_info
-
-
-class TestOptions(unittest.TestCase):
- def test_hide_login_info(self):
- self.assertEqual(_hide_login_info(['-u', 'foo', '-p', 'bar']),
- ['-u', 'PRIVATE', '-p', 'PRIVATE'])
- self.assertEqual(_hide_login_info(['-u']), ['-u'])
- self.assertEqual(_hide_login_info(['-u', 'foo', '-u', 'bar']),
- ['-u', 'PRIVATE', '-u', 'PRIVATE'])
- self.assertEqual(_hide_login_info(['--username=foo']),
- ['--username=PRIVATE'])
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/test_postprocessors.py b/test/test_postprocessors.py
deleted file mode 100644
index 4209d1d9a..000000000
--- a/test/test_postprocessors.py
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/usr/bin/env python
-
-from __future__ import unicode_literals
-
-# Allow direct execution
-import os
-import sys
-import unittest
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-from youtube_dl.postprocessor import MetadataFromTitlePP
-
-
-class TestMetadataFromTitle(unittest.TestCase):
- def test_format_to_regex(self):
- pp = MetadataFromTitlePP(None, '%(title)s - %(artist)s')
- self.assertEqual(pp._titleregex, r'(?P.+)\ \-\ (?P.+)')
diff --git a/test/test_socks.py b/test/test_socks.py
deleted file mode 100644
index 1e68eb0da..000000000
--- a/test/test_socks.py
+++ /dev/null
@@ -1,118 +0,0 @@
-#!/usr/bin/env python
-# coding: utf-8
-from __future__ import unicode_literals
-
-# Allow direct execution
-import os
-import sys
-import unittest
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-import random
-import subprocess
-
-from test.helper import (
- FakeYDL,
- get_params,
-)
-from youtube_dl.compat import (
- compat_str,
- compat_urllib_request,
-)
-
-
-class TestMultipleSocks(unittest.TestCase):
- @staticmethod
- def _check_params(attrs):
- params = get_params()
- for attr in attrs:
- if attr not in params:
- print('Missing %s. Skipping.' % attr)
- return
- return params
-
- def test_proxy_http(self):
- params = self._check_params(['primary_proxy', 'primary_server_ip'])
- if params is None:
- return
- ydl = FakeYDL({
- 'proxy': params['primary_proxy']
- })
- self.assertEqual(
- ydl.urlopen('http://yt-dl.org/ip').read().decode('utf-8'),
- params['primary_server_ip'])
-
- def test_proxy_https(self):
- params = self._check_params(['primary_proxy', 'primary_server_ip'])
- if params is None:
- return
- ydl = FakeYDL({
- 'proxy': params['primary_proxy']
- })
- self.assertEqual(
- ydl.urlopen('https://yt-dl.org/ip').read().decode('utf-8'),
- params['primary_server_ip'])
-
- def test_secondary_proxy_http(self):
- params = self._check_params(['secondary_proxy', 'secondary_server_ip'])
- if params is None:
- return
- ydl = FakeYDL()
- req = compat_urllib_request.Request('http://yt-dl.org/ip')
- req.add_header('Ytdl-request-proxy', params['secondary_proxy'])
- self.assertEqual(
- ydl.urlopen(req).read().decode('utf-8'),
- params['secondary_server_ip'])
-
- def test_secondary_proxy_https(self):
- params = self._check_params(['secondary_proxy', 'secondary_server_ip'])
- if params is None:
- return
- ydl = FakeYDL()
- req = compat_urllib_request.Request('https://yt-dl.org/ip')
- req.add_header('Ytdl-request-proxy', params['secondary_proxy'])
- self.assertEqual(
- ydl.urlopen(req).read().decode('utf-8'),
- params['secondary_server_ip'])
-
-
-class TestSocks(unittest.TestCase):
- _SKIP_SOCKS_TEST = True
-
- def setUp(self):
- if self._SKIP_SOCKS_TEST:
- return
-
- self.port = random.randint(20000, 30000)
- self.server_process = subprocess.Popen([
- 'srelay', '-f', '-i', '127.0.0.1:%d' % self.port],
- stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-
- def tearDown(self):
- if self._SKIP_SOCKS_TEST:
- return
-
- self.server_process.terminate()
- self.server_process.communicate()
-
- def _get_ip(self, protocol):
- if self._SKIP_SOCKS_TEST:
- return '127.0.0.1'
-
- ydl = FakeYDL({
- 'proxy': '%s://127.0.0.1:%d' % (protocol, self.port),
- })
- return ydl.urlopen('http://yt-dl.org/ip').read().decode('utf-8')
-
- def test_socks4(self):
- self.assertTrue(isinstance(self._get_ip('socks4'), compat_str))
-
- def test_socks4a(self):
- self.assertTrue(isinstance(self._get_ip('socks4a'), compat_str))
-
- def test_socks5(self):
- self.assertTrue(isinstance(self._get_ip('socks5'), compat_str))
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/test_subtitles.py b/test/test_subtitles.py
deleted file mode 100644
index e005c78fc..000000000
--- a/test/test_subtitles.py
+++ /dev/null
@@ -1,399 +0,0 @@
-#!/usr/bin/env python
-from __future__ import unicode_literals
-
-# Allow direct execution
-import os
-import sys
-import unittest
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-from test.helper import FakeYDL, md5
-
-
-from youtube_dl.extractor import (
- YoutubeIE,
- DailymotionIE,
- TEDIE,
- VimeoIE,
- WallaIE,
- CeskaTelevizeIE,
- LyndaIE,
- NPOIE,
- ComedyCentralIE,
- NRKTVIE,
- RaiPlayIE,
- VikiIE,
- ThePlatformIE,
- ThePlatformFeedIE,
- RTVEALaCartaIE,
- DemocracynowIE,
-)
-
-
-class BaseTestSubtitles(unittest.TestCase):
- url = None
- IE = None
-
- def setUp(self):
- self.DL = FakeYDL()
- self.ie = self.IE()
- self.DL.add_info_extractor(self.ie)
- if not self.IE.working():
- print('Skipping: %s marked as not _WORKING' % self.IE.ie_key())
- self.skipTest('IE marked as not _WORKING')
-
- def getInfoDict(self):
- info_dict = self.DL.extract_info(self.url, download=False)
- return info_dict
-
- def getSubtitles(self):
- info_dict = self.getInfoDict()
- subtitles = info_dict['requested_subtitles']
- if not subtitles:
- return subtitles
- for sub_info in subtitles.values():
- if sub_info.get('data') is None:
- uf = self.DL.urlopen(sub_info['url'])
- sub_info['data'] = uf.read().decode('utf-8')
- return dict((l, sub_info['data']) for l, sub_info in subtitles.items())
-
-
-class TestYoutubeSubtitles(BaseTestSubtitles):
- # Available subtitles for QRS8MkLhQmM:
- # Language formats
- # ru vtt, ttml, srv3, srv2, srv1, json3
- # fr vtt, ttml, srv3, srv2, srv1, json3
- # en vtt, ttml, srv3, srv2, srv1, json3
- # nl vtt, ttml, srv3, srv2, srv1, json3
- # de vtt, ttml, srv3, srv2, srv1, json3
- # ko vtt, ttml, srv3, srv2, srv1, json3
- # it vtt, ttml, srv3, srv2, srv1, json3
- # zh-Hant vtt, ttml, srv3, srv2, srv1, json3
- # hi vtt, ttml, srv3, srv2, srv1, json3
- # pt-BR vtt, ttml, srv3, srv2, srv1, json3
- # es-MX vtt, ttml, srv3, srv2, srv1, json3
- # ja vtt, ttml, srv3, srv2, srv1, json3
- # pl vtt, ttml, srv3, srv2, srv1, json3
- url = 'QRS8MkLhQmM'
- IE = YoutubeIE
-
- def test_youtube_allsubtitles(self):
- self.DL.params['writesubtitles'] = True
- self.DL.params['allsubtitles'] = True
- subtitles = self.getSubtitles()
- self.assertEqual(len(subtitles.keys()), 13)
- self.assertEqual(md5(subtitles['en']), 'ae1bd34126571a77aabd4d276b28044d')
- self.assertEqual(md5(subtitles['it']), '0e0b667ba68411d88fd1c5f4f4eab2f9')
- for lang in ['fr', 'de']:
- self.assertTrue(subtitles.get(lang) is not None, 'Subtitles for \'%s\' not extracted' % lang)
-
- def _test_subtitles_format(self, fmt, md5_hash, lang='en'):
- self.DL.params['writesubtitles'] = True
- self.DL.params['subtitlesformat'] = fmt
- subtitles = self.getSubtitles()
- self.assertEqual(md5(subtitles[lang]), md5_hash)
-
- def test_youtube_subtitles_ttml_format(self):
- self._test_subtitles_format('ttml', 'c97ddf1217390906fa9fbd34901f3da2')
-
- def test_youtube_subtitles_vtt_format(self):
- self._test_subtitles_format('vtt', 'ae1bd34126571a77aabd4d276b28044d')
-
- def test_youtube_subtitles_json3_format(self):
- self._test_subtitles_format('json3', '688dd1ce0981683867e7fe6fde2a224b')
-
- def _test_automatic_captions(self, url, lang):
- self.url = url
- self.DL.params['writeautomaticsub'] = True
- self.DL.params['subtitleslangs'] = [lang]
- subtitles = self.getSubtitles()
- self.assertTrue(subtitles[lang] is not None)
-
- def test_youtube_automatic_captions(self):
- # Available automatic captions for 8YoUxe5ncPo:
- # Language formats (all in vtt, ttml, srv3, srv2, srv1, json3)
- # gu, zh-Hans, zh-Hant, gd, ga, gl, lb, la, lo, tt, tr,
- # lv, lt, tk, th, tg, te, fil, haw, yi, ceb, yo, de, da,
- # el, eo, en, eu, et, es, ru, rw, ro, bn, be, bg, uk, jv,
- # bs, ja, or, xh, co, ca, cy, cs, ps, pt, pa, vi, pl, hy,
- # hr, ht, hu, hmn, hi, ha, mg, uz, ml, mn, mi, mk, ur,
- # mt, ms, mr, ug, ta, my, af, sw, is, am,
- # *it*, iw, sv, ar,
- # su, zu, az, id, ig, nl, no, ne, ny, fr, ku, fy, fa, fi,
- # ka, kk, sr, sq, ko, kn, km, st, sk, si, so, sn, sm, sl,
- # ky, sd
- # ...
- self._test_automatic_captions('8YoUxe5ncPo', 'it')
-
- @unittest.skip('ASR subs all in all supported langs now')
- def test_youtube_translated_subtitles(self):
- # This video has a subtitles track, which can be translated (#4555)
- self._test_automatic_captions('Ky9eprVWzlI', 'it')
-
- def test_youtube_nosubtitles(self):
- self.DL.expect_warning('video doesn\'t have subtitles')
- # Available automatic captions for 8YoUxe5ncPo:
- # ...
- # 8YoUxe5ncPo has no subtitles
- self.url = '8YoUxe5ncPo'
- self.DL.params['writesubtitles'] = True
- self.DL.params['allsubtitles'] = True
- subtitles = self.getSubtitles()
- self.assertFalse(subtitles)
-
-
-class TestDailymotionSubtitles(BaseTestSubtitles):
- url = 'http://www.dailymotion.com/video/xczg00'
- IE = DailymotionIE
-
- def test_allsubtitles(self):
- self.DL.params['writesubtitles'] = True
- self.DL.params['allsubtitles'] = True
- subtitles = self.getSubtitles()
- self.assertTrue(len(subtitles.keys()) >= 6)
- self.assertEqual(md5(subtitles['en']), '976553874490cba125086bbfea3ff76f')
- self.assertEqual(md5(subtitles['fr']), '594564ec7d588942e384e920e5341792')
- for lang in ['es', 'fr', 'de']:
- self.assertTrue(subtitles.get(lang) is not None, 'Subtitles for \'%s\' not extracted' % lang)
-
- def test_nosubtitles(self):
- self.DL.expect_warning('video doesn\'t have subtitles')
- self.url = 'http://www.dailymotion.com/video/x12u166_le-zapping-tele-star-du-08-aout-2013_tv'
- self.DL.params['writesubtitles'] = True
- self.DL.params['allsubtitles'] = True
- subtitles = self.getSubtitles()
- self.assertFalse(subtitles)
-
-
-@unittest.skip('IE broken')
-class TestTedSubtitles(BaseTestSubtitles):
- url = 'http://www.ted.com/talks/dan_dennett_on_our_consciousness.html'
- IE = TEDIE
-
- def test_allsubtitles(self):
- self.DL.params['writesubtitles'] = True
- self.DL.params['allsubtitles'] = True
- subtitles = self.getSubtitles()
- self.assertTrue(len(subtitles.keys()) >= 28)
- self.assertEqual(md5(subtitles['en']), '4262c1665ff928a2dada178f62cb8d14')
- self.assertEqual(md5(subtitles['fr']), '66a63f7f42c97a50f8c0e90bc7797bb5')
- for lang in ['es', 'fr', 'de']:
- self.assertTrue(subtitles.get(lang) is not None, 'Subtitles for \'%s\' not extracted' % lang)
-
-
-class TestVimeoSubtitles(BaseTestSubtitles):
- url = 'http://vimeo.com/76979871'
- IE = VimeoIE
-
- def test_allsubtitles(self):
- self.DL.params['writesubtitles'] = True
- self.DL.params['allsubtitles'] = True
- subtitles = self.getSubtitles()
- self.assertEqual(set(subtitles.keys()), set(['de', 'en', 'es', 'fr']))
- self.assertEqual(md5(subtitles['en']), '386cbc9320b94e25cb364b97935e5dd1')
- self.assertEqual(md5(subtitles['fr']), 'c9b69eef35bc6641c0d4da8a04f9dfac')
-
- def test_nosubtitles(self):
- self.DL.expect_warning('video doesn\'t have subtitles')
- self.url = 'http://vimeo.com/68093876'
- self.DL.params['writesubtitles'] = True
- self.DL.params['allsubtitles'] = True
- subtitles = self.getSubtitles()
- self.assertFalse(subtitles)
-
-
-@unittest.skip('IE broken')
-class TestWallaSubtitles(BaseTestSubtitles):
- url = 'http://vod.walla.co.il/movie/2705958/the-yes-men'
- IE = WallaIE
-
- def test_allsubtitles(self):
- self.DL.expect_warning('Automatic Captions not supported by this server')
- self.DL.params['writesubtitles'] = True
- self.DL.params['allsubtitles'] = True
- subtitles = self.getSubtitles()
- self.assertEqual(set(subtitles.keys()), set(['heb']))
- self.assertEqual(md5(subtitles['heb']), 'e758c5d7cb982f6bef14f377ec7a3920')
-
- def test_nosubtitles(self):
- self.DL.expect_warning('video doesn\'t have subtitles')
- self.url = 'http://vod.walla.co.il/movie/2642630/one-direction-all-for-one'
- self.DL.params['writesubtitles'] = True
- self.DL.params['allsubtitles'] = True
- subtitles = self.getSubtitles()
- self.assertFalse(subtitles)
-
-
-@unittest.skip('IE broken')
-class TestCeskaTelevizeSubtitles(BaseTestSubtitles):
- url = 'http://www.ceskatelevize.cz/ivysilani/10600540290-u6-uzasny-svet-techniky'
- IE = CeskaTelevizeIE
-
- def test_allsubtitles(self):
- self.DL.expect_warning('Automatic Captions not supported by this server')
- self.DL.params['writesubtitles'] = True
- self.DL.params['allsubtitles'] = True
- subtitles = self.getSubtitles()
- self.assertEqual(set(subtitles.keys()), set(['cs']))
- self.assertTrue(len(subtitles['cs']) > 20000)
-
- def test_nosubtitles(self):
- self.DL.expect_warning('video doesn\'t have subtitles')
- self.url = 'http://www.ceskatelevize.cz/ivysilani/ivysilani/10441294653-hyde-park-civilizace/214411058091220'
- self.DL.params['writesubtitles'] = True
- self.DL.params['allsubtitles'] = True
- subtitles = self.getSubtitles()
- self.assertFalse(subtitles)
-
-
-@unittest.skip('IE broken')
-class TestLyndaSubtitles(BaseTestSubtitles):
- url = 'http://www.lynda.com/Bootstrap-tutorials/Using-exercise-files/110885/114408-4.html'
- IE = LyndaIE
-
- def test_allsubtitles(self):
- self.DL.params['writesubtitles'] = True
- self.DL.params['allsubtitles'] = True
- subtitles = self.getSubtitles()
- self.assertEqual(set(subtitles.keys()), set(['en']))
- self.assertEqual(md5(subtitles['en']), '09bbe67222259bed60deaa26997d73a7')
-
-
-@unittest.skip('IE broken')
-class TestNPOSubtitles(BaseTestSubtitles):
- url = 'http://www.npo.nl/nos-journaal/28-08-2014/POW_00722860'
- IE = NPOIE
-
- def test_allsubtitles(self):
- self.DL.params['writesubtitles'] = True
- self.DL.params['allsubtitles'] = True
- subtitles = self.getSubtitles()
- self.assertEqual(set(subtitles.keys()), set(['nl']))
- self.assertEqual(md5(subtitles['nl']), 'fc6435027572b63fb4ab143abd5ad3f4')
-
-
-@unittest.skip('IE broken')
-class TestMTVSubtitles(BaseTestSubtitles):
- url = 'http://www.cc.com/video-clips/p63lk0/adam-devine-s-house-party-chasing-white-swans'
- IE = ComedyCentralIE
-
- def getInfoDict(self):
- return super(TestMTVSubtitles, self).getInfoDict()['entries'][0]
-
- def test_allsubtitles(self):
- self.DL.params['writesubtitles'] = True
- self.DL.params['allsubtitles'] = True
- subtitles = self.getSubtitles()
- self.assertEqual(set(subtitles.keys()), set(['en']))
- self.assertEqual(md5(subtitles['en']), '78206b8d8a0cfa9da64dc026eea48961')
-
-
-class TestNRKSubtitles(BaseTestSubtitles):
- url = 'http://tv.nrk.no/serie/ikke-gjoer-dette-hjemme/DMPV73000411/sesong-2/episode-1'
- IE = NRKTVIE
-
- def test_allsubtitles(self):
- self.DL.params['writesubtitles'] = True
- self.DL.params['allsubtitles'] = True
- self.DL.params['format'] = 'best/bestvideo'
- subtitles = self.getSubtitles()
- self.assertEqual(set(subtitles.keys()), set(['nb-ttv']))
- self.assertEqual(md5(subtitles['nb-ttv']), '67e06ff02d0deaf975e68f6cb8f6a149')
-
-
-class TestRaiPlaySubtitles(BaseTestSubtitles):
- IE = RaiPlayIE
-
- def test_subtitles_key(self):
- self.url = 'http://www.raiplay.it/video/2014/04/Report-del-07042014-cb27157f-9dd0-4aee-b788-b1f67643a391.html'
- self.DL.params['writesubtitles'] = True
- self.DL.params['allsubtitles'] = True
- subtitles = self.getSubtitles()
- self.assertEqual(set(subtitles.keys()), set(['it']))
- self.assertEqual(md5(subtitles['it']), 'b1d90a98755126b61e667567a1f6680a')
-
- def test_subtitles_array_key(self):
- self.url = 'https://www.raiplay.it/video/2020/12/Report---04-01-2021-2e90f1de-8eee-4de4-ac0e-78d21db5b600.html'
- self.DL.params['writesubtitles'] = True
- self.DL.params['allsubtitles'] = True
- subtitles = self.getSubtitles()
- self.assertEqual(set(subtitles.keys()), set(['it']))
- self.assertEqual(md5(subtitles['it']), '4b3264186fbb103508abe5311cfcb9cd')
-
-
-@unittest.skip('IE broken - DRM only')
-class TestVikiSubtitles(BaseTestSubtitles):
- url = 'http://www.viki.com/videos/1060846v-punch-episode-18'
- IE = VikiIE
-
- def test_allsubtitles(self):
- self.DL.params['writesubtitles'] = True
- self.DL.params['allsubtitles'] = True
- subtitles = self.getSubtitles()
- self.assertEqual(set(subtitles.keys()), set(['en']))
- self.assertEqual(md5(subtitles['en']), '53cb083a5914b2d84ef1ab67b880d18a')
-
-
-class TestThePlatformSubtitles(BaseTestSubtitles):
- # from http://www.3playmedia.com/services-features/tools/integrations/theplatform/
- # (see http://theplatform.com/about/partners/type/subtitles-closed-captioning/)
- url = 'theplatform:JFUjUE1_ehvq'
- IE = ThePlatformIE
-
- def test_allsubtitles(self):
- self.DL.params['writesubtitles'] = True
- self.DL.params['allsubtitles'] = True
- subtitles = self.getSubtitles()
- self.assertEqual(set(subtitles.keys()), set(['en']))
- self.assertEqual(md5(subtitles['en']), '97e7670cbae3c4d26ae8bcc7fdd78d4b')
-
-
-@unittest.skip('IE broken')
-class TestThePlatformFeedSubtitles(BaseTestSubtitles):
- url = 'http://feed.theplatform.com/f/7wvmTC/msnbc_video-p-test?form=json&pretty=true&range=-40&byGuid=n_hardball_5biden_140207'
- IE = ThePlatformFeedIE
-
- def test_allsubtitles(self):
- self.DL.params['writesubtitles'] = True
- self.DL.params['allsubtitles'] = True
- subtitles = self.getSubtitles()
- self.assertEqual(set(subtitles.keys()), set(['en']))
- self.assertEqual(md5(subtitles['en']), '48649a22e82b2da21c9a67a395eedade')
-
-
-class TestRtveSubtitles(BaseTestSubtitles):
- url = 'http://www.rtve.es/alacarta/videos/los-misterios-de-laura/misterios-laura-capitulo-32-misterio-del-numero-17-2-parte/2428621/'
- IE = RTVEALaCartaIE
-
- def test_allsubtitles(self):
- print('Skipping, only available from Spain')
- return
- self.DL.params['writesubtitles'] = True
- self.DL.params['allsubtitles'] = True
- subtitles = self.getSubtitles()
- self.assertEqual(set(subtitles.keys()), set(['es']))
- self.assertEqual(md5(subtitles['es']), '69e70cae2d40574fb7316f31d6eb7fca')
-
-
-class TestDemocracynowSubtitles(BaseTestSubtitles):
- url = 'http://www.democracynow.org/shows/2015/7/3'
- IE = DemocracynowIE
-
- def test_allsubtitles(self):
- self.DL.params['writesubtitles'] = True
- self.DL.params['allsubtitles'] = True
- subtitles = self.getSubtitles()
- self.assertEqual(set(subtitles.keys()), set(['en']))
- self.assertEqual(md5(subtitles['en']), 'a3cc4c0b5eadd74d9974f1c1f5101045')
-
- def test_subtitles_in_page(self):
- self.url = 'http://www.democracynow.org/2015/7/3/this_flag_comes_down_today_bree'
- self.DL.params['writesubtitles'] = True
- self.DL.params['allsubtitles'] = True
- subtitles = self.getSubtitles()
- self.assertEqual(set(subtitles.keys()), set(['en']))
- self.assertEqual(md5(subtitles['en']), 'a3cc4c0b5eadd74d9974f1c1f5101045')
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/test_swfinterp.py b/test/test_swfinterp.py
deleted file mode 100644
index 7c282ee00..000000000
--- a/test/test_swfinterp.py
+++ /dev/null
@@ -1,82 +0,0 @@
-#!/usr/bin/env python
-from __future__ import unicode_literals
-
-# Allow direct execution
-import os
-import sys
-import unittest
-
-dirn = os.path.dirname
-
-sys.path.insert(0, dirn(dirn(os.path.abspath(__file__))))
-
-import errno
-import json
-import re
-import subprocess
-
-from youtube_dl.swfinterp import SWFInterpreter
-from youtube_dl.compat import compat_open as open
-
-
-TEST_DIR = os.path.join(
- os.path.dirname(os.path.abspath(__file__)), 'swftests')
-
-
-class TestSWFInterpreter(unittest.TestCase):
- pass
-
-
-def _make_testfunc(testfile):
- m = re.match(r'^(.*)\.(as)$', testfile)
- if not m:
- return
- test_id = m.group(1)
-
- def test_func(self):
- as_file = os.path.join(TEST_DIR, testfile)
- swf_file = os.path.join(TEST_DIR, test_id + '.swf')
- if ((not os.path.exists(swf_file))
- or os.path.getmtime(swf_file) < os.path.getmtime(as_file)):
- # Recompile
- try:
- subprocess.check_call([
- 'mxmlc', '-output', swf_file,
- '-static-link-runtime-shared-libraries', as_file])
- except OSError as ose:
- if ose.errno == errno.ENOENT:
- self.skipTest('mxmlc not found!')
- return
- raise
-
- with open(swf_file, 'rb') as swf_f:
- swf_content = swf_f.read()
- swfi = SWFInterpreter(swf_content)
-
- with open(as_file, 'r', encoding='utf-8') as as_f:
- as_content = as_f.read()
-
- def _find_spec(key):
- m = re.search(
- r'(?m)^//\s*%s:\s*(.*?)\n' % re.escape(key), as_content)
- if not m:
- raise ValueError('Cannot find %s in %s' % (key, testfile))
- return json.loads(m.group(1))
-
- input_args = _find_spec('input')
- output = _find_spec('output')
-
- swf_class = swfi.extract_class(test_id)
- func = swfi.extract_function(swf_class, 'main')
- res = func(input_args)
- self.assertEqual(res, output)
-
- test_func.__name__ = str('test_swf_' + test_id)
- setattr(TestSWFInterpreter, test_func.__name__, test_func)
-
-
-for testfile in os.listdir(TEST_DIR):
- _make_testfunc(testfile)
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/test_traversal.py b/test/test_traversal.py
deleted file mode 100644
index 00a428edb..000000000
--- a/test/test_traversal.py
+++ /dev/null
@@ -1,509 +0,0 @@
-#!/usr/bin/env python
-# coding: utf-8
-from __future__ import unicode_literals
-
-# Allow direct execution
-import os
-import sys
-import unittest
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-
-import re
-
-from youtube_dl.traversal import (
- dict_get,
- get_first,
- T,
- traverse_obj,
-)
-from youtube_dl.compat import (
- compat_etree_fromstring,
- compat_http_cookies,
- compat_str,
-)
-from youtube_dl.utils import (
- int_or_none,
- str_or_none,
-)
-
-_TEST_DATA = {
- 100: 100,
- 1.2: 1.2,
- 'str': 'str',
- 'None': None,
- '...': Ellipsis,
- 'urls': [
- {'index': 0, 'url': 'https://www.example.com/0'},
- {'index': 1, 'url': 'https://www.example.com/1'},
- ],
- 'data': (
- {'index': 2},
- {'index': 3},
- ),
- 'dict': {},
-}
-
-
-if sys.version_info < (3, 0):
- class _TestCase(unittest.TestCase):
-
- def assertCountEqual(self, *args, **kwargs):
- return self.assertItemsEqual(*args, **kwargs)
-else:
- _TestCase = unittest.TestCase
-
-
-class TestTraversal(_TestCase):
- def assertMaybeCountEqual(self, *args, **kwargs):
- if sys.version_info < (3, 7):
- # random dict order
- return self.assertCountEqual(*args, **kwargs)
- else:
- return self.assertEqual(*args, **kwargs)
-
- def test_traverse_obj(self):
- # instant compat
- str = compat_str
-
- # define a pukka Iterable
- def iter_range(stop):
- for from_ in range(stop):
- yield from_
-
- # Test base functionality
- self.assertEqual(traverse_obj(_TEST_DATA, ('str',)), 'str',
- msg='allow tuple path')
- self.assertEqual(traverse_obj(_TEST_DATA, ['str']), 'str',
- msg='allow list path')
- self.assertEqual(traverse_obj(_TEST_DATA, (value for value in ("str",))), 'str',
- msg='allow iterable path')
- self.assertEqual(traverse_obj(_TEST_DATA, 'str'), 'str',
- msg='single items should be treated as a path')
- self.assertEqual(traverse_obj(_TEST_DATA, None), _TEST_DATA)
- self.assertEqual(traverse_obj(_TEST_DATA, 100), 100)
- self.assertEqual(traverse_obj(_TEST_DATA, 1.2), 1.2)
-
- # Test Ellipsis behavior
- self.assertCountEqual(traverse_obj(_TEST_DATA, Ellipsis),
- (item for item in _TEST_DATA.values() if item not in (None, {})),
- msg='`...` should give all non-discarded values')
- self.assertCountEqual(traverse_obj(_TEST_DATA, ('urls', 0, Ellipsis)), _TEST_DATA['urls'][0].values(),
- msg='`...` selection for dicts should select all values')
- self.assertEqual(traverse_obj(_TEST_DATA, (Ellipsis, Ellipsis, 'url')),
- ['https://www.example.com/0', 'https://www.example.com/1'],
- msg='nested `...` queries should work')
- self.assertCountEqual(traverse_obj(_TEST_DATA, (Ellipsis, Ellipsis, 'index')), iter_range(4),
- msg='`...` query result should be flattened')
- self.assertEqual(traverse_obj(iter(range(4)), Ellipsis), list(range(4)),
- msg='`...` should accept iterables')
-
- # Test function as key
- self.assertEqual(traverse_obj(_TEST_DATA, lambda x, y: x == 'urls' and isinstance(y, list)),
- [_TEST_DATA['urls']],
- msg='function as query key should perform a filter based on (key, value)')
- self.assertCountEqual(traverse_obj(_TEST_DATA, lambda _, x: isinstance(x[0], str)), set(('str',)),
- msg='exceptions in the query function should be caught')
- self.assertEqual(traverse_obj(iter(range(4)), lambda _, x: x % 2 == 0), [0, 2],
- msg='function key should accept iterables')
- if __debug__:
- with self.assertRaises(Exception, msg='Wrong function signature should raise in debug'):
- traverse_obj(_TEST_DATA, lambda a: Ellipsis)
- with self.assertRaises(Exception, msg='Wrong function signature should raise in debug'):
- traverse_obj(_TEST_DATA, lambda a, b, c: Ellipsis)
-
- # Test set as key (transformation/type, like `expected_type`)
- self.assertEqual(traverse_obj(_TEST_DATA, (Ellipsis, T(str.upper), )), ['STR'],
- msg='Function in set should be a transformation')
- self.assertEqual(traverse_obj(_TEST_DATA, ('fail', T(lambda _: 'const'))), 'const',
- msg='Function in set should always be called')
- self.assertEqual(traverse_obj(_TEST_DATA, (Ellipsis, T(str))), ['str'],
- msg='Type in set should be a type filter')
- self.assertMaybeCountEqual(traverse_obj(_TEST_DATA, (Ellipsis, T(str, int))), [100, 'str'],
- msg='Multiple types in set should be a type filter')
- self.assertEqual(traverse_obj(_TEST_DATA, T(dict)), _TEST_DATA,
- msg='A single set should be wrapped into a path')
- self.assertEqual(traverse_obj(_TEST_DATA, (Ellipsis, T(str.upper))), ['STR'],
- msg='Transformation function should not raise')
- self.assertMaybeCountEqual(traverse_obj(_TEST_DATA, (Ellipsis, T(str_or_none))),
- [item for item in map(str_or_none, _TEST_DATA.values()) if item is not None],
- msg='Function in set should be a transformation')
- if __debug__:
- with self.assertRaises(Exception, msg='Sets with length != 1 should raise in debug'):
- traverse_obj(_TEST_DATA, set())
- with self.assertRaises(Exception, msg='Sets with length != 1 should raise in debug'):
- traverse_obj(_TEST_DATA, set((str.upper, str)))
-
- # Test `slice` as a key
- _SLICE_DATA = [0, 1, 2, 3, 4]
- self.assertEqual(traverse_obj(_TEST_DATA, ('dict', slice(1))), None,
- msg='slice on a dictionary should not throw')
- self.assertEqual(traverse_obj(_SLICE_DATA, slice(1)), _SLICE_DATA[:1],
- msg='slice key should apply slice to sequence')
- self.assertEqual(traverse_obj(_SLICE_DATA, slice(1, 2)), _SLICE_DATA[1:2],
- msg='slice key should apply slice to sequence')
- self.assertEqual(traverse_obj(_SLICE_DATA, slice(1, 4, 2)), _SLICE_DATA[1:4:2],
- msg='slice key should apply slice to sequence')
-
- # Test alternative paths
- self.assertEqual(traverse_obj(_TEST_DATA, 'fail', 'str'), 'str',
- msg='multiple `paths` should be treated as alternative paths')
- self.assertEqual(traverse_obj(_TEST_DATA, 'str', 100), 'str',
- msg='alternatives should exit early')
- self.assertEqual(traverse_obj(_TEST_DATA, 'fail', 'fail'), None,
- msg='alternatives should return `default` if exhausted')
- self.assertEqual(traverse_obj(_TEST_DATA, (Ellipsis, 'fail'), 100), 100,
- msg='alternatives should track their own branching return')
- self.assertEqual(traverse_obj(_TEST_DATA, ('dict', Ellipsis), ('data', Ellipsis)), list(_TEST_DATA['data']),
- msg='alternatives on empty objects should search further')
-
- # Test branch and path nesting
- self.assertEqual(traverse_obj(_TEST_DATA, ('urls', (3, 0), 'url')), ['https://www.example.com/0'],
- msg='tuple as key should be treated as branches')
- self.assertEqual(traverse_obj(_TEST_DATA, ('urls', [3, 0], 'url')), ['https://www.example.com/0'],
- msg='list as key should be treated as branches')
- self.assertEqual(traverse_obj(_TEST_DATA, ('urls', ((1, 'fail'), (0, 'url')))), ['https://www.example.com/0'],
- msg='double nesting in path should be treated as paths')
- self.assertEqual(traverse_obj(['0', [1, 2]], [(0, 1), 0]), [1],
- msg='do not fail early on branching')
- self.assertCountEqual(traverse_obj(_TEST_DATA, ('urls', ((1, ('fail', 'url')), (0, 'url')))),
- ['https://www.example.com/0', 'https://www.example.com/1'],
- msg='triple nesting in path should be treated as branches')
- self.assertEqual(traverse_obj(_TEST_DATA, ('urls', ('fail', (Ellipsis, 'url')))),
- ['https://www.example.com/0', 'https://www.example.com/1'],
- msg='ellipsis as branch path start gets flattened')
-
- # Test dictionary as key
- self.assertEqual(traverse_obj(_TEST_DATA, {0: 100, 1: 1.2}), {0: 100, 1: 1.2},
- msg='dict key should result in a dict with the same keys')
- self.assertEqual(traverse_obj(_TEST_DATA, {0: ('urls', 0, 'url')}),
- {0: 'https://www.example.com/0'},
- msg='dict key should allow paths')
- self.assertEqual(traverse_obj(_TEST_DATA, {0: ('urls', (3, 0), 'url')}),
- {0: ['https://www.example.com/0']},
- msg='tuple in dict path should be treated as branches')
- self.assertEqual(traverse_obj(_TEST_DATA, {0: ('urls', ((1, 'fail'), (0, 'url')))}),
- {0: ['https://www.example.com/0']},
- msg='double nesting in dict path should be treated as paths')
- self.assertEqual(traverse_obj(_TEST_DATA, {0: ('urls', ((1, ('fail', 'url')), (0, 'url')))}),
- {0: ['https://www.example.com/1', 'https://www.example.com/0']},
- msg='triple nesting in dict path should be treated as branches')
- self.assertEqual(traverse_obj(_TEST_DATA, {0: 'fail'}), {},
- msg='remove `None` values when top level dict key fails')
- self.assertEqual(traverse_obj(_TEST_DATA, {0: 'fail'}, default=Ellipsis), {0: Ellipsis},
- msg='use `default` if key fails and `default`')
- self.assertEqual(traverse_obj(_TEST_DATA, {0: 'dict'}), {},
- msg='remove empty values when dict key')
- self.assertEqual(traverse_obj(_TEST_DATA, {0: 'dict'}, default=Ellipsis), {0: Ellipsis},
- msg='use `default` when dict key and a default')
- self.assertEqual(traverse_obj(_TEST_DATA, {0: {0: 'fail'}}), {},
- msg='remove empty values when nested dict key fails')
- self.assertEqual(traverse_obj(None, {0: 'fail'}), {},
- msg='default to dict if pruned')
- self.assertEqual(traverse_obj(None, {0: 'fail'}, default=Ellipsis), {0: Ellipsis},
- msg='default to dict if pruned and default is given')
- self.assertEqual(traverse_obj(_TEST_DATA, {0: {0: 'fail'}}, default=Ellipsis), {0: {0: Ellipsis}},
- msg='use nested `default` when nested dict key fails and `default`')
- self.assertEqual(traverse_obj(_TEST_DATA, {0: ('dict', Ellipsis)}), {},
- msg='remove key if branch in dict key not successful')
-
- # Testing default parameter behavior
- _DEFAULT_DATA = {'None': None, 'int': 0, 'list': []}
- self.assertEqual(traverse_obj(_DEFAULT_DATA, 'fail'), None,
- msg='default value should be `None`')
- self.assertEqual(traverse_obj(_DEFAULT_DATA, 'fail', 'fail', default=Ellipsis), Ellipsis,
- msg='chained fails should result in default')
- self.assertEqual(traverse_obj(_DEFAULT_DATA, 'None', 'int'), 0,
- msg='should not short cirquit on `None`')
- self.assertEqual(traverse_obj(_DEFAULT_DATA, 'fail', default=1), 1,
- msg='invalid dict key should result in `default`')
- self.assertEqual(traverse_obj(_DEFAULT_DATA, 'None', default=1), 1,
- msg='`None` is a deliberate sentinel and should become `default`')
- self.assertEqual(traverse_obj(_DEFAULT_DATA, ('list', 10)), None,
- msg='`IndexError` should result in `default`')
- self.assertEqual(traverse_obj(_DEFAULT_DATA, (Ellipsis, 'fail'), default=1), 1,
- msg='if branched but not successful return `default` if defined, not `[]`')
- self.assertEqual(traverse_obj(_DEFAULT_DATA, (Ellipsis, 'fail'), default=None), None,
- msg='if branched but not successful return `default` even if `default` is `None`')
- self.assertEqual(traverse_obj(_DEFAULT_DATA, (Ellipsis, 'fail')), [],
- msg='if branched but not successful return `[]`, not `default`')
- self.assertEqual(traverse_obj(_DEFAULT_DATA, ('list', Ellipsis)), [],
- msg='if branched but object is empty return `[]`, not `default`')
- self.assertEqual(traverse_obj(None, Ellipsis), [],
- msg='if branched but object is `None` return `[]`, not `default`')
- self.assertEqual(traverse_obj({0: None}, (0, Ellipsis)), [],
- msg='if branched but state is `None` return `[]`, not `default`')
-
- branching_paths = [
- ('fail', Ellipsis),
- (Ellipsis, 'fail'),
- 100 * ('fail',) + (Ellipsis,),
- (Ellipsis,) + 100 * ('fail',),
- ]
- for branching_path in branching_paths:
- self.assertEqual(traverse_obj({}, branching_path), [],
- msg='if branched but state is `None`, return `[]` (not `default`)')
- self.assertEqual(traverse_obj({}, 'fail', branching_path), [],
- msg='if branching in last alternative and previous did not match, return `[]` (not `default`)')
- self.assertEqual(traverse_obj({0: 'x'}, 0, branching_path), 'x',
- msg='if branching in last alternative and previous did match, return single value')
- self.assertEqual(traverse_obj({0: 'x'}, branching_path, 0), 'x',
- msg='if branching in first alternative and non-branching path does match, return single value')
- self.assertEqual(traverse_obj({}, branching_path, 'fail'), None,
- msg='if branching in first alternative and non-branching path does not match, return `default`')
-
- # Testing expected_type behavior
- _EXPECTED_TYPE_DATA = {'str': 'str', 'int': 0}
- self.assertEqual(traverse_obj(_EXPECTED_TYPE_DATA, 'str', expected_type=str),
- 'str', msg='accept matching `expected_type` type')
- self.assertEqual(traverse_obj(_EXPECTED_TYPE_DATA, 'str', expected_type=int),
- None, msg='reject non-matching `expected_type` type')
- self.assertEqual(traverse_obj(_EXPECTED_TYPE_DATA, 'int', expected_type=lambda x: str(x)),
- '0', msg='transform type using type function')
- self.assertEqual(traverse_obj(_EXPECTED_TYPE_DATA, 'str', expected_type=lambda _: 1 / 0),
- None, msg='wrap expected_type function in try_call')
- self.assertEqual(traverse_obj(_EXPECTED_TYPE_DATA, Ellipsis, expected_type=str),
- ['str'], msg='eliminate items that expected_type fails on')
- self.assertEqual(traverse_obj(_TEST_DATA, {0: 100, 1: 1.2}, expected_type=int),
- {0: 100}, msg='type as expected_type should filter dict values')
- self.assertEqual(traverse_obj(_TEST_DATA, {0: 100, 1: 1.2, 2: 'None'}, expected_type=str_or_none),
- {0: '100', 1: '1.2'}, msg='function as expected_type should transform dict values')
- self.assertEqual(traverse_obj(_TEST_DATA, ({0: 1.2}, 0, set((int_or_none,))), expected_type=int),
- 1, msg='expected_type should not filter non-final dict values')
- self.assertEqual(traverse_obj(_TEST_DATA, {0: {0: 100, 1: 'str'}}, expected_type=int),
- {0: {0: 100}}, msg='expected_type should transform deep dict values')
- self.assertEqual(traverse_obj(_TEST_DATA, [({0: '...'}, {0: '...'})], expected_type=type(Ellipsis)),
- [{0: Ellipsis}, {0: Ellipsis}], msg='expected_type should transform branched dict values')
- self.assertEqual(traverse_obj({1: {3: 4}}, [(1, 2), 3], expected_type=int),
- [4], msg='expected_type regression for type matching in tuple branching')
- self.assertEqual(traverse_obj(_TEST_DATA, ['data', Ellipsis], expected_type=int),
- [], msg='expected_type regression for type matching in dict result')
-
- # Test get_all behavior
- _GET_ALL_DATA = {'key': [0, 1, 2]}
- self.assertEqual(traverse_obj(_GET_ALL_DATA, ('key', Ellipsis), get_all=False), 0,
- msg='if not `get_all`, return only first matching value')
- self.assertEqual(traverse_obj(_GET_ALL_DATA, Ellipsis, get_all=False), [0, 1, 2],
- msg='do not overflatten if not `get_all`')
-
- # Test casesense behavior
- _CASESENSE_DATA = {
- 'KeY': 'value0',
- 0: {
- 'KeY': 'value1',
- 0: {'KeY': 'value2'},
- },
- # FULLWIDTH LATIN CAPITAL LETTER K
- '\uff2bey': 'value3',
- }
- self.assertEqual(traverse_obj(_CASESENSE_DATA, 'key'), None,
- msg='dict keys should be case sensitive unless `casesense`')
- self.assertEqual(traverse_obj(_CASESENSE_DATA, 'keY',
- casesense=False), 'value0',
- msg='allow non matching key case if `casesense`')
- self.assertEqual(traverse_obj(_CASESENSE_DATA, '\uff4bey', # FULLWIDTH LATIN SMALL LETTER K
- casesense=False), 'value3',
- msg='allow non matching Unicode key case if `casesense`')
- self.assertEqual(traverse_obj(_CASESENSE_DATA, (0, ('keY',)),
- casesense=False), ['value1'],
- msg='allow non matching key case in branch if `casesense`')
- self.assertEqual(traverse_obj(_CASESENSE_DATA, (0, ((0, 'keY'),)),
- casesense=False), ['value2'],
- msg='allow non matching key case in branch path if `casesense`')
-
- # Test traverse_string behavior
- _TRAVERSE_STRING_DATA = {'str': 'str', 1.2: 1.2}
- self.assertEqual(traverse_obj(_TRAVERSE_STRING_DATA, ('str', 0)), None,
- msg='do not traverse into string if not `traverse_string`')
- self.assertEqual(traverse_obj(_TRAVERSE_STRING_DATA, ('str', 0),
- _traverse_string=True), 's',
- msg='traverse into string if `traverse_string`')
- self.assertEqual(traverse_obj(_TRAVERSE_STRING_DATA, (1.2, 1),
- _traverse_string=True), '.',
- msg='traverse into converted data if `traverse_string`')
- self.assertEqual(traverse_obj(_TRAVERSE_STRING_DATA, ('str', Ellipsis),
- _traverse_string=True), 'str',
- msg='`...` should result in string (same value) if `traverse_string`')
- self.assertEqual(traverse_obj(_TRAVERSE_STRING_DATA, ('str', slice(0, None, 2)),
- _traverse_string=True), 'sr',
- msg='`slice` should result in string if `traverse_string`')
- self.assertEqual(traverse_obj(_TRAVERSE_STRING_DATA, ('str', lambda i, v: i or v == 's'),
- _traverse_string=True), 'str',
- msg='function should result in string if `traverse_string`')
- self.assertEqual(traverse_obj(_TRAVERSE_STRING_DATA, ('str', (0, 2)),
- _traverse_string=True), ['s', 'r'],
- msg='branching should result in list if `traverse_string`')
- self.assertEqual(traverse_obj({}, (0, Ellipsis), _traverse_string=True), [],
- msg='branching should result in list if `traverse_string`')
- self.assertEqual(traverse_obj({}, (0, lambda x, y: True), _traverse_string=True), [],
- msg='branching should result in list if `traverse_string`')
- self.assertEqual(traverse_obj({}, (0, slice(1)), _traverse_string=True), [],
- msg='branching should result in list if `traverse_string`')
-
- # Test re.Match as input obj
- mobj = re.match(r'^0(12)(?P3)(4)?$', '0123')
- self.assertEqual(traverse_obj(mobj, Ellipsis), [x for x in mobj.groups() if x is not None],
- msg='`...` on a `re.Match` should give its `groups()`')
- self.assertEqual(traverse_obj(mobj, lambda k, _: k in (0, 2)), ['0123', '3'],
- msg='function on a `re.Match` should give groupno, value starting at 0')
- self.assertEqual(traverse_obj(mobj, 'group'), '3',
- msg='str key on a `re.Match` should give group with that name')
- self.assertEqual(traverse_obj(mobj, 2), '3',
- msg='int key on a `re.Match` should give group with that name')
- self.assertEqual(traverse_obj(mobj, 'gRoUp', casesense=False), '3',
- msg='str key on a `re.Match` should respect casesense')
- self.assertEqual(traverse_obj(mobj, 'fail'), None,
- msg='failing str key on a `re.Match` should return `default`')
- self.assertEqual(traverse_obj(mobj, 'gRoUpS', casesense=False), None,
- msg='failing str key on a `re.Match` should return `default`')
- self.assertEqual(traverse_obj(mobj, 8), None,
- msg='failing int key on a `re.Match` should return `default`')
- self.assertEqual(traverse_obj(mobj, lambda k, _: k in (0, 'group')), ['0123', '3'],
- msg='function on a `re.Match` should give group name as well')
-
- # Test xml.etree.ElementTree.Element as input obj
- etree = compat_etree_fromstring('''
-
-
- 1
- 2008
- 141100
-
-
-
-
- 4
- 2011
- 59900
-
-
-
- 68
- 2011
- 13600
-
-
-
- ''')
- self.assertEqual(traverse_obj(etree, ''), etree,
- msg='empty str key should return the element itself')
- self.assertEqual(traverse_obj(etree, 'country'), list(etree),
- msg='str key should return all children with that tag name')
- self.assertEqual(traverse_obj(etree, Ellipsis), list(etree),
- msg='`...` as key should return all children')
- self.assertEqual(traverse_obj(etree, lambda _, x: x[0].text == '4'), [etree[1]],
- msg='function as key should get element as value')
- self.assertEqual(traverse_obj(etree, lambda i, _: i == 1), [etree[1]],
- msg='function as key should get index as key')
- self.assertEqual(traverse_obj(etree, 0), etree[0],
- msg='int key should return the nth child')
- self.assertEqual(traverse_obj(etree, './/neighbor/@name'),
- ['Austria', 'Switzerland', 'Malaysia', 'Costa Rica', 'Colombia'],
- msg='`@` at end of path should give that attribute')
- self.assertEqual(traverse_obj(etree, '//neighbor/@fail'), [None, None, None, None, None],
- msg='`@` at end of path should give `None`')
- self.assertEqual(traverse_obj(etree, ('//neighbor/@', 2)), {'name': 'Malaysia', 'direction': 'N'},
- msg='`@` should give the full attribute dict')
- self.assertEqual(traverse_obj(etree, '//year/text()'), ['2008', '2011', '2011'],
- msg='`text()` at end of path should give the inner text')
- self.assertEqual(traverse_obj(etree, '//*[@direction]/@direction'), ['E', 'W', 'N', 'W', 'E'],
- msg='full python xpath features should be supported')
- self.assertEqual(traverse_obj(etree, (0, '@name')), 'Liechtenstein',
- msg='special transformations should act on current element')
- self.assertEqual(traverse_obj(etree, ('country', 0, Ellipsis, 'text()', T(int_or_none))), [1, 2008, 141100],
- msg='special transformations should act on current element')
-
- def test_traversal_unbranching(self):
- self.assertEqual(traverse_obj(_TEST_DATA, [(100, 1.2), all]), [100, 1.2],
- msg='`all` should give all results as list')
- self.assertEqual(traverse_obj(_TEST_DATA, [(100, 1.2), any]), 100,
- msg='`any` should give the first result')
- self.assertEqual(traverse_obj(_TEST_DATA, [100, all]), [100],
- msg='`all` should give list if non branching')
- self.assertEqual(traverse_obj(_TEST_DATA, [100, any]), 100,
- msg='`any` should give single item if non branching')
- self.assertEqual(traverse_obj(_TEST_DATA, [('dict', 'None', 100), all]), [100],
- msg='`all` should filter `None` and empty dict')
- self.assertEqual(traverse_obj(_TEST_DATA, [('dict', 'None', 100), any]), 100,
- msg='`any` should filter `None` and empty dict')
- self.assertEqual(traverse_obj(_TEST_DATA, [{
- 'all': [('dict', 'None', 100, 1.2), all],
- 'any': [('dict', 'None', 100, 1.2), any],
- }]), {'all': [100, 1.2], 'any': 100},
- msg='`all`/`any` should apply to each dict path separately')
- self.assertEqual(traverse_obj(_TEST_DATA, [{
- 'all': [('dict', 'None', 100, 1.2), all],
- 'any': [('dict', 'None', 100, 1.2), any],
- }], get_all=False), {'all': [100, 1.2], 'any': 100},
- msg='`all`/`any` should apply to dict regardless of `get_all`')
- self.assertIs(traverse_obj(_TEST_DATA, [('dict', 'None', 100, 1.2), all, T(float)]), None,
- msg='`all` should reset branching status')
- self.assertIs(traverse_obj(_TEST_DATA, [('dict', 'None', 100, 1.2), any, T(float)]), None,
- msg='`any` should reset branching status')
- self.assertEqual(traverse_obj(_TEST_DATA, [('dict', 'None', 100, 1.2), all, Ellipsis, T(float)]), [1.2],
- msg='`all` should allow further branching')
- self.assertEqual(traverse_obj(_TEST_DATA, [('dict', 'None', 'urls', 'data'), any, Ellipsis, 'index']), [0, 1],
- msg='`any` should allow further branching')
-
- def test_traversal_morsel(self):
- values = {
- 'expires': 'a',
- 'path': 'b',
- 'comment': 'c',
- 'domain': 'd',
- 'max-age': 'e',
- 'secure': 'f',
- 'httponly': 'g',
- 'version': 'h',
- 'samesite': 'i',
- }
- # SameSite added in Py3.8, breaks .update for 3.5-3.7
- if sys.version_info < (3, 8):
- del values['samesite']
- morsel = compat_http_cookies.Morsel()
- morsel.set(str('item_key'), 'item_value', 'coded_value')
- morsel.update(values)
- values['key'] = str('item_key')
- values['value'] = 'item_value'
- values = dict((str(k), v) for k, v in values.items())
- # make test pass even without ordered dict
- value_set = set(values.values())
-
- for key, value in values.items():
- self.assertEqual(traverse_obj(morsel, key), value,
- msg='Morsel should provide access to all values')
- self.assertEqual(set(traverse_obj(morsel, Ellipsis)), value_set,
- msg='`...` should yield all values')
- self.assertEqual(set(traverse_obj(morsel, lambda k, v: True)), value_set,
- msg='function key should yield all values')
- self.assertIs(traverse_obj(morsel, [(None,), any]), morsel,
- msg='Morsel should not be implicitly changed to dict on usage')
-
- def test_get_first(self):
- self.assertEqual(get_first([{'a': None}, {'a': 'spam'}], 'a'), 'spam')
-
- def test_dict_get(self):
- FALSE_VALUES = {
- 'none': None,
- 'false': False,
- 'zero': 0,
- 'empty_string': '',
- 'empty_list': [],
- }
- d = FALSE_VALUES.copy()
- d['a'] = 42
- self.assertEqual(dict_get(d, 'a'), 42)
- self.assertEqual(dict_get(d, 'b'), None)
- self.assertEqual(dict_get(d, 'b', 42), 42)
- self.assertEqual(dict_get(d, ('a', )), 42)
- self.assertEqual(dict_get(d, ('b', 'a', )), 42)
- self.assertEqual(dict_get(d, ('b', 'c', 'a', 'd', )), 42)
- self.assertEqual(dict_get(d, ('b', 'c', )), None)
- self.assertEqual(dict_get(d, ('b', 'c', ), 42), 42)
- for key, false_value in FALSE_VALUES.items():
- self.assertEqual(dict_get(d, ('b', 'c', key, )), None)
- self.assertEqual(dict_get(d, ('b', 'c', key, ), skip_false_values=False), false_value)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/test_unicode_literals.py b/test/test_unicode_literals.py
deleted file mode 100644
index 0c83f2a0c..000000000
--- a/test/test_unicode_literals.py
+++ /dev/null
@@ -1,66 +0,0 @@
-from __future__ import unicode_literals
-
-# Allow direct execution
-import os
-import re
-import sys
-import unittest
-
-dirn = os.path.dirname
-
-rootDir = dirn(dirn(os.path.abspath(__file__)))
-
-sys.path.insert(0, rootDir)
-
-IGNORED_FILES = [
- 'setup.py', # http://bugs.python.org/issue13943
- 'conf.py',
- 'buildserver.py',
- 'get-pip.py',
-]
-
-IGNORED_DIRS = [
- '.git',
- '.tox',
-]
-
-from test.helper import assertRegexpMatches
-from youtube_dl.compat import compat_open as open
-
-
-class TestUnicodeLiterals(unittest.TestCase):
- def test_all_files(self):
- for dirpath, dirnames, filenames in os.walk(rootDir):
- for ignore_dir in IGNORED_DIRS:
- if ignore_dir in dirnames:
- # If we remove the directory from dirnames os.walk won't
- # recurse into it
- dirnames.remove(ignore_dir)
- for basename in filenames:
- if not basename.endswith('.py'):
- continue
- if basename in IGNORED_FILES:
- continue
-
- fn = os.path.join(dirpath, basename)
- with open(fn, encoding='utf-8') as inf:
- code = inf.read()
-
- if "'" not in code and '"' not in code:
- continue
- assertRegexpMatches(
- self,
- code,
- r'(?:(?:#.*?|\s*)\n)*from __future__ import (?:[a-z_]+,\s*)*unicode_literals',
- 'unicode_literals import missing in %s' % fn)
-
- m = re.search(r'(?<=\s)u[\'"](?!\)|,|$)', code)
- if m is not None:
- self.assertTrue(
- m is None,
- 'u present in %s, around %s' % (
- fn, code[m.start() - 10:m.end() + 10]))
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/test_update.py b/test/test_update.py
deleted file mode 100644
index d9c71511d..000000000
--- a/test/test_update.py
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/usr/bin/env python
-
-from __future__ import unicode_literals
-
-# Allow direct execution
-import os
-import sys
-import unittest
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-
-import json
-from youtube_dl.update import rsa_verify
-
-
-class TestUpdate(unittest.TestCase):
- def test_rsa_verify(self):
- UPDATES_RSA_KEY = (0x9d60ee4d8f805312fdb15a62f87b95bd66177b91df176765d13514a0f1754bcd2057295c5b6f1d35daa6742c3ffc9a82d3e118861c207995a8031e151d863c9927e304576bc80692bc8e094896fcf11b66f3e29e04e3a71e9a11558558acea1840aec37fc396fb6b65dc81a1c4144e03bd1c011de62e3f1357b327d08426fe93, 65537)
- with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'versions.json'), 'rb') as f:
- versions_info = f.read().decode()
- versions_info = json.loads(versions_info)
- signature = versions_info['signature']
- del versions_info['signature']
- self.assertTrue(rsa_verify(
- json.dumps(versions_info, sort_keys=True).encode('utf-8'),
- signature, UPDATES_RSA_KEY))
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/test_utils.py b/test/test_utils.py
deleted file mode 100644
index 2947cce7e..000000000
--- a/test/test_utils.py
+++ /dev/null
@@ -1,1728 +0,0 @@
-#!/usr/bin/env python
-# coding: utf-8
-
-from __future__ import unicode_literals
-
-# Allow direct execution
-import os
-import sys
-import unittest
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-
-# Various small unit tests
-import io
-import itertools
-import json
-import types
-import xml.etree.ElementTree
-
-from youtube_dl.utils import (
- _UnsafeExtensionError,
- age_restricted,
- args_to_str,
- base_url,
- caesar,
- clean_html,
- clean_podcast_url,
- date_from_str,
- DateRange,
- detect_exe_version,
- determine_ext,
- encode_base_n,
- encode_compat_str,
- encodeFilename,
- escape_rfc3986,
- escape_url,
- expand_path,
- extract_attributes,
- ExtractorError,
- find_xpath_attr,
- fix_xml_ampersands,
- float_or_none,
- get_element_by_class,
- get_element_by_attribute,
- get_elements_by_class,
- get_elements_by_attribute,
- InAdvancePagedList,
- int_or_none,
- intlist_to_bytes,
- is_html,
- join_nonempty,
- js_to_json,
- LazyList,
- limit_length,
- lowercase_escape,
- merge_dicts,
- mimetype2ext,
- month_by_name,
- multipart_encode,
- ohdave_rsa_encrypt,
- OnDemandPagedList,
- orderedSet,
- parse_age_limit,
- parse_bitrate,
- parse_duration,
- parse_filesize,
- parse_codecs,
- parse_count,
- parse_iso8601,
- parse_resolution,
- parse_qs,
- pkcs1pad,
- prepend_extension,
- read_batch_urls,
- remove_start,
- remove_end,
- remove_quotes,
- replace_extension,
- rot47,
- sanitize_filename,
- sanitize_path,
- sanitize_url,
- sanitized_Request,
- shell_quote,
- smuggle_url,
- str_to_int,
- strip_jsonp,
- strip_or_none,
- subtitles_filename,
- timeconvert,
- try_call,
- unescapeHTML,
- unified_strdate,
- unified_timestamp,
- unsmuggle_url,
- uppercase_escape,
- url_basename,
- url_or_none,
- urljoin,
- urlencode_postdata,
- urshift,
- update_url_query,
- variadic,
- version_tuple,
- xpath_with_ns,
- xpath_element,
- xpath_text,
- xpath_attr,
- render_table,
- match_str,
- parse_dfxp_time_expr,
- dfxp2srt,
- cli_option,
- cli_valueless_option,
- cli_bool_option,
- YoutubeDLHandler,
-)
-from youtube_dl.compat import (
- compat_chr,
- compat_etree_fromstring,
- compat_getenv,
- compat_os_name,
- compat_setenv,
- compat_str,
- compat_urlparse,
-)
-
-
-class TestUtil(unittest.TestCase):
-
- def test_timeconvert(self):
- self.assertTrue(timeconvert('') is None)
- self.assertTrue(timeconvert('bougrg') is None)
-
- def test_sanitize_filename(self):
- self.assertEqual(sanitize_filename('abc'), 'abc')
- self.assertEqual(sanitize_filename('abc_d-e'), 'abc_d-e')
-
- self.assertEqual(sanitize_filename('123'), '123')
-
- self.assertEqual('abc_de', sanitize_filename('abc/de'))
- self.assertFalse('/' in sanitize_filename('abc/de///'))
-
- self.assertEqual('abc_de', sanitize_filename('abc/<>\\*|de'))
- self.assertEqual('xxx', sanitize_filename('xxx/<>\\*|'))
- self.assertEqual('yes no', sanitize_filename('yes? no'))
- self.assertEqual('this - that', sanitize_filename('this: that'))
-
- self.assertEqual(sanitize_filename('AT&T'), 'AT&T')
- aumlaut = 'ä'
- self.assertEqual(sanitize_filename(aumlaut), aumlaut)
- tests = '\u043a\u0438\u0440\u0438\u043b\u043b\u0438\u0446\u0430'
- self.assertEqual(sanitize_filename(tests), tests)
-
- self.assertEqual(
- sanitize_filename('New World record at 0:12:34'),
- 'New World record at 0_12_34')
-
- self.assertEqual(sanitize_filename('--gasdgf'), '_-gasdgf')
- self.assertEqual(sanitize_filename('--gasdgf', is_id=True), '--gasdgf')
- self.assertEqual(sanitize_filename('.gasdgf'), 'gasdgf')
- self.assertEqual(sanitize_filename('.gasdgf', is_id=True), '.gasdgf')
-
- forbidden = '"\0\\/'
- for fc in forbidden:
- for fbc in forbidden:
- self.assertTrue(fbc not in sanitize_filename(fc))
-
- def test_sanitize_filename_restricted(self):
- self.assertEqual(sanitize_filename('abc', restricted=True), 'abc')
- self.assertEqual(sanitize_filename('abc_d-e', restricted=True), 'abc_d-e')
-
- self.assertEqual(sanitize_filename('123', restricted=True), '123')
-
- self.assertEqual('abc_de', sanitize_filename('abc/de', restricted=True))
- self.assertFalse('/' in sanitize_filename('abc/de///', restricted=True))
-
- self.assertEqual('abc_de', sanitize_filename('abc/<>\\*|de', restricted=True))
- self.assertEqual('xxx', sanitize_filename('xxx/<>\\*|', restricted=True))
- self.assertEqual('yes_no', sanitize_filename('yes? no', restricted=True))
- self.assertEqual('this_-_that', sanitize_filename('this: that', restricted=True))
-
- tests = 'aäb\u4e2d\u56fd\u7684c'
- self.assertEqual(sanitize_filename(tests, restricted=True), 'aab_c')
- self.assertTrue(sanitize_filename('\xf6', restricted=True) != '') # No empty filename
-
- forbidden = '"\0\\/&!: \'\t\n()[]{}$;`^,#'
- for fc in forbidden:
- for fbc in forbidden:
- self.assertTrue(fbc not in sanitize_filename(fc, restricted=True))
-
- # Handle a common case more neatly
- self.assertEqual(sanitize_filename('\u5927\u58f0\u5e26 - Song', restricted=True), 'Song')
- self.assertEqual(sanitize_filename('\u603b\u7edf: Speech', restricted=True), 'Speech')
- # .. but make sure the file name is never empty
- self.assertTrue(sanitize_filename('-', restricted=True) != '')
- self.assertTrue(sanitize_filename(':', restricted=True) != '')
-
- self.assertEqual(sanitize_filename(
- 'ÂÃÄÀÁÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖŐØŒÙÚÛÜŰÝÞßàáâãäåæçèéêëìíîïðñòóôõöőøœùúûüűýþÿ', restricted=True),
- 'AAAAAAAECEEEEIIIIDNOOOOOOOOEUUUUUYTHssaaaaaaaeceeeeiiiionooooooooeuuuuuythy')
-
- def test_sanitize_ids(self):
- self.assertEqual(sanitize_filename('_n_cd26wFpw', is_id=True), '_n_cd26wFpw')
- self.assertEqual(sanitize_filename('_BD_eEpuzXw', is_id=True), '_BD_eEpuzXw')
- self.assertEqual(sanitize_filename('N0Y__7-UOdI', is_id=True), 'N0Y__7-UOdI')
-
- def test_sanitize_path(self):
- if sys.platform != 'win32':
- return
-
- self.assertEqual(sanitize_path('abc'), 'abc')
- self.assertEqual(sanitize_path('abc/def'), 'abc\\def')
- self.assertEqual(sanitize_path('abc\\def'), 'abc\\def')
- self.assertEqual(sanitize_path('abc|def'), 'abc#def')
- self.assertEqual(sanitize_path('<>:"|?*'), '#######')
- self.assertEqual(sanitize_path('C:/abc/def'), 'C:\\abc\\def')
- self.assertEqual(sanitize_path('C?:/abc/def'), 'C##\\abc\\def')
-
- self.assertEqual(sanitize_path('\\\\?\\UNC\\ComputerName\\abc'), '\\\\?\\UNC\\ComputerName\\abc')
- self.assertEqual(sanitize_path('\\\\?\\UNC/ComputerName/abc'), '\\\\?\\UNC\\ComputerName\\abc')
-
- self.assertEqual(sanitize_path('\\\\?\\C:\\abc'), '\\\\?\\C:\\abc')
- self.assertEqual(sanitize_path('\\\\?\\C:/abc'), '\\\\?\\C:\\abc')
- self.assertEqual(sanitize_path('\\\\?\\C:\\ab?c\\de:f'), '\\\\?\\C:\\ab#c\\de#f')
- self.assertEqual(sanitize_path('\\\\?\\C:\\abc'), '\\\\?\\C:\\abc')
-
- self.assertEqual(
- sanitize_path('youtube/%(uploader)s/%(autonumber)s-%(title)s-%(upload_date)s.%(ext)s'),
- 'youtube\\%(uploader)s\\%(autonumber)s-%(title)s-%(upload_date)s.%(ext)s')
-
- self.assertEqual(
- sanitize_path('youtube/TheWreckingYard ./00001-Not bad, Especially for Free! (1987 Yamaha 700)-20141116.mp4.part'),
- 'youtube\\TheWreckingYard #\\00001-Not bad, Especially for Free! (1987 Yamaha 700)-20141116.mp4.part')
- self.assertEqual(sanitize_path('abc/def...'), 'abc\\def..#')
- self.assertEqual(sanitize_path('abc.../def'), 'abc..#\\def')
- self.assertEqual(sanitize_path('abc.../def...'), 'abc..#\\def..#')
-
- self.assertEqual(sanitize_path('../abc'), '..\\abc')
- self.assertEqual(sanitize_path('../../abc'), '..\\..\\abc')
- self.assertEqual(sanitize_path('./abc'), 'abc')
- self.assertEqual(sanitize_path('./../abc'), '..\\abc')
-
- def test_sanitize_url(self):
- self.assertEqual(sanitize_url('//foo.bar'), 'http://foo.bar')
- self.assertEqual(sanitize_url('httpss://foo.bar'), 'https://foo.bar')
- self.assertEqual(sanitize_url('rmtps://foo.bar'), 'rtmps://foo.bar')
- self.assertEqual(sanitize_url('https://foo.bar'), 'https://foo.bar')
- self.assertEqual(sanitize_url('foo bar'), 'foo bar')
-
- def test_sanitized_Request(self):
- self.assertFalse(sanitized_Request('http://foo.bar').has_header('Authorization'))
- self.assertFalse(sanitized_Request('http://:foo.bar').has_header('Authorization'))
- self.assertEqual(sanitized_Request('http://@foo.bar').get_header('Authorization'),
- 'Basic Og==')
- self.assertEqual(sanitized_Request('http://:pass@foo.bar').get_header('Authorization'),
- 'Basic OnBhc3M=')
- self.assertEqual(sanitized_Request('http://user:@foo.bar').get_header('Authorization'),
- 'Basic dXNlcjo=')
- self.assertEqual(sanitized_Request('http://user:pass@foo.bar').get_header('Authorization'),
- 'Basic dXNlcjpwYXNz')
-
- def test_expand_path(self):
- def env(var):
- return '%{0}%'.format(var) if sys.platform == 'win32' else '${0}'.format(var)
-
- compat_setenv('YOUTUBE_DL_EXPATH_PATH', 'expanded')
- self.assertEqual(expand_path(env('YOUTUBE_DL_EXPATH_PATH')), 'expanded')
- self.assertEqual(expand_path(env('HOME')), compat_getenv('HOME'))
- self.assertEqual(expand_path('~'), compat_getenv('HOME'))
- self.assertEqual(
- expand_path('~/%s' % env('YOUTUBE_DL_EXPATH_PATH')),
- '%s/expanded' % compat_getenv('HOME'))
-
- _uncommon_extensions = [
- ('exe', 'abc.exe.ext'),
- ('de', 'abc.de.ext'),
- ('../.mp4', None),
- ('..\\.mp4', None),
- ]
-
- def assertUnsafeExtension(self, ext=None):
- assert_raises = self.assertRaises(_UnsafeExtensionError)
- assert_raises.ext = ext
- orig_exit = assert_raises.__exit__
-
- def my_exit(self_, exc_type, exc_val, exc_tb):
- did_raise = orig_exit(exc_type, exc_val, exc_tb)
- if did_raise and assert_raises.ext is not None:
- self.assertEqual(assert_raises.ext, assert_raises.exception.extension, 'Unsafe extension not as unexpected')
- return did_raise
-
- assert_raises.__exit__ = types.MethodType(my_exit, assert_raises)
- return assert_raises
-
- def test_prepend_extension(self):
- self.assertEqual(prepend_extension('abc.ext', 'temp'), 'abc.temp.ext')
- self.assertEqual(prepend_extension('abc.ext', 'temp', 'ext'), 'abc.temp.ext')
- self.assertEqual(prepend_extension('abc.unexpected_ext', 'temp', 'ext'), 'abc.unexpected_ext.temp')
- self.assertEqual(prepend_extension('abc', 'temp'), 'abc.temp')
- self.assertEqual(prepend_extension('.abc', 'temp'), '.abc.temp')
- self.assertEqual(prepend_extension('.abc.ext', 'temp'), '.abc.temp.ext')
-
- # Test uncommon extensions
- self.assertEqual(prepend_extension('abc.ext', 'bin'), 'abc.bin.ext')
- for ext, result in self._uncommon_extensions:
- with self.assertUnsafeExtension(ext):
- prepend_extension('abc', ext)
- if result:
- self.assertEqual(prepend_extension('abc.ext', ext, 'ext'), result)
- else:
- with self.assertUnsafeExtension(ext):
- prepend_extension('abc.ext', ext, 'ext')
- with self.assertUnsafeExtension(ext):
- prepend_extension('abc.unexpected_ext', ext, 'ext')
-
- def test_replace_extension(self):
- self.assertEqual(replace_extension('abc.ext', 'temp'), 'abc.temp')
- self.assertEqual(replace_extension('abc.ext', 'temp', 'ext'), 'abc.temp')
- self.assertEqual(replace_extension('abc.unexpected_ext', 'temp', 'ext'), 'abc.unexpected_ext.temp')
- self.assertEqual(replace_extension('abc', 'temp'), 'abc.temp')
- self.assertEqual(replace_extension('.abc', 'temp'), '.abc.temp')
- self.assertEqual(replace_extension('.abc.ext', 'temp'), '.abc.temp')
-
- # Test uncommon extensions
- self.assertEqual(replace_extension('abc.ext', 'bin'), 'abc.unknown_video')
- for ext, _ in self._uncommon_extensions:
- with self.assertUnsafeExtension(ext):
- replace_extension('abc', ext)
- with self.assertUnsafeExtension(ext):
- replace_extension('abc.ext', ext, 'ext')
- with self.assertUnsafeExtension(ext):
- replace_extension('abc.unexpected_ext', ext, 'ext')
-
- def test_subtitles_filename(self):
- self.assertEqual(subtitles_filename('abc.ext', 'en', 'vtt'), 'abc.en.vtt')
- self.assertEqual(subtitles_filename('abc.ext', 'en', 'vtt', 'ext'), 'abc.en.vtt')
- self.assertEqual(subtitles_filename('abc.unexpected_ext', 'en', 'vtt', 'ext'), 'abc.unexpected_ext.en.vtt')
-
- def test_remove_start(self):
- self.assertEqual(remove_start(None, 'A - '), None)
- self.assertEqual(remove_start('A - B', 'A - '), 'B')
- self.assertEqual(remove_start('B - A', 'A - '), 'B - A')
-
- def test_remove_end(self):
- self.assertEqual(remove_end(None, ' - B'), None)
- self.assertEqual(remove_end('A - B', ' - B'), 'A')
- self.assertEqual(remove_end('B - A', ' - B'), 'B - A')
-
- def test_remove_quotes(self):
- self.assertEqual(remove_quotes(None), None)
- self.assertEqual(remove_quotes('"'), '"')
- self.assertEqual(remove_quotes("'"), "'")
- self.assertEqual(remove_quotes(';'), ';')
- self.assertEqual(remove_quotes('";'), '";')
- self.assertEqual(remove_quotes('""'), '')
- self.assertEqual(remove_quotes('";"'), ';')
-
- def test_ordered_set(self):
- self.assertEqual(orderedSet([1, 1, 2, 3, 4, 4, 5, 6, 7, 3, 5]), [1, 2, 3, 4, 5, 6, 7])
- self.assertEqual(orderedSet([]), [])
- self.assertEqual(orderedSet([1]), [1])
- # keep the list ordered
- self.assertEqual(orderedSet([135, 1, 1, 1]), [135, 1])
-
- def test_unescape_html(self):
- self.assertEqual(unescapeHTML('%20;'), '%20;')
- self.assertEqual(unescapeHTML('/'), '/')
- self.assertEqual(unescapeHTML('/'), '/')
- self.assertEqual(unescapeHTML('é'), 'é')
- self.assertEqual(unescapeHTML(''), '')
- self.assertEqual(unescapeHTML('&a"'), '&a"')
- # HTML5 entities
- self.assertEqual(unescapeHTML('.''), '.\'')
-
- def test_date_from_str(self):
- self.assertEqual(date_from_str('yesterday'), date_from_str('now-1day'))
- self.assertEqual(date_from_str('now+7day'), date_from_str('now+1week'))
- self.assertEqual(date_from_str('now+14day'), date_from_str('now+2week'))
- self.assertEqual(date_from_str('now+365day'), date_from_str('now+1year'))
- self.assertEqual(date_from_str('now+30day'), date_from_str('now+1month'))
-
- def test_daterange(self):
- _20century = DateRange("19000101", "20000101")
- self.assertFalse("17890714" in _20century)
- _ac = DateRange("00010101")
- self.assertTrue("19690721" in _ac)
- _firstmilenium = DateRange(end="10000101")
- self.assertTrue("07110427" in _firstmilenium)
-
- def test_unified_dates(self):
- self.assertEqual(unified_strdate('December 21, 2010'), '20101221')
- self.assertEqual(unified_strdate('8/7/2009'), '20090708')
- self.assertEqual(unified_strdate('Dec 14, 2012'), '20121214')
- self.assertEqual(unified_strdate('2012/10/11 01:56:38 +0000'), '20121011')
- self.assertEqual(unified_strdate('1968 12 10'), '19681210')
- self.assertEqual(unified_strdate('1968-12-10'), '19681210')
- self.assertEqual(unified_strdate('28/01/2014 21:00:00 +0100'), '20140128')
- self.assertEqual(
- unified_strdate('11/26/2014 11:30:00 AM PST', day_first=False),
- '20141126')
- self.assertEqual(
- unified_strdate('2/2/2015 6:47:40 PM', day_first=False),
- '20150202')
- self.assertEqual(unified_strdate('Feb 14th 2016 5:45PM'), '20160214')
- self.assertEqual(unified_strdate('25-09-2014'), '20140925')
- self.assertEqual(unified_strdate('27.02.2016 17:30'), '20160227')
- self.assertEqual(unified_strdate('UNKNOWN DATE FORMAT'), None)
- self.assertEqual(unified_strdate('Feb 7, 2016 at 6:35 pm'), '20160207')
- self.assertEqual(unified_strdate('July 15th, 2013'), '20130715')
- self.assertEqual(unified_strdate('September 1st, 2013'), '20130901')
- self.assertEqual(unified_strdate('Sep 2nd, 2013'), '20130902')
- self.assertEqual(unified_strdate('November 3rd, 2019'), '20191103')
- self.assertEqual(unified_strdate('October 23rd, 2005'), '20051023')
-
- def test_unified_timestamps(self):
- self.assertEqual(unified_timestamp('December 21, 2010'), 1292889600)
- self.assertEqual(unified_timestamp('8/7/2009'), 1247011200)
- self.assertEqual(unified_timestamp('Dec 14, 2012'), 1355443200)
- self.assertEqual(unified_timestamp('2012/10/11 01:56:38 +0000'), 1349920598)
- self.assertEqual(unified_timestamp('1968 12 10'), -33436800)
- self.assertEqual(unified_timestamp('1968-12-10'), -33436800)
- self.assertEqual(unified_timestamp('28/01/2014 21:00:00 +0100'), 1390939200)
- self.assertEqual(
- unified_timestamp('11/26/2014 11:30:00 AM PST', day_first=False),
- 1417001400)
- self.assertEqual(
- unified_timestamp('2/2/2015 6:47:40 PM', day_first=False),
- 1422902860)
- self.assertEqual(unified_timestamp('Feb 14th 2016 5:45PM'), 1455471900)
- self.assertEqual(unified_timestamp('25-09-2014'), 1411603200)
- self.assertEqual(unified_timestamp('27.02.2016 17:30'), 1456594200)
- self.assertEqual(unified_timestamp('UNKNOWN DATE FORMAT'), None)
- self.assertEqual(unified_timestamp('May 16, 2016 11:15 PM'), 1463440500)
- self.assertEqual(unified_timestamp('Feb 7, 2016 at 6:35 pm'), 1454870100)
- self.assertEqual(unified_timestamp('2017-03-30T17:52:41Q'), 1490896361)
- self.assertEqual(unified_timestamp('Sep 11, 2013 | 5:49 AM'), 1378878540)
- self.assertEqual(unified_timestamp('December 15, 2017 at 7:49 am'), 1513324140)
- self.assertEqual(unified_timestamp('2018-03-14T08:32:43.1493874+00:00'), 1521016363)
- self.assertEqual(unified_timestamp('December 31 1969 20:00:01 EDT'), 1)
- self.assertEqual(unified_timestamp('Wednesday 31 December 1969 18:01:26 MDT'), 86)
- self.assertEqual(unified_timestamp('12/31/1969 20:01:18 EDT', False), 78)
-
- def test_determine_ext(self):
- self.assertEqual(determine_ext('http://example.com/foo/bar.mp4/?download'), 'mp4')
- self.assertEqual(determine_ext('http://example.com/foo/bar/?download', None), None)
- self.assertEqual(determine_ext('http://example.com/foo/bar.nonext/?download', None), None)
- self.assertEqual(determine_ext('http://example.com/foo/bar/mp4?download', None), None)
- self.assertEqual(determine_ext('http://example.com/foo/bar.m3u8//?download'), 'm3u8')
- self.assertEqual(determine_ext('foobar', None), None)
-
- def test_find_xpath_attr(self):
- testxml = '''
-
-
-
-
-
- '''
- doc = compat_etree_fromstring(testxml)
-
- self.assertEqual(find_xpath_attr(doc, './/fourohfour', 'n'), None)
- self.assertEqual(find_xpath_attr(doc, './/fourohfour', 'n', 'v'), None)
- self.assertEqual(find_xpath_attr(doc, './/node', 'n'), None)
- self.assertEqual(find_xpath_attr(doc, './/node', 'n', 'v'), None)
- self.assertEqual(find_xpath_attr(doc, './/node', 'x'), doc[1])
- self.assertEqual(find_xpath_attr(doc, './/node', 'x', 'a'), doc[1])
- self.assertEqual(find_xpath_attr(doc, './/node', 'x', 'b'), doc[3])
- self.assertEqual(find_xpath_attr(doc, './/node', 'y'), doc[2])
- self.assertEqual(find_xpath_attr(doc, './/node', 'y', 'c'), doc[2])
- self.assertEqual(find_xpath_attr(doc, './/node', 'y', 'd'), doc[3])
- self.assertEqual(find_xpath_attr(doc, './/node', 'x', ''), doc[4])
-
- def test_xpath_with_ns(self):
- testxml = '''
-
- The Author
- http://server.com/download.mp3
-
- '''
- doc = compat_etree_fromstring(testxml)
- find = lambda p: doc.find(xpath_with_ns(p, {'media': 'http://example.com/'}))
- self.assertTrue(find('media:song') is not None)
- self.assertEqual(find('media:song/media:author').text, 'The Author')
- self.assertEqual(find('media:song/url').text, 'http://server.com/download.mp3')
-
- def test_xpath_element(self):
- doc = xml.etree.ElementTree.Element('root')
- div = xml.etree.ElementTree.SubElement(doc, 'div')
- p = xml.etree.ElementTree.SubElement(div, 'p')
- p.text = 'Foo'
- self.assertEqual(xpath_element(doc, 'div/p'), p)
- self.assertEqual(xpath_element(doc, ['div/p']), p)
- self.assertEqual(xpath_element(doc, ['div/bar', 'div/p']), p)
- self.assertEqual(xpath_element(doc, 'div/bar', default='default'), 'default')
- self.assertEqual(xpath_element(doc, ['div/bar'], default='default'), 'default')
- self.assertTrue(xpath_element(doc, 'div/bar') is None)
- self.assertTrue(xpath_element(doc, ['div/bar']) is None)
- self.assertTrue(xpath_element(doc, ['div/bar'], 'div/baz') is None)
- self.assertRaises(ExtractorError, xpath_element, doc, 'div/bar', fatal=True)
- self.assertRaises(ExtractorError, xpath_element, doc, ['div/bar'], fatal=True)
- self.assertRaises(ExtractorError, xpath_element, doc, ['div/bar', 'div/baz'], fatal=True)
-
- def test_xpath_text(self):
- testxml = '''
-
- '''
- doc = compat_etree_fromstring(testxml)
- self.assertEqual(xpath_text(doc, 'div/p'), 'Foo')
- self.assertEqual(xpath_text(doc, 'div/bar', default='default'), 'default')
- self.assertTrue(xpath_text(doc, 'div/bar') is None)
- self.assertRaises(ExtractorError, xpath_text, doc, 'div/bar', fatal=True)
-
- def test_xpath_attr(self):
- testxml = '''
-
- '''
- doc = compat_etree_fromstring(testxml)
- self.assertEqual(xpath_attr(doc, 'div/p', 'x'), 'a')
- self.assertEqual(xpath_attr(doc, 'div/bar', 'x'), None)
- self.assertEqual(xpath_attr(doc, 'div/p', 'y'), None)
- self.assertEqual(xpath_attr(doc, 'div/bar', 'x', default='default'), 'default')
- self.assertEqual(xpath_attr(doc, 'div/p', 'y', default='default'), 'default')
- self.assertRaises(ExtractorError, xpath_attr, doc, 'div/bar', 'x', fatal=True)
- self.assertRaises(ExtractorError, xpath_attr, doc, 'div/p', 'y', fatal=True)
-
- def test_smuggle_url(self):
- data = {"ö": "ö", "abc": [3]}
- url = 'https://foo.bar/baz?x=y#a'
- smug_url = smuggle_url(url, data)
- unsmug_url, unsmug_data = unsmuggle_url(smug_url)
- self.assertEqual(url, unsmug_url)
- self.assertEqual(data, unsmug_data)
-
- res_url, res_data = unsmuggle_url(url)
- self.assertEqual(res_url, url)
- self.assertEqual(res_data, None)
-
- smug_url = smuggle_url(url, {'a': 'b'})
- smug_smug_url = smuggle_url(smug_url, {'c': 'd'})
- res_url, res_data = unsmuggle_url(smug_smug_url)
- self.assertEqual(res_url, url)
- self.assertEqual(res_data, {'a': 'b', 'c': 'd'})
-
- def test_shell_quote(self):
- args = ['ffmpeg', '-i', encodeFilename('ñ€ß\'.mp4')]
- self.assertEqual(
- shell_quote(args),
- """ffmpeg -i 'ñ€ß'"'"'.mp4'""" if compat_os_name != 'nt' else '''ffmpeg -i "ñ€ß'.mp4"''')
-
- def test_float_or_none(self):
- self.assertEqual(float_or_none('42.42'), 42.42)
- self.assertEqual(float_or_none('42'), 42.0)
- self.assertEqual(float_or_none(''), None)
- self.assertEqual(float_or_none(None), None)
- self.assertEqual(float_or_none([]), None)
- self.assertEqual(float_or_none(set()), None)
-
- def test_int_or_none(self):
- self.assertEqual(int_or_none(42), 42)
- self.assertEqual(int_or_none('42'), 42)
- self.assertEqual(int_or_none(''), None)
- self.assertEqual(int_or_none(None), None)
- self.assertEqual(int_or_none([]), None)
- self.assertEqual(int_or_none(set()), None)
- self.assertEqual(int_or_none('42', base=8), 34)
- self.assertRaises(TypeError, int_or_none(42, base=8))
-
- def test_str_to_int(self):
- self.assertEqual(str_to_int('123,456'), 123456)
- self.assertEqual(str_to_int('123.456'), 123456)
- self.assertEqual(str_to_int(523), 523)
- # Python 3 has no long
- if sys.version_info < (3, 0):
- eval('self.assertEqual(str_to_int(123456L), 123456)')
- self.assertEqual(str_to_int('noninteger'), None)
- self.assertEqual(str_to_int([]), None)
-
- def test_url_basename(self):
- self.assertEqual(url_basename('http://foo.de/'), '')
- self.assertEqual(url_basename('http://foo.de/bar/baz'), 'baz')
- self.assertEqual(url_basename('http://foo.de/bar/baz?x=y'), 'baz')
- self.assertEqual(url_basename('http://foo.de/bar/baz#x=y'), 'baz')
- self.assertEqual(url_basename('http://foo.de/bar/baz/'), 'baz')
- self.assertEqual(
- url_basename('http://media.w3.org/2010/05/sintel/trailer.mp4'),
- 'trailer.mp4')
-
- def test_base_url(self):
- self.assertEqual(base_url('http://foo.de/'), 'http://foo.de/')
- self.assertEqual(base_url('http://foo.de/bar'), 'http://foo.de/')
- self.assertEqual(base_url('http://foo.de/bar/'), 'http://foo.de/bar/')
- self.assertEqual(base_url('http://foo.de/bar/baz'), 'http://foo.de/bar/')
- self.assertEqual(base_url('http://foo.de/bar/baz?x=z/x/c'), 'http://foo.de/bar/')
-
- def test_urljoin(self):
- self.assertEqual(urljoin('http://foo.de/', '/a/b/c.txt'), 'http://foo.de/a/b/c.txt')
- self.assertEqual(urljoin(b'http://foo.de/', '/a/b/c.txt'), 'http://foo.de/a/b/c.txt')
- self.assertEqual(urljoin('http://foo.de/', b'/a/b/c.txt'), 'http://foo.de/a/b/c.txt')
- self.assertEqual(urljoin(b'http://foo.de/', b'/a/b/c.txt'), 'http://foo.de/a/b/c.txt')
- self.assertEqual(urljoin('//foo.de/', '/a/b/c.txt'), '//foo.de/a/b/c.txt')
- self.assertEqual(urljoin('http://foo.de/', 'a/b/c.txt'), 'http://foo.de/a/b/c.txt')
- self.assertEqual(urljoin('http://foo.de', '/a/b/c.txt'), 'http://foo.de/a/b/c.txt')
- self.assertEqual(urljoin('http://foo.de', 'a/b/c.txt'), 'http://foo.de/a/b/c.txt')
- self.assertEqual(urljoin('http://foo.de/', 'http://foo.de/a/b/c.txt'), 'http://foo.de/a/b/c.txt')
- self.assertEqual(urljoin('http://foo.de/', '//foo.de/a/b/c.txt'), '//foo.de/a/b/c.txt')
- self.assertEqual(urljoin(None, 'http://foo.de/a/b/c.txt'), 'http://foo.de/a/b/c.txt')
- self.assertEqual(urljoin(None, '//foo.de/a/b/c.txt'), '//foo.de/a/b/c.txt')
- self.assertEqual(urljoin('', 'http://foo.de/a/b/c.txt'), 'http://foo.de/a/b/c.txt')
- self.assertEqual(urljoin(['foobar'], 'http://foo.de/a/b/c.txt'), 'http://foo.de/a/b/c.txt')
- self.assertEqual(urljoin('http://foo.de/', None), None)
- self.assertEqual(urljoin('http://foo.de/', ''), None)
- self.assertEqual(urljoin('http://foo.de/', ['foobar']), None)
- self.assertEqual(urljoin('http://foo.de/a/b/c.txt', '.././../d.txt'), 'http://foo.de/d.txt')
- self.assertEqual(urljoin('http://foo.de/a/b/c.txt', 'rtmp://foo.de'), 'rtmp://foo.de')
- self.assertEqual(urljoin(None, 'rtmp://foo.de'), 'rtmp://foo.de')
-
- def test_url_or_none(self):
- self.assertEqual(url_or_none(None), None)
- self.assertEqual(url_or_none(''), None)
- self.assertEqual(url_or_none('foo'), None)
- self.assertEqual(url_or_none('http://foo.de'), 'http://foo.de')
- self.assertEqual(url_or_none('https://foo.de'), 'https://foo.de')
- self.assertEqual(url_or_none('http$://foo.de'), None)
- self.assertEqual(url_or_none('http://foo.de'), 'http://foo.de')
- self.assertEqual(url_or_none('//foo.de'), '//foo.de')
- self.assertEqual(url_or_none('s3://foo.de'), None)
- self.assertEqual(url_or_none('rtmpte://foo.de'), 'rtmpte://foo.de')
- self.assertEqual(url_or_none('mms://foo.de'), 'mms://foo.de')
- self.assertEqual(url_or_none('rtspu://foo.de'), 'rtspu://foo.de')
- self.assertEqual(url_or_none('ftps://foo.de'), 'ftps://foo.de')
-
- def test_parse_age_limit(self):
- self.assertEqual(parse_age_limit(None), None)
- self.assertEqual(parse_age_limit(False), None)
- self.assertEqual(parse_age_limit('invalid'), None)
- self.assertEqual(parse_age_limit(0), 0)
- self.assertEqual(parse_age_limit(18), 18)
- self.assertEqual(parse_age_limit(21), 21)
- self.assertEqual(parse_age_limit(22), None)
- self.assertEqual(parse_age_limit('18'), 18)
- self.assertEqual(parse_age_limit('18+'), 18)
- self.assertEqual(parse_age_limit('PG-13'), 13)
- self.assertEqual(parse_age_limit('TV-14'), 14)
- self.assertEqual(parse_age_limit('TV-MA'), 17)
- self.assertEqual(parse_age_limit('TV14'), 14)
- self.assertEqual(parse_age_limit('TV_G'), 0)
-
- def test_parse_duration(self):
- self.assertEqual(parse_duration(None), None)
- self.assertEqual(parse_duration(False), None)
- self.assertEqual(parse_duration('invalid'), None)
- self.assertEqual(parse_duration('1'), 1)
- self.assertEqual(parse_duration('1337:12'), 80232)
- self.assertEqual(parse_duration('9:12:43'), 33163)
- self.assertEqual(parse_duration('12:00'), 720)
- self.assertEqual(parse_duration('00:01:01'), 61)
- self.assertEqual(parse_duration('x:y'), None)
- self.assertEqual(parse_duration('3h11m53s'), 11513)
- self.assertEqual(parse_duration('3h 11m 53s'), 11513)
- self.assertEqual(parse_duration('3 hours 11 minutes 53 seconds'), 11513)
- self.assertEqual(parse_duration('3 hours 11 mins 53 secs'), 11513)
- self.assertEqual(parse_duration('62m45s'), 3765)
- self.assertEqual(parse_duration('6m59s'), 419)
- self.assertEqual(parse_duration('49s'), 49)
- self.assertEqual(parse_duration('0h0m0s'), 0)
- self.assertEqual(parse_duration('0m0s'), 0)
- self.assertEqual(parse_duration('0s'), 0)
- self.assertEqual(parse_duration('01:02:03.05'), 3723.05)
- self.assertEqual(parse_duration('T30M38S'), 1838)
- self.assertEqual(parse_duration('5 s'), 5)
- self.assertEqual(parse_duration('3 min'), 180)
- self.assertEqual(parse_duration('2.5 hours'), 9000)
- self.assertEqual(parse_duration('02:03:04'), 7384)
- self.assertEqual(parse_duration('01:02:03:04'), 93784)
- self.assertEqual(parse_duration('1 hour 3 minutes'), 3780)
- self.assertEqual(parse_duration('87 Min.'), 5220)
- self.assertEqual(parse_duration('PT1H0.040S'), 3600.04)
- self.assertEqual(parse_duration('PT00H03M30SZ'), 210)
- self.assertEqual(parse_duration('P0Y0M0DT0H4M20.880S'), 260.88)
-
- def test_fix_xml_ampersands(self):
- self.assertEqual(
- fix_xml_ampersands('"&x=y&z=a'), '"&x=y&z=a')
- self.assertEqual(
- fix_xml_ampersands('"&x=y&wrong;&z=a'),
- '"&x=y&wrong;&z=a')
- self.assertEqual(
- fix_xml_ampersands('&'><"'),
- '&'><"')
- self.assertEqual(
- fix_xml_ampersands('Ӓ᪼'), 'Ӓ᪼')
- self.assertEqual(fix_xml_ampersands(''), '&#&#')
-
- def test_paged_list(self):
- def testPL(size, pagesize, sliceargs, expected):
- def get_page(pagenum):
- firstid = pagenum * pagesize
- upto = min(size, pagenum * pagesize + pagesize)
- for i in range(firstid, upto):
- yield i
-
- pl = OnDemandPagedList(get_page, pagesize)
- got = pl.getslice(*sliceargs)
- self.assertEqual(got, expected)
-
- iapl = InAdvancePagedList(get_page, size // pagesize + 1, pagesize)
- got = iapl.getslice(*sliceargs)
- self.assertEqual(got, expected)
-
- testPL(5, 2, (), [0, 1, 2, 3, 4])
- testPL(5, 2, (1,), [1, 2, 3, 4])
- testPL(5, 2, (2,), [2, 3, 4])
- testPL(5, 2, (4,), [4])
- testPL(5, 2, (0, 3), [0, 1, 2])
- testPL(5, 2, (1, 4), [1, 2, 3])
- testPL(5, 2, (2, 99), [2, 3, 4])
- testPL(5, 2, (20, 99), [])
-
- def test_read_batch_urls(self):
- f = io.StringIO('''\xef\xbb\xbf foo
- bar\r
- baz
- # More after this line\r
- ; or after this
- bam''')
- self.assertEqual(read_batch_urls(f), ['foo', 'bar', 'baz', 'bam'])
-
- def test_urlencode_postdata(self):
- data = urlencode_postdata({'username': 'foo@bar.com', 'password': '1234'})
- self.assertTrue(isinstance(data, bytes))
-
- def test_update_url_query(self):
- self.assertEqual(parse_qs(update_url_query(
- 'http://example.com/path', {'quality': ['HD'], 'format': ['mp4']})),
- parse_qs('http://example.com/path?quality=HD&format=mp4'))
- self.assertEqual(parse_qs(update_url_query(
- 'http://example.com/path', {'system': ['LINUX', 'WINDOWS']})),
- parse_qs('http://example.com/path?system=LINUX&system=WINDOWS'))
- self.assertEqual(parse_qs(update_url_query(
- 'http://example.com/path', {'fields': 'id,formats,subtitles'})),
- parse_qs('http://example.com/path?fields=id,formats,subtitles'))
- self.assertEqual(parse_qs(update_url_query(
- 'http://example.com/path', {'fields': ('id,formats,subtitles', 'thumbnails')})),
- parse_qs('http://example.com/path?fields=id,formats,subtitles&fields=thumbnails'))
- self.assertEqual(parse_qs(update_url_query(
- 'http://example.com/path?manifest=f4m', {'manifest': []})),
- parse_qs('http://example.com/path'))
- self.assertEqual(parse_qs(update_url_query(
- 'http://example.com/path?system=LINUX&system=WINDOWS', {'system': 'LINUX'})),
- parse_qs('http://example.com/path?system=LINUX'))
- self.assertEqual(parse_qs(update_url_query(
- 'http://example.com/path', {'fields': b'id,formats,subtitles'})),
- parse_qs('http://example.com/path?fields=id,formats,subtitles'))
- self.assertEqual(parse_qs(update_url_query(
- 'http://example.com/path', {'width': 1080, 'height': 720})),
- parse_qs('http://example.com/path?width=1080&height=720'))
- self.assertEqual(parse_qs(update_url_query(
- 'http://example.com/path', {'bitrate': 5020.43})),
- parse_qs('http://example.com/path?bitrate=5020.43'))
- self.assertEqual(parse_qs(update_url_query(
- 'http://example.com/path', {'test': '第二行тест'})),
- parse_qs('http://example.com/path?test=%E7%AC%AC%E4%BA%8C%E8%A1%8C%D1%82%D0%B5%D1%81%D1%82'))
-
- def test_multipart_encode(self):
- self.assertEqual(
- multipart_encode({b'field': b'value'}, boundary='AAAAAA')[0],
- b'--AAAAAA\r\nContent-Disposition: form-data; name="field"\r\n\r\nvalue\r\n--AAAAAA--\r\n')
- self.assertEqual(
- multipart_encode({'欄位'.encode('utf-8'): '值'.encode('utf-8')}, boundary='AAAAAA')[0],
- b'--AAAAAA\r\nContent-Disposition: form-data; name="\xe6\xac\x84\xe4\xbd\x8d"\r\n\r\n\xe5\x80\xbc\r\n--AAAAAA--\r\n')
- self.assertRaises(
- ValueError, multipart_encode, {b'field': b'value'}, boundary='value')
-
- def test_merge_dicts(self):
- self.assertEqual(merge_dicts({'a': 1}, {'b': 2}), {'a': 1, 'b': 2})
- self.assertEqual(merge_dicts({'a': 1}, {'a': 2}), {'a': 1})
- self.assertEqual(merge_dicts({'a': 1}, {'a': None}), {'a': 1})
- self.assertEqual(merge_dicts({'a': 1}, {'a': ''}), {'a': 1})
- self.assertEqual(merge_dicts({'a': 1}, {}), {'a': 1})
- self.assertEqual(merge_dicts({'a': None}, {'a': 1}), {'a': 1})
- self.assertEqual(merge_dicts({'a': ''}, {'a': 1}), {'a': ''})
- self.assertEqual(merge_dicts({'a': ''}, {'a': 'abc'}), {'a': 'abc'})
- self.assertEqual(merge_dicts({'a': None}, {'a': ''}, {'a': 'abc'}), {'a': 'abc'})
-
- def test_encode_compat_str(self):
- self.assertEqual(encode_compat_str(b'\xd1\x82\xd0\xb5\xd1\x81\xd1\x82', 'utf-8'), 'тест')
- self.assertEqual(encode_compat_str('тест', 'utf-8'), 'тест')
-
- def test_parse_iso8601(self):
- self.assertEqual(parse_iso8601('2014-03-23T23:04:26+0100'), 1395612266)
- self.assertEqual(parse_iso8601('2014-03-23T22:04:26+0000'), 1395612266)
- self.assertEqual(parse_iso8601('2014-03-23T22:04:26Z'), 1395612266)
- self.assertEqual(parse_iso8601('2014-03-23T22:04:26.1234Z'), 1395612266)
- self.assertEqual(parse_iso8601('2015-09-29T08:27:31.727'), 1443515251)
- self.assertEqual(parse_iso8601('2015-09-29T08-27-31.727'), None)
-
- def test_strip_jsonp(self):
- stripped = strip_jsonp('cb ([ {"id":"532cb",\n\n\n"x":\n3}\n]\n);')
- d = json.loads(stripped)
- self.assertEqual(d, [{"id": "532cb", "x": 3}])
-
- stripped = strip_jsonp('parseMetadata({"STATUS":"OK"})\n\n\n//epc')
- d = json.loads(stripped)
- self.assertEqual(d, {'STATUS': 'OK'})
-
- stripped = strip_jsonp('ps.embedHandler({"status": "success"});')
- d = json.loads(stripped)
- self.assertEqual(d, {'status': 'success'})
-
- stripped = strip_jsonp('window.cb && window.cb({"status": "success"});')
- d = json.loads(stripped)
- self.assertEqual(d, {'status': 'success'})
-
- stripped = strip_jsonp('window.cb && cb({"status": "success"});')
- d = json.loads(stripped)
- self.assertEqual(d, {'status': 'success'})
-
- stripped = strip_jsonp('({"status": "success"});')
- d = json.loads(stripped)
- self.assertEqual(d, {'status': 'success'})
-
- def test_strip_or_none(self):
- self.assertEqual(strip_or_none(' abc'), 'abc')
- self.assertEqual(strip_or_none('abc '), 'abc')
- self.assertEqual(strip_or_none(' abc '), 'abc')
- self.assertEqual(strip_or_none('\tabc\t'), 'abc')
- self.assertEqual(strip_or_none('\n\tabc\n\t'), 'abc')
- self.assertEqual(strip_or_none('abc'), 'abc')
- self.assertEqual(strip_or_none(''), '')
- self.assertEqual(strip_or_none(None), None)
- self.assertEqual(strip_or_none(42), None)
- self.assertEqual(strip_or_none([]), None)
-
- def test_uppercase_escape(self):
- self.assertEqual(uppercase_escape('aä'), 'aä')
- self.assertEqual(uppercase_escape('\\U0001d550'), '𝕐')
-
- def test_lowercase_escape(self):
- self.assertEqual(lowercase_escape('aä'), 'aä')
- self.assertEqual(lowercase_escape('\\u0026'), '&')
-
- def test_limit_length(self):
- self.assertEqual(limit_length(None, 12), None)
- self.assertEqual(limit_length('foo', 12), 'foo')
- self.assertTrue(
- limit_length('foo bar baz asd', 12).startswith('foo bar'))
- self.assertTrue('...' in limit_length('foo bar baz asd', 12))
-
- def test_mimetype2ext(self):
- self.assertEqual(mimetype2ext(None), None)
- self.assertEqual(mimetype2ext('video/x-flv'), 'flv')
- self.assertEqual(mimetype2ext('application/x-mpegURL'), 'm3u8')
- self.assertEqual(mimetype2ext('text/vtt'), 'vtt')
- self.assertEqual(mimetype2ext('text/vtt;charset=utf-8'), 'vtt')
- self.assertEqual(mimetype2ext('text/html; charset=utf-8'), 'html')
- self.assertEqual(mimetype2ext('audio/x-wav'), 'wav')
- self.assertEqual(mimetype2ext('audio/x-wav;codec=pcm'), 'wav')
-
- def test_month_by_name(self):
- self.assertEqual(month_by_name(None), None)
- self.assertEqual(month_by_name('December', 'en'), 12)
- self.assertEqual(month_by_name('décembre', 'fr'), 12)
- self.assertEqual(month_by_name('December'), 12)
- self.assertEqual(month_by_name('décembre'), None)
- self.assertEqual(month_by_name('Unknown', 'unknown'), None)
-
- def test_parse_codecs(self):
- self.assertEqual(parse_codecs(''), {})
- self.assertEqual(parse_codecs('avc1.77.30, mp4a.40.2'), {
- 'vcodec': 'avc1.77.30',
- 'acodec': 'mp4a.40.2',
- })
- self.assertEqual(parse_codecs('mp4a.40.2'), {
- 'vcodec': 'none',
- 'acodec': 'mp4a.40.2',
- })
- self.assertEqual(parse_codecs('mp4a.40.5,avc1.42001e'), {
- 'vcodec': 'avc1.42001e',
- 'acodec': 'mp4a.40.5',
- })
- self.assertEqual(parse_codecs('avc3.640028'), {
- 'vcodec': 'avc3.640028',
- 'acodec': 'none',
- })
- self.assertEqual(parse_codecs(', h264,,newcodec,aac'), {
- 'vcodec': 'h264',
- 'acodec': 'aac',
- })
- self.assertEqual(parse_codecs('av01.0.05M.08'), {
- 'vcodec': 'av01.0.05M.08',
- 'acodec': 'none',
- })
- self.assertEqual(parse_codecs('theora, vorbis'), {
- 'vcodec': 'theora',
- 'acodec': 'vorbis',
- })
- self.assertEqual(parse_codecs('unknownvcodec, unknownacodec'), {
- 'vcodec': 'unknownvcodec',
- 'acodec': 'unknownacodec',
- })
- self.assertEqual(parse_codecs('unknown'), {})
-
- def test_escape_rfc3986(self):
- reserved = "!*'();:@&=+$,/?#[]"
- unreserved = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~'
- self.assertEqual(escape_rfc3986(reserved), reserved)
- self.assertEqual(escape_rfc3986(unreserved), unreserved)
- self.assertEqual(escape_rfc3986('тест'), '%D1%82%D0%B5%D1%81%D1%82')
- self.assertEqual(escape_rfc3986('%D1%82%D0%B5%D1%81%D1%82'), '%D1%82%D0%B5%D1%81%D1%82')
- self.assertEqual(escape_rfc3986('foo bar'), 'foo%20bar')
- self.assertEqual(escape_rfc3986('foo%20bar'), 'foo%20bar')
-
- def test_escape_url(self):
- self.assertEqual(
- escape_url('http://wowza.imust.org/srv/vod/telemb/new/UPLOAD/UPLOAD/20224_IncendieHavré_FD.mp4'),
- 'http://wowza.imust.org/srv/vod/telemb/new/UPLOAD/UPLOAD/20224_IncendieHavre%CC%81_FD.mp4'
- )
- self.assertEqual(
- escape_url('http://www.ardmediathek.de/tv/Sturm-der-Liebe/Folge-2036-Zu-Mann-und-Frau-erklärt/Das-Erste/Video?documentId=22673108&bcastId=5290'),
- 'http://www.ardmediathek.de/tv/Sturm-der-Liebe/Folge-2036-Zu-Mann-und-Frau-erkl%C3%A4rt/Das-Erste/Video?documentId=22673108&bcastId=5290'
- )
- self.assertEqual(
- escape_url('http://тест.рф/фрагмент'),
- 'http://xn--e1aybc.xn--p1ai/%D1%84%D1%80%D0%B0%D0%B3%D0%BC%D0%B5%D0%BD%D1%82'
- )
- self.assertEqual(
- escape_url('http://тест.рф/абв?абв=абв#абв'),
- 'http://xn--e1aybc.xn--p1ai/%D0%B0%D0%B1%D0%B2?%D0%B0%D0%B1%D0%B2=%D0%B0%D0%B1%D0%B2#%D0%B0%D0%B1%D0%B2'
- )
- self.assertEqual(escape_url('http://vimeo.com/56015672#at=0'), 'http://vimeo.com/56015672#at=0')
-
- def test_remove_dot_segments(self):
-
- def remove_dot_segments(p):
- q = '' if p.startswith('/') else '/'
- p = 'http://example.com' + q + p
- p = compat_urlparse.urlsplit(YoutubeDLHandler._fix_path(p)).path
- return p[1:] if q else p
-
- self.assertEqual(remove_dot_segments('/a/b/c/./../../g'), '/a/g')
- self.assertEqual(remove_dot_segments('mid/content=5/../6'), 'mid/6')
- self.assertEqual(remove_dot_segments('/ad/../cd'), '/cd')
- self.assertEqual(remove_dot_segments('/ad/../cd/'), '/cd/')
- self.assertEqual(remove_dot_segments('/..'), '/')
- self.assertEqual(remove_dot_segments('/./'), '/')
- self.assertEqual(remove_dot_segments('/./a'), '/a')
- self.assertEqual(remove_dot_segments('/abc/./.././d/././e/.././f/./../../ghi'), '/ghi')
- self.assertEqual(remove_dot_segments('/'), '/')
- self.assertEqual(remove_dot_segments('/t'), '/t')
- self.assertEqual(remove_dot_segments('t'), 't')
- self.assertEqual(remove_dot_segments(''), '')
- self.assertEqual(remove_dot_segments('/../a/b/c'), '/a/b/c')
- self.assertEqual(remove_dot_segments('../a'), 'a')
- self.assertEqual(remove_dot_segments('./a'), 'a')
- self.assertEqual(remove_dot_segments('.'), '')
- self.assertEqual(remove_dot_segments('////'), '////')
-
- def test_js_to_json_vars_strings(self):
- self.assertDictEqual(
- json.loads(js_to_json(
- '''{
- 'null': a,
- 'nullStr': b,
- 'true': c,
- 'trueStr': d,
- 'false': e,
- 'falseStr': f,
- 'unresolvedVar': g,
- }''',
- {
- 'a': 'null',
- 'b': '"null"',
- 'c': 'true',
- 'd': '"true"',
- 'e': 'false',
- 'f': '"false"',
- 'g': 'var',
- }
- )),
- {
- 'null': None,
- 'nullStr': 'null',
- 'true': True,
- 'trueStr': 'true',
- 'false': False,
- 'falseStr': 'false',
- 'unresolvedVar': 'var'
- }
- )
-
- self.assertDictEqual(
- json.loads(js_to_json(
- '''{
- 'int': a,
- 'intStr': b,
- 'float': c,
- 'floatStr': d,
- }''',
- {
- 'a': '123',
- 'b': '"123"',
- 'c': '1.23',
- 'd': '"1.23"',
- }
- )),
- {
- 'int': 123,
- 'intStr': '123',
- 'float': 1.23,
- 'floatStr': '1.23',
- }
- )
-
- self.assertDictEqual(
- json.loads(js_to_json(
- '''{
- 'object': a,
- 'objectStr': b,
- 'array': c,
- 'arrayStr': d,
- }''',
- {
- 'a': '{}',
- 'b': '"{}"',
- 'c': '[]',
- 'd': '"[]"',
- }
- )),
- {
- 'object': {},
- 'objectStr': '{}',
- 'array': [],
- 'arrayStr': '[]',
- }
- )
-
- def test_js_to_json_realworld(self):
- inp = '''{
- 'clip':{'provider':'pseudo'}
- }'''
- self.assertEqual(js_to_json(inp), '''{
- "clip":{"provider":"pseudo"}
- }''')
- json.loads(js_to_json(inp))
-
- inp = '''{
- 'playlist':[{'controls':{'all':null}}]
- }'''
- self.assertEqual(js_to_json(inp), '''{
- "playlist":[{"controls":{"all":null}}]
- }''')
-
- inp = '''"The CW\\'s \\'Crazy Ex-Girlfriend\\'"'''
- self.assertEqual(js_to_json(inp), '''"The CW's 'Crazy Ex-Girlfriend'"''')
-
- inp = '"SAND Number: SAND 2013-7800P\\nPresenter: Tom Russo\\nHabanero Software Training - Xyce Software\\nXyce, Sandia\\u0027s"'
- json_code = js_to_json(inp)
- self.assertEqual(json.loads(json_code), json.loads(inp))
-
- inp = '''{
- 0:{src:'skipped', type: 'application/dash+xml'},
- 1:{src:'skipped', type: 'application/vnd.apple.mpegURL'},
- }'''
- self.assertEqual(js_to_json(inp), '''{
- "0":{"src":"skipped", "type": "application/dash+xml"},
- "1":{"src":"skipped", "type": "application/vnd.apple.mpegURL"}
- }''')
-
- inp = '''{"foo":101}'''
- self.assertEqual(js_to_json(inp), '''{"foo":101}''')
-
- inp = '''{"duration": "00:01:07"}'''
- self.assertEqual(js_to_json(inp), '''{"duration": "00:01:07"}''')
-
- inp = '''{segments: [{"offset":-3.885780586188048e-16,"duration":39.75000000000001}]}'''
- self.assertEqual(js_to_json(inp), '''{"segments": [{"offset":-3.885780586188048e-16,"duration":39.75000000000001}]}''')
-
- def test_js_to_json_edgecases(self):
- on = js_to_json("{abc_def:'1\\'\\\\2\\\\\\'3\"4'}")
- self.assertEqual(json.loads(on), {"abc_def": "1'\\2\\'3\"4"})
-
- on = js_to_json('{"abc": true}')
- self.assertEqual(json.loads(on), {'abc': True})
-
- # Ignore JavaScript code as well
- on = js_to_json('''{
- "x": 1,
- y: "a",
- z: some.code
- }''')
- d = json.loads(on)
- self.assertEqual(d['x'], 1)
- self.assertEqual(d['y'], 'a')
-
- # Just drop ! prefix for now though this results in a wrong value
- on = js_to_json('''{
- a: !0,
- b: !1,
- c: !!0,
- d: !!42.42,
- e: !!![],
- f: !"abc",
- g: !"",
- !42: 42
- }''')
- self.assertEqual(json.loads(on), {
- 'a': True,
- 'b': False,
- 'c': False,
- 'd': True,
- 'e': [],
- 'f': "abc",
- 'g': "",
- '42': 42
- })
-
- on = js_to_json('["abc", "def",]')
- self.assertEqual(json.loads(on), ['abc', 'def'])
-
- on = js_to_json('[/*comment\n*/"abc"/*comment\n*/,/*comment\n*/"def",/*comment\n*/]')
- self.assertEqual(json.loads(on), ['abc', 'def'])
-
- on = js_to_json('[//comment\n"abc" //comment\n,//comment\n"def",//comment\n]')
- self.assertEqual(json.loads(on), ['abc', 'def'])
-
- on = js_to_json('{"abc": "def",}')
- self.assertEqual(json.loads(on), {'abc': 'def'})
-
- on = js_to_json('{/*comment\n*/"abc"/*comment\n*/:/*comment\n*/"def"/*comment\n*/,/*comment\n*/}')
- self.assertEqual(json.loads(on), {'abc': 'def'})
-
- on = js_to_json('{ 0: /* " \n */ ",]" , }')
- self.assertEqual(json.loads(on), {'0': ',]'})
-
- on = js_to_json('{ /*comment\n*/0/*comment\n*/: /* " \n */ ",]" , }')
- self.assertEqual(json.loads(on), {'0': ',]'})
-
- on = js_to_json('{ 0: // comment\n1 }')
- self.assertEqual(json.loads(on), {'0': 1})
-
- on = js_to_json(r'["x<\/p>"]')
- self.assertEqual(json.loads(on), ['
x
'])
-
- on = js_to_json(r'["\xaa"]')
- self.assertEqual(json.loads(on), ['\u00aa'])
-
- on = js_to_json("['a\\\nb']")
- self.assertEqual(json.loads(on), ['ab'])
-
- on = js_to_json("/*comment\n*/[/*comment\n*/'a\\\nb'/*comment\n*/]/*comment\n*/")
- self.assertEqual(json.loads(on), ['ab'])
-
- on = js_to_json('{0xff:0xff}')
- self.assertEqual(json.loads(on), {'255': 255})
-
- on = js_to_json('{/*comment\n*/0xff/*comment\n*/:/*comment\n*/0xff/*comment\n*/}')
- self.assertEqual(json.loads(on), {'255': 255})
-
- on = js_to_json('{077:077}')
- self.assertEqual(json.loads(on), {'63': 63})
-
- on = js_to_json('{/*comment\n*/077/*comment\n*/:/*comment\n*/077/*comment\n*/}')
- self.assertEqual(json.loads(on), {'63': 63})
-
- on = js_to_json('{42:42}')
- self.assertEqual(json.loads(on), {'42': 42})
-
- on = js_to_json('{/*comment\n*/42/*comment\n*/:/*comment\n*/42/*comment\n*/}')
- self.assertEqual(json.loads(on), {'42': 42})
-
- on = js_to_json('{42:4.2e1}')
- self.assertEqual(json.loads(on), {'42': 42.0})
-
- on = js_to_json('{ "0x40": "0x40" }')
- self.assertEqual(json.loads(on), {'0x40': '0x40'})
-
- on = js_to_json('{ "040": "040" }')
- self.assertEqual(json.loads(on), {'040': '040'})
-
- on = js_to_json('[1,//{},\n2]')
- self.assertEqual(json.loads(on), [1, 2])
-
- on = js_to_json(r'"\^\$\#"')
- self.assertEqual(json.loads(on), R'^$#', msg='Unnecessary escapes should be stripped')
-
- on = js_to_json('\'"\\""\'')
- self.assertEqual(json.loads(on), '"""', msg='Unnecessary quote escape should be escaped')
-
- def test_js_to_json_malformed(self):
- self.assertEqual(js_to_json('42a1'), '42"a1"')
- self.assertEqual(js_to_json('42a-1'), '42"a"-1')
-
- def test_js_to_json_template_literal(self):
- self.assertEqual(js_to_json('`Hello ${name}`', {'name': '"world"'}), '"Hello world"')
- self.assertEqual(js_to_json('`${name}${name}`', {'name': '"X"'}), '"XX"')
- self.assertEqual(js_to_json('`${name}${name}`', {'name': '5'}), '"55"')
- self.assertEqual(js_to_json('`${name}"${name}"`', {'name': '5'}), '"5\\"5\\""')
- self.assertEqual(js_to_json('`${name}`', {}), '"name"')
-
- def test_extract_attributes(self):
- self.assertEqual(extract_attributes(''), {'x': 'y'})
- self.assertEqual(extract_attributes(""), {'x': 'y'})
- self.assertEqual(extract_attributes(''), {'x': 'y'})
- self.assertEqual(extract_attributes(''), {'x': "a 'b' c"})
- self.assertEqual(extract_attributes(''), {'x': 'a "b" c'})
- self.assertEqual(extract_attributes(''), {'x': 'y'})
- self.assertEqual(extract_attributes(''), {'x': 'y'})
- self.assertEqual(extract_attributes(''), {'x': '&'}) # XML
- self.assertEqual(extract_attributes(''), {'x': '"'})
- self.assertEqual(extract_attributes(''), {'x': '£'}) # HTML 3.2
- self.assertEqual(extract_attributes(''), {'x': 'λ'}) # HTML 4.0
- self.assertEqual(extract_attributes(''), {'x': '&foo'})
- self.assertEqual(extract_attributes(''), {'x': "'"})
- self.assertEqual(extract_attributes(''), {'x': '"'})
- self.assertEqual(extract_attributes(''), {'x': None})
- self.assertEqual(extract_attributes(''), {'x': 'y', 'a': None})
- self.assertEqual(extract_attributes(''), {'x': 'y'})
- self.assertEqual(extract_attributes(''), {'y': '2', 'x': '3'})
- self.assertEqual(extract_attributes(''), {'x': 'y'})
- self.assertEqual(extract_attributes(''), {'x': 'y'})
- self.assertEqual(extract_attributes(""), {'x': 'y'})
- self.assertEqual(extract_attributes(''), {'x': '\ny\n'})
- self.assertEqual(extract_attributes(''), {'caps': 'x'}) # Names lowercased
- self.assertEqual(extract_attributes(''), {'x': '2'})
- self.assertEqual(extract_attributes(''), {'x': '2'})
- self.assertEqual(extract_attributes(''), {'_:funny-name1': '1'})
- self.assertEqual(extract_attributes(''), {'x': 'Fáilte 世界 \U0001f600'})
- self.assertEqual(extract_attributes(''), {'x': 'décompose\u0301'})
- # "Narrow" Python builds don't support unicode code points outside BMP.
- try:
- compat_chr(0x10000)
- supports_outside_bmp = True
- except ValueError:
- supports_outside_bmp = False
- if supports_outside_bmp:
- self.assertEqual(extract_attributes(''), {'x': 'Smile \U0001f600!'})
- # Malformed HTML should not break attributes extraction on older Python
- self.assertEqual(extract_attributes(''), {})
-
- def test_clean_html(self):
- self.assertEqual(clean_html('a:\nb'), 'a: b')
- self.assertEqual(clean_html('a:\n "b"'), 'a: "b"')
- self.assertEqual(clean_html('a
\xa0b'), 'a\nb')
-
- def test_intlist_to_bytes(self):
- self.assertEqual(
- 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 compat_os_name != 'nt' else 'foo ba/r -baz "2 be" ""'
- )
-
- def test_parse_filesize(self):
- self.assertEqual(parse_filesize(None), None)
- self.assertEqual(parse_filesize(''), None)
- self.assertEqual(parse_filesize('91 B'), 91)
- self.assertEqual(parse_filesize('foobar'), None)
- self.assertEqual(parse_filesize('2 MiB'), 2097152)
- self.assertEqual(parse_filesize('5 GB'), 5000000000)
- self.assertEqual(parse_filesize('1.2Tb'), 1200000000000)
- self.assertEqual(parse_filesize('1.2tb'), 1200000000000)
- self.assertEqual(parse_filesize('1,24 KB'), 1240)
- self.assertEqual(parse_filesize('1,24 kb'), 1240)
- self.assertEqual(parse_filesize('8.5 megabytes'), 8500000)
-
- def test_parse_count(self):
- self.assertEqual(parse_count(None), None)
- self.assertEqual(parse_count(''), None)
- self.assertEqual(parse_count('0'), 0)
- self.assertEqual(parse_count('1000'), 1000)
- self.assertEqual(parse_count('1.000'), 1000)
- self.assertEqual(parse_count('1.1k'), 1100)
- self.assertEqual(parse_count('1.1kk'), 1100000)
- self.assertEqual(parse_count('1.1kk '), 1100000)
- self.assertEqual(parse_count('1.1kk views'), 1100000)
-
- def test_parse_resolution(self):
- self.assertEqual(parse_resolution(None), {})
- self.assertEqual(parse_resolution(''), {})
- self.assertEqual(parse_resolution('1920x1080'), {'width': 1920, 'height': 1080})
- self.assertEqual(parse_resolution('1920×1080'), {'width': 1920, 'height': 1080})
- self.assertEqual(parse_resolution('1920 x 1080'), {'width': 1920, 'height': 1080})
- self.assertEqual(parse_resolution('720p'), {'height': 720})
- self.assertEqual(parse_resolution('4k'), {'height': 2160})
- self.assertEqual(parse_resolution('8K'), {'height': 4320})
-
- def test_parse_bitrate(self):
- self.assertEqual(parse_bitrate(None), None)
- self.assertEqual(parse_bitrate(''), None)
- self.assertEqual(parse_bitrate('300kbps'), 300)
- self.assertEqual(parse_bitrate('1500kbps'), 1500)
- self.assertEqual(parse_bitrate('300 kbps'), 300)
-
- def test_version_tuple(self):
- self.assertEqual(version_tuple('1'), (1,))
- self.assertEqual(version_tuple('10.23.344'), (10, 23, 344))
- self.assertEqual(version_tuple('10.1-6'), (10, 1, 6)) # avconv style
-
- def test_detect_exe_version(self):
- self.assertEqual(detect_exe_version('''ffmpeg version 1.2.1
-built on May 27 2013 08:37:26 with gcc 4.7 (Debian 4.7.3-4)
-configuration: --prefix=/usr --extra-'''), '1.2.1')
- self.assertEqual(detect_exe_version('''ffmpeg version N-63176-g1fb4685
-built on May 15 2014 22:09:06 with gcc 4.8.2 (GCC)'''), 'N-63176-g1fb4685')
- self.assertEqual(detect_exe_version('''X server found. dri2 connection failed!
-Trying to open render node...
-Success at /dev/dri/renderD128.
-ffmpeg version 2.4.4 Copyright (c) 2000-2014 the FFmpeg ...'''), '2.4.4')
-
- def test_age_restricted(self):
- self.assertFalse(age_restricted(None, 10)) # unrestricted content
- self.assertFalse(age_restricted(1, None)) # unrestricted policy
- self.assertFalse(age_restricted(8, 10))
- self.assertTrue(age_restricted(18, 14))
- self.assertFalse(age_restricted(18, 18))
-
- def test_is_html(self):
- self.assertFalse(is_html(b'\x49\x44\x43\xaaa'))
- self.assertTrue(is_html( # UTF-8 with BOM
- b'\xef\xbb\xbf\xaaa'))
- self.assertTrue(is_html( # UTF-16-LE
- b'\xff\xfe<\x00h\x00t\x00m\x00l\x00>\x00\xe4\x00'
- ))
- self.assertTrue(is_html( # UTF-16-BE
- b'\xfe\xff\x00<\x00h\x00t\x00m\x00l\x00>\x00\xe4'
- ))
- self.assertTrue(is_html( # UTF-32-BE
- b'\x00\x00\xFE\xFF\x00\x00\x00<\x00\x00\x00h\x00\x00\x00t\x00\x00\x00m\x00\x00\x00l\x00\x00\x00>\x00\x00\x00\xe4'))
- self.assertTrue(is_html( # UTF-32-LE
- b'\xFF\xFE\x00\x00<\x00\x00\x00h\x00\x00\x00t\x00\x00\x00m\x00\x00\x00l\x00\x00\x00>\x00\x00\x00\xe4\x00\x00\x00'))
-
- def test_render_table(self):
- self.assertEqual(
- render_table(
- ['a', 'bcd'],
- [[123, 4], [9999, 51]]),
- 'a bcd\n'
- '123 4\n'
- '9999 51')
-
- def test_match_str(self):
- self.assertRaises(ValueError, match_str, 'xy>foobar', {})
- self.assertFalse(match_str('xy', {'x': 1200}))
- self.assertTrue(match_str('!xy', {'x': 1200}))
- self.assertTrue(match_str('x', {'x': 1200}))
- self.assertFalse(match_str('!x', {'x': 1200}))
- self.assertTrue(match_str('x', {'x': 0}))
- self.assertFalse(match_str('x>0', {'x': 0}))
- self.assertFalse(match_str('x>0', {}))
- self.assertTrue(match_str('x>?0', {}))
- self.assertTrue(match_str('x>1K', {'x': 1200}))
- self.assertFalse(match_str('x>2K', {'x': 1200}))
- self.assertTrue(match_str('x>=1200 & x < 1300', {'x': 1200}))
- self.assertFalse(match_str('x>=1100 & x < 1200', {'x': 1200}))
- self.assertFalse(match_str('y=a212', {'y': 'foobar42'}))
- self.assertTrue(match_str('y=foobar42', {'y': 'foobar42'}))
- self.assertFalse(match_str('y!=foobar42', {'y': 'foobar42'}))
- self.assertTrue(match_str('y!=foobar2', {'y': 'foobar42'}))
- self.assertFalse(match_str(
- 'like_count > 100 & dislike_count 50 & description',
- {'like_count': 90, 'description': 'foo'}))
- self.assertTrue(match_str(
- 'like_count > 100 & dislike_count 50 & description',
- {'like_count': 190, 'description': 'foo'}))
- self.assertFalse(match_str(
- 'like_count > 100 & dislike_count 50 & description',
- {'like_count': 190, 'dislike_count': 60, 'description': 'foo'}))
- self.assertFalse(match_str(
- 'like_count > 100 & dislike_count 50 & description',
- {'like_count': 190, 'dislike_count': 10}))
- self.assertTrue(match_str('is_live', {'is_live': True}))
- self.assertFalse(match_str('is_live', {'is_live': False}))
- self.assertFalse(match_str('is_live', {'is_live': None}))
- self.assertFalse(match_str('is_live', {}))
- self.assertFalse(match_str('!is_live', {'is_live': True}))
- self.assertTrue(match_str('!is_live', {'is_live': False}))
- self.assertTrue(match_str('!is_live', {'is_live': None}))
- self.assertTrue(match_str('!is_live', {}))
- self.assertTrue(match_str('title', {'title': 'abc'}))
- self.assertTrue(match_str('title', {'title': ''}))
- self.assertFalse(match_str('!title', {'title': 'abc'}))
- self.assertFalse(match_str('!title', {'title': ''}))
-
- def test_parse_dfxp_time_expr(self):
- self.assertEqual(parse_dfxp_time_expr(None), None)
- self.assertEqual(parse_dfxp_time_expr(''), None)
- self.assertEqual(parse_dfxp_time_expr('0.1'), 0.1)
- self.assertEqual(parse_dfxp_time_expr('0.1s'), 0.1)
- self.assertEqual(parse_dfxp_time_expr('00:00:01'), 1.0)
- self.assertEqual(parse_dfxp_time_expr('00:00:01.100'), 1.1)
- self.assertEqual(parse_dfxp_time_expr('00:00:01:100'), 1.1)
-
- def test_dfxp2srt(self):
- dfxp_data = '''
-
-
-
-
The following line contains Chinese characters and special symbols
-
第二行
♪♪
-
Third
Line
-
Lines with invalid timestamps are ignored
-
Ignore, two
-
Ignored, three
-
-
- '''.encode('utf-8')
- srt_data = '''1
-00:00:00,000 --> 00:00:01,000
-The following line contains Chinese characters and special symbols
-
-2
-00:00:01,000 --> 00:00:02,000
-第二行
-♪♪
-
-3
-00:00:02,000 --> 00:00:03,000
-Third
-Line
-
-'''
- self.assertEqual(dfxp2srt(dfxp_data), srt_data)
-
- dfxp_data_no_default_namespace = '''
-
-
-
-
- '''.encode('utf-8')
- srt_data = '''1
-00:00:00,000 --> 00:00:01,000
-The first line
-
-'''
- self.assertEqual(dfxp2srt(dfxp_data_no_default_namespace), srt_data)
-
- dfxp_data_with_style = '''
-
-
-
-
-
-
-
-
-
-
-
-
default stylecustom style
-
part 1
part 2
-
line 3
part 3
-
inner
style
-
-
-'''.encode('utf-8')
- srt_data = '''1
-00:00:02,080 --> 00:00:05,839
-default stylecustom style
-
-2
-00:00:02,080 --> 00:00:05,839
-part 1
-part 2
-
-3
-00:00:05,839 --> 00:00:09,560
-line 3
-part 3
-
-4
-00:00:09,560 --> 00:00:12,359
-inner
- style
-
-'''
- self.assertEqual(dfxp2srt(dfxp_data_with_style), srt_data)
-
- dfxp_data_non_utf8 = '''
-
-
-
-
- '''.encode('utf-16')
- srt_data = '''1
-00:00:00,000 --> 00:00:01,000
-Line 1
-
-2
-00:00:01,000 --> 00:00:02,000
-第二行
-
-'''
- self.assertEqual(dfxp2srt(dfxp_data_non_utf8), srt_data)
-
- def test_cli_option(self):
- self.assertEqual(cli_option({'proxy': '127.0.0.1:3128'}, '--proxy', 'proxy'), ['--proxy', '127.0.0.1:3128'])
- self.assertEqual(cli_option({'proxy': None}, '--proxy', 'proxy'), [])
- self.assertEqual(cli_option({}, '--proxy', 'proxy'), [])
- self.assertEqual(cli_option({'retries': 10}, '--retries', 'retries'), ['--retries', '10'])
-
- def test_cli_valueless_option(self):
- self.assertEqual(cli_valueless_option(
- {'downloader': 'external'}, '--external-downloader', 'downloader', 'external'), ['--external-downloader'])
- self.assertEqual(cli_valueless_option(
- {'downloader': 'internal'}, '--external-downloader', 'downloader', 'external'), [])
- self.assertEqual(cli_valueless_option(
- {'nocheckcertificate': True}, '--no-check-certificate', 'nocheckcertificate'), ['--no-check-certificate'])
- self.assertEqual(cli_valueless_option(
- {'nocheckcertificate': False}, '--no-check-certificate', 'nocheckcertificate'), [])
- self.assertEqual(cli_valueless_option(
- {'checkcertificate': True}, '--no-check-certificate', 'checkcertificate', False), [])
- self.assertEqual(cli_valueless_option(
- {'checkcertificate': False}, '--no-check-certificate', 'checkcertificate', False), ['--no-check-certificate'])
-
- def test_cli_bool_option(self):
- self.assertEqual(
- cli_bool_option(
- {'nocheckcertificate': True}, '--no-check-certificate', 'nocheckcertificate'),
- ['--no-check-certificate', 'true'])
- self.assertEqual(
- cli_bool_option(
- {'nocheckcertificate': True}, '--no-check-certificate', 'nocheckcertificate', separator='='),
- ['--no-check-certificate=true'])
- self.assertEqual(
- cli_bool_option(
- {'nocheckcertificate': True}, '--check-certificate', 'nocheckcertificate', 'false', 'true'),
- ['--check-certificate', 'false'])
- self.assertEqual(
- cli_bool_option(
- {'nocheckcertificate': True}, '--check-certificate', 'nocheckcertificate', 'false', 'true', '='),
- ['--check-certificate=false'])
- self.assertEqual(
- cli_bool_option(
- {'nocheckcertificate': False}, '--check-certificate', 'nocheckcertificate', 'false', 'true'),
- ['--check-certificate', 'true'])
- self.assertEqual(
- cli_bool_option(
- {'nocheckcertificate': False}, '--check-certificate', 'nocheckcertificate', 'false', 'true', '='),
- ['--check-certificate=true'])
- self.assertEqual(
- cli_bool_option(
- {}, '--check-certificate', 'nocheckcertificate', 'false', 'true', '='),
- [])
-
- def test_ohdave_rsa_encrypt(self):
- N = 0xab86b6371b5318aaa1d3c9e612a9f1264f372323c8c0f19875b5fc3b3fd3afcc1e5bec527aa94bfa85bffc157e4245aebda05389a5357b75115ac94f074aefcd
- e = 65537
-
- self.assertEqual(
- ohdave_rsa_encrypt(b'aa111222', e, N),
- '726664bd9a23fd0c70f9f1b84aab5e3905ce1e45a584e9cbcf9bcc7510338fc1986d6c599ff990d923aa43c51c0d9013cd572e13bc58f4ae48f2ed8c0b0ba881')
-
- def test_pkcs1pad(self):
- data = [1, 2, 3]
- padded_data = pkcs1pad(data, 32)
- self.assertEqual(padded_data[:2], [0, 2])
- self.assertEqual(padded_data[28:], [0, 1, 2, 3])
-
- self.assertRaises(ValueError, pkcs1pad, data, 8)
-
- def test_encode_base_n(self):
- self.assertEqual(encode_base_n(0, 30), '0')
- self.assertEqual(encode_base_n(80, 30), '2k')
-
- custom_table = '9876543210ZYXWVUTSRQPONMLKJIHGFEDCBA'
- self.assertEqual(encode_base_n(0, 30, custom_table), '9')
- self.assertEqual(encode_base_n(80, 30, custom_table), '7P')
-
- self.assertRaises(ValueError, encode_base_n, 0, 70)
- self.assertRaises(ValueError, encode_base_n, 0, 60, custom_table)
-
- def test_caesar(self):
- self.assertEqual(caesar('ace', 'abcdef', 2), 'cea')
- self.assertEqual(caesar('cea', 'abcdef', -2), 'ace')
- self.assertEqual(caesar('ace', 'abcdef', -2), 'eac')
- self.assertEqual(caesar('eac', 'abcdef', 2), 'ace')
- self.assertEqual(caesar('ace', 'abcdef', 0), 'ace')
- self.assertEqual(caesar('xyz', 'abcdef', 2), 'xyz')
- self.assertEqual(caesar('abc', 'acegik', 2), 'ebg')
- self.assertEqual(caesar('ebg', 'acegik', -2), 'abc')
-
- def test_rot47(self):
- self.assertEqual(rot47('youtube-dl'), r'J@FEF36\5=')
- self.assertEqual(rot47('YOUTUBE-DL'), r'*~&%&qt\s{')
-
- def test_urshift(self):
- self.assertEqual(urshift(3, 1), 1)
- self.assertEqual(urshift(-3, 1), 2147483646)
-
- def test_get_element_by_class(self):
- html = '''
- nice
- '''
-
- self.assertEqual(get_element_by_class('foo', html), 'nice')
- self.assertEqual(get_element_by_class('no-such-class', html), None)
-
- def test_get_element_by_attribute(self):
- html = '''
- nice
- '''
-
- self.assertEqual(get_element_by_attribute('class', 'foo bar', html), 'nice')
- self.assertEqual(get_element_by_attribute('class', 'foo', html), None)
- self.assertEqual(get_element_by_attribute('class', 'no-such-foo', html), None)
-
- html = '''
- foo
- '''
-
- self.assertEqual(get_element_by_attribute('itemprop', 'author', html), 'foo')
-
- def test_get_elements_by_class(self):
- html = '''
- nicealso nice
- '''
-
- self.assertEqual(get_elements_by_class('foo', html), ['nice', 'also nice'])
- self.assertEqual(get_elements_by_class('no-such-class', html), [])
-
- def test_get_elements_by_attribute(self):
- html = '''
- nicealso nice
- '''
-
- self.assertEqual(get_elements_by_attribute('class', 'foo bar', html), ['nice', 'also nice'])
- self.assertEqual(get_elements_by_attribute('class', 'foo', html), [])
- self.assertEqual(get_elements_by_attribute('class', 'no-such-foo', html), [])
-
- def test_clean_podcast_url(self):
- self.assertEqual(clean_podcast_url('https://www.podtrac.com/pts/redirect.mp3/chtbl.com/track/5899E/traffic.megaphone.fm/HSW7835899191.mp3'), 'https://traffic.megaphone.fm/HSW7835899191.mp3')
- self.assertEqual(clean_podcast_url('https://play.podtrac.com/npr-344098539/edge1.pod.npr.org/anon.npr-podcasts/podcast/npr/waitwait/2020/10/20201003_waitwait_wwdtmpodcast201003-015621a5-f035-4eca-a9a1-7c118d90bc3c.mp3'), 'https://edge1.pod.npr.org/anon.npr-podcasts/podcast/npr/waitwait/2020/10/20201003_waitwait_wwdtmpodcast201003-015621a5-f035-4eca-a9a1-7c118d90bc3c.mp3')
-
- def test_LazyList(self):
- it = list(range(10))
-
- self.assertEqual(list(LazyList(it)), it)
- self.assertEqual(LazyList(it).exhaust(), it)
- self.assertEqual(LazyList(it)[5], it[5])
-
- self.assertEqual(LazyList(it)[5:], it[5:])
- self.assertEqual(LazyList(it)[:5], it[:5])
- self.assertEqual(LazyList(it)[::2], it[::2])
- self.assertEqual(LazyList(it)[1::2], it[1::2])
- self.assertEqual(LazyList(it)[5::-1], it[5::-1])
- self.assertEqual(LazyList(it)[6:2:-2], it[6:2:-2])
- self.assertEqual(LazyList(it)[::-1], it[::-1])
-
- self.assertTrue(LazyList(it))
- self.assertFalse(LazyList(range(0)))
- self.assertEqual(len(LazyList(it)), len(it))
- self.assertEqual(repr(LazyList(it)), repr(it))
- self.assertEqual(compat_str(LazyList(it)), compat_str(it))
-
- self.assertEqual(list(LazyList(it, reverse=True)), it[::-1])
- self.assertEqual(list(reversed(LazyList(it))[::-1]), it)
- self.assertEqual(list(reversed(LazyList(it))[1:3:7]), it[::-1][1:3:7])
-
- def test_LazyList_laziness(self):
-
- def test(ll, idx, val, cache):
- self.assertEqual(ll[idx], val)
- self.assertEqual(ll._cache, list(cache))
-
- ll = LazyList(range(10))
- test(ll, 0, 0, range(1))
- test(ll, 5, 5, range(6))
- test(ll, -3, 7, range(10))
-
- ll = LazyList(range(10), reverse=True)
- test(ll, -1, 0, range(1))
- test(ll, 3, 6, range(10))
-
- ll = LazyList(itertools.count())
- test(ll, 10, 10, range(11))
- ll = reversed(ll)
- test(ll, -15, 14, range(15))
-
- def test_try_call(self):
- def total(*x, **kwargs):
- return sum(x) + sum(kwargs.values())
-
- self.assertEqual(try_call(None), None,
- msg='not a fn should give None')
- self.assertEqual(try_call(lambda: 1), 1,
- msg='int fn with no expected_type should give int')
- self.assertEqual(try_call(lambda: 1, expected_type=int), 1,
- msg='int fn with expected_type int should give int')
- self.assertEqual(try_call(lambda: 1, expected_type=dict), None,
- msg='int fn with wrong expected_type should give None')
- self.assertEqual(try_call(total, args=(0, 1, 0, ), expected_type=int), 1,
- msg='fn should accept arglist')
- self.assertEqual(try_call(total, kwargs={'a': 0, 'b': 1, 'c': 0}, expected_type=int), 1,
- msg='fn should accept kwargs')
- self.assertEqual(try_call(lambda: 1, expected_type=dict), None,
- msg='int fn with no expected_type should give None')
- self.assertEqual(try_call(lambda x: {}, total, args=(42, ), expected_type=int), 42,
- msg='expect first int result with expected_type int')
-
- def test_variadic(self):
- self.assertEqual(variadic(None), (None, ))
- self.assertEqual(variadic('spam'), ('spam', ))
- self.assertEqual(variadic('spam', allowed_types=dict), 'spam')
- self.assertEqual(variadic('spam', allowed_types=[dict]), 'spam')
-
- def test_join_nonempty(self):
- self.assertEqual(join_nonempty('a', 'b'), 'a-b')
- self.assertEqual(join_nonempty(
- 'a', 'b', 'c', 'd',
- from_dict={'a': 'c', 'c': [], 'b': 'd', 'd': None}), 'c-d')
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/test_verbose_output.py b/test/test_verbose_output.py
deleted file mode 100644
index c1465fe8c..000000000
--- a/test/test_verbose_output.py
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/usr/bin/env python
-# coding: utf-8
-
-from __future__ import unicode_literals
-
-import unittest
-
-import sys
-import os
-import subprocess
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-rootDir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-
-
-class TestVerboseOutput(unittest.TestCase):
- def test_private_info_arg(self):
- outp = subprocess.Popen(
- [
- sys.executable, 'youtube_dl/__main__.py', '-v',
- '--username', 'johnsmith@gmail.com',
- '--password', 'secret',
- ], cwd=rootDir, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- sout, serr = outp.communicate()
- self.assertTrue(b'--username' in serr)
- self.assertTrue(b'johnsmith' not in serr)
- self.assertTrue(b'--password' in serr)
- self.assertTrue(b'secret' not in serr)
-
- def test_private_info_shortarg(self):
- outp = subprocess.Popen(
- [
- sys.executable, 'youtube_dl/__main__.py', '-v',
- '-u', 'johnsmith@gmail.com',
- '-p', 'secret',
- ], cwd=rootDir, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- sout, serr = outp.communicate()
- self.assertTrue(b'-u' in serr)
- self.assertTrue(b'johnsmith' not in serr)
- self.assertTrue(b'-p' in serr)
- self.assertTrue(b'secret' not in serr)
-
- def test_private_info_eq(self):
- outp = subprocess.Popen(
- [
- sys.executable, 'youtube_dl/__main__.py', '-v',
- '--username=johnsmith@gmail.com',
- '--password=secret',
- ], cwd=rootDir, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- sout, serr = outp.communicate()
- self.assertTrue(b'--username' in serr)
- self.assertTrue(b'johnsmith' not in serr)
- self.assertTrue(b'--password' in serr)
- self.assertTrue(b'secret' not in serr)
-
- def test_private_info_shortarg_eq(self):
- outp = subprocess.Popen(
- [
- sys.executable, 'youtube_dl/__main__.py', '-v',
- '-u=johnsmith@gmail.com',
- '-p=secret',
- ], cwd=rootDir, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- sout, serr = outp.communicate()
- self.assertTrue(b'-u' in serr)
- self.assertTrue(b'johnsmith' not in serr)
- self.assertTrue(b'-p' in serr)
- self.assertTrue(b'secret' not in serr)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/test_write_annotations.py b/test/test_write_annotations.py
deleted file mode 100644
index 68e0a391d..000000000
--- a/test/test_write_annotations.py
+++ /dev/null
@@ -1,79 +0,0 @@
-#!/usr/bin/env python
-# coding: utf-8
-from __future__ import unicode_literals
-
-# Allow direct execution
-import os
-import sys
-import unittest
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-from test.helper import get_params, try_rm
-
-
-import xml.etree.ElementTree
-
-import youtube_dl.YoutubeDL
-import youtube_dl.extractor
-from youtube_dl.compat import compat_open as open
-
-
-class YoutubeDL(youtube_dl.YoutubeDL):
- def __init__(self, *args, **kwargs):
- super(YoutubeDL, self).__init__(*args, **kwargs)
- self.to_stderr = self.to_screen
-
-
-params = get_params({
- 'writeannotations': True,
- 'skip_download': True,
- 'writeinfojson': False,
- 'format': 'flv',
-})
-
-
-TEST_ID = 'gr51aVj-mLg'
-ANNOTATIONS_FILE = TEST_ID + '.annotations.xml'
-EXPECTED_ANNOTATIONS = ['Speech bubble', 'Note', 'Title', 'Spotlight', 'Label']
-
-
-class TestAnnotations(unittest.TestCase):
- def setUp(self):
- # Clear old files
- self.tearDown()
-
- def test_info_json(self):
- expected = list(EXPECTED_ANNOTATIONS) # Two annotations could have the same text.
- ie = youtube_dl.extractor.YoutubeIE()
- ydl = YoutubeDL(params)
- ydl.add_info_extractor(ie)
- ydl.download([TEST_ID])
- self.assertTrue(os.path.exists(ANNOTATIONS_FILE))
- annoxml = None
- with open(ANNOTATIONS_FILE, 'r', encoding='utf-8') as annof:
- annoxml = xml.etree.ElementTree.parse(annof)
- self.assertTrue(annoxml is not None, 'Failed to parse annotations XML')
- root = annoxml.getroot()
- self.assertEqual(root.tag, 'document')
- annotationsTag = root.find('annotations')
- self.assertEqual(annotationsTag.tag, 'annotations')
- annotations = annotationsTag.findall('annotation')
-
- # Not all the annotations have TEXT children and the annotations are returned unsorted.
- for a in annotations:
- self.assertEqual(a.tag, 'annotation')
- if a.get('type') == 'text':
- textTag = a.find('TEXT')
- text = textTag.text
- self.assertTrue(text in expected) # assertIn only added in python 2.7
- # remove the first occurrence, there could be more than one annotation with the same text
- expected.remove(text)
- # We should have seen (and removed) all the expected annotation texts.
- self.assertEqual(len(expected), 0, 'Not all expected annotations were found.')
-
- def tearDown(self):
- try_rm(ANNOTATIONS_FILE)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/test_youtube_lists.py b/test/test_youtube_lists.py
deleted file mode 100644
index e0e8891ba..000000000
--- a/test/test_youtube_lists.py
+++ /dev/null
@@ -1,65 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
-
-# Allow direct execution
-import os
-import sys
-import unittest
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-from test.helper import FakeYDL
-
-from youtube_dl.extractor import (
- YoutubeIE,
- YoutubePlaylistIE,
- YoutubeTabIE,
-)
-
-
-class TestYoutubeLists(unittest.TestCase):
- def assertIsPlaylist(self, info):
- """Make sure the info has '_type' set to 'playlist'"""
- self.assertEqual(info['_type'], 'playlist')
-
- def test_youtube_playlist_noplaylist(self):
- dl = FakeYDL()
- dl.params['noplaylist'] = True
- dl.params['format'] = 'best'
- ie = YoutubePlaylistIE(dl)
- result = ie.extract('https://www.youtube.com/watch?v=FXxLjLQi3Fg&list=PLwiyx1dc3P2JR9N8gQaQN_BCvlSlap7re')
- self.assertEqual(result['_type'], 'url')
- result = dl.extract_info(result['url'], download=False, ie_key=result.get('ie_key'), process=False)
- self.assertEqual(YoutubeIE().extract_id(result['url']), 'FXxLjLQi3Fg')
-
- def test_youtube_mix(self):
- dl = FakeYDL()
- dl.params['format'] = 'best'
- ie = YoutubeTabIE(dl)
- result = dl.extract_info('https://www.youtube.com/watch?v=tyITL_exICo&list=RDCLAK5uy_kLWIr9gv1XLlPbaDS965-Db4TrBoUTxQ8',
- download=False, ie_key=ie.ie_key(), process=True)
- entries = (result or {}).get('entries', [{'id': 'not_found', }])
- self.assertTrue(len(entries) >= 25)
- original_video = entries[0]
- self.assertEqual(original_video['id'], 'tyITL_exICo')
-
- def test_youtube_flat_playlist_extraction(self):
- dl = FakeYDL()
- dl.params['extract_flat'] = True
- ie = YoutubeTabIE(dl)
- result = ie.extract('https://www.youtube.com/playlist?list=PL4lCao7KL_QFVb7Iudeipvc2BCavECqzc')
- self.assertIsPlaylist(result)
- entries = list(result['entries'])
- self.assertTrue(len(entries) == 1)
- video = entries[0]
- self.assertEqual(video['_type'], 'url')
- self.assertEqual(video['ie_key'], 'Youtube')
- self.assertEqual(video['id'], 'BaW_jenozKc')
- self.assertEqual(video['url'], 'BaW_jenozKc')
- self.assertEqual(video['title'], 'youtube-dl test video "\'/\\ä↭𝕐')
- self.assertEqual(video['duration'], 10)
- self.assertEqual(video['uploader'], 'Philipp Hagemeister')
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/test_youtube_misc.py b/test/test_youtube_misc.py
deleted file mode 100644
index e18e71101..000000000
--- a/test/test_youtube_misc.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env python
-from __future__ import unicode_literals
-
-# Allow direct execution
-import os
-import sys
-import unittest
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-
-from youtube_dl.extractor import YoutubeIE
-
-
-class TestYoutubeMisc(unittest.TestCase):
- def test_youtube_extract(self):
- assertExtractId = lambda url, id: self.assertEqual(YoutubeIE.extract_id(url), id)
- assertExtractId('http://www.youtube.com/watch?&v=BaW_jenozKc', 'BaW_jenozKc')
- assertExtractId('https://www.youtube.com/watch?&v=BaW_jenozKc', 'BaW_jenozKc')
- assertExtractId('https://www.youtube.com/watch?feature=player_embedded&v=BaW_jenozKc', 'BaW_jenozKc')
- assertExtractId('https://www.youtube.com/watch_popup?v=BaW_jenozKc', 'BaW_jenozKc')
- assertExtractId('http://www.youtube.com/watch?v=BaW_jenozKcsharePLED17F32AD9753930', 'BaW_jenozKc')
- assertExtractId('BaW_jenozKc', 'BaW_jenozKc')
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/test_youtube_signature.py b/test/test_youtube_signature.py
deleted file mode 100644
index 67ef75fde..000000000
--- a/test/test_youtube_signature.py
+++ /dev/null
@@ -1,312 +0,0 @@
-#!/usr/bin/env python
-# coding: utf-8
-
-from __future__ import unicode_literals
-
-# Allow direct execution
-import os
-import sys
-import unittest
-sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-import re
-import string
-
-from youtube_dl.compat import (
- compat_contextlib_suppress,
- compat_open as open,
- compat_str,
- compat_urlretrieve,
-)
-
-from test.helper import FakeYDL
-from youtube_dl.extractor import YoutubeIE
-from youtube_dl.jsinterp import JSInterpreter
-
-_SIG_TESTS = [
- (
- 'https://s.ytimg.com/yts/jsbin/html5player-vflHOr_nV.js',
- 86,
- '>=<;:/.-[+*)(\'&%$#"!ZYX0VUTSRQPONMLKJIHGFEDCBA\\yxwvutsrqponmlkjihgfedcba987654321',
- ),
- (
- 'https://s.ytimg.com/yts/jsbin/html5player-vfldJ8xgI.js',
- 85,
- '3456789a0cdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRS[UVWXYZ!"#$%&\'()*+,-./:;<=>?@',
- ),
- (
- 'https://s.ytimg.com/yts/jsbin/html5player-vfle-mVwz.js',
- 90,
- ']\\[@?>=<;:/.-,+*)(\'&%$#"hZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjiagfedcb39876',
- ),
- (
- 'https://s.ytimg.com/yts/jsbin/html5player-en_US-vfl0Cbn9e.js',
- 84,
- 'O1I3456789abcde0ghijklmnopqrstuvwxyzABCDEFGHfJKLMN2PQRSTUVW@YZ!"#$%&\'()*+,-./:;<=',
- ),
- (
- 'https://s.ytimg.com/yts/jsbin/html5player-en_US-vflXGBaUN.js',
- '2ACFC7A61CA478CD21425E5A57EBD73DDC78E22A.2094302436B2D377D14A3BBA23022D023B8BC25AA',
- 'A52CB8B320D22032ABB3A41D773D2B6342034902.A22E87CDD37DBE75A5E52412DC874AC16A7CFCA2',
- ),
- (
- 'https://s.ytimg.com/yts/jsbin/html5player-en_US-vflBb0OQx.js',
- 84,
- '123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQ0STUVWXYZ!"#$%&\'()*+,@./:;<=>',
- ),
- (
- 'https://s.ytimg.com/yts/jsbin/html5player-en_US-vfl9FYC6l.js',
- 83,
- '123456789abcdefghijklmnopqr0tuvwxyzABCDETGHIJKLMNOPQRS>UVWXYZ!"#$%&\'()*+,-./:;<=F',
- ),
- (
- 'https://s.ytimg.com/yts/jsbin/html5player-en_US-vflCGk6yw/html5player.js',
- '4646B5181C6C3020DF1D9C7FCFEA.AD80ABF70C39BD369CCCAE780AFBB98FA6B6CB42766249D9488C288',
- '82C8849D94266724DC6B6AF89BBFA087EACCD963.B93C07FBA084ACAEFCF7C9D1FD0203C6C1815B6B',
- ),
- (
- 'https://s.ytimg.com/yts/jsbin/html5player-en_US-vflKjOTVq/html5player.js',
- '312AA52209E3623129A412D56A40F11CB0AF14AE.3EE09501CB14E3BCDC3B2AE808BF3F1D14E7FBF12',
- '112AA5220913623229A412D56A40F11CB0AF14AE.3EE0950FCB14EEBCDC3B2AE808BF331D14E7FBF3',
- ),
- (
- 'https://www.youtube.com/s/player/6ed0d907/player_ias.vflset/en_US/base.js',
- '2aq0aqSyOoJXtK73m-uME_jv7-pT15gOFC02RFkGMqWpzEICs69VdbwQ0LDp1v7j8xx92efCJlYFYb1sUkkBSPOlPmXgIARw8JQ0qOAOAA',
- 'AOq0QJ8wRAIgXmPlOPSBkkUs1bYFYlJCfe29xx8j7v1pDL2QwbdV96sCIEzpWqMGkFR20CFOg51Tp-7vj_EMu-m37KtXJoOySqa0',
- ),
- (
- 'https://www.youtube.com/s/player/3bb1f723/player_ias.vflset/en_US/base.js',
- '2aq0aqSyOoJXtK73m-uME_jv7-pT15gOFC02RFkGMqWpzEICs69VdbwQ0LDp1v7j8xx92efCJlYFYb1sUkkBSPOlPmXgIARw8JQ0qOAOAA',
- 'MyOSJXtKI3m-uME_jv7-pT12gOFC02RFkGoqWpzE0Cs69VdbwQ0LDp1v7j8xx92efCJlYFYb1sUkkBSPOlPmXgIARw8JQ0qOAOAA',
- ),
- (
- 'https://www.youtube.com/s/player/2f1832d2/player_ias.vflset/en_US/base.js',
- '2aq0aqSyOoJXtK73m-uME_jv7-pT15gOFC02RFkGMqWpzEICs69VdbwQ0LDp1v7j8xx92efCJlYFYb1sUkkBSPOlPmXgIARw8JQ0qOAOAA',
- '0QJ8wRAIgXmPlOPSBkkUs1bYFYlJCfe29xxAj7v1pDL0QwbdV96sCIEzpWqMGkFR20CFOg51Tp-7vj_EMu-m37KtXJ2OySqa0q',
- ),
-]
-
-_NSIG_TESTS = [
- (
- 'https://www.youtube.com/s/player/7862ca1f/player_ias.vflset/en_US/base.js',
- 'X_LCxVDjAavgE5t', 'yxJ1dM6iz5ogUg',
- ),
- (
- 'https://www.youtube.com/s/player/9216d1f7/player_ias.vflset/en_US/base.js',
- 'SLp9F5bwjAdhE9F-', 'gWnb9IK2DJ8Q1w',
- ),
- (
- 'https://www.youtube.com/s/player/f8cb7a3b/player_ias.vflset/en_US/base.js',
- 'oBo2h5euWy6osrUt', 'ivXHpm7qJjJN',
- ),
- (
- 'https://www.youtube.com/s/player/2dfe380c/player_ias.vflset/en_US/base.js',
- 'oBo2h5euWy6osrUt', '3DIBbn3qdQ',
- ),
- (
- 'https://www.youtube.com/s/player/f1ca6900/player_ias.vflset/en_US/base.js',
- 'cu3wyu6LQn2hse', 'jvxetvmlI9AN9Q',
- ),
- (
- 'https://www.youtube.com/s/player/8040e515/player_ias.vflset/en_US/base.js',
- 'wvOFaY-yjgDuIEg5', 'HkfBFDHmgw4rsw',
- ),
- (
- 'https://www.youtube.com/s/player/e06dea74/player_ias.vflset/en_US/base.js',
- 'AiuodmaDDYw8d3y4bf', 'ankd8eza2T6Qmw',
- ),
- (
- 'https://www.youtube.com/s/player/5dd88d1d/player-plasma-ias-phone-en_US.vflset/base.js',
- 'kSxKFLeqzv_ZyHSAt', 'n8gS8oRlHOxPFA',
- ),
- (
- 'https://www.youtube.com/s/player/324f67b9/player_ias.vflset/en_US/base.js',
- 'xdftNy7dh9QGnhW', '22qLGxrmX8F1rA',
- ),
- (
- 'https://www.youtube.com/s/player/4c3f79c5/player_ias.vflset/en_US/base.js',
- 'TDCstCG66tEAO5pR9o', 'dbxNtZ14c-yWyw',
- ),
- (
- 'https://www.youtube.com/s/player/c81bbb4a/player_ias.vflset/en_US/base.js',
- 'gre3EcLurNY2vqp94', 'Z9DfGxWP115WTg',
- ),
- (
- 'https://www.youtube.com/s/player/1f7d5369/player_ias.vflset/en_US/base.js',
- 'batNX7sYqIJdkJ', 'IhOkL_zxbkOZBw',
- ),
- (
- 'https://www.youtube.com/s/player/009f1d77/player_ias.vflset/en_US/base.js',
- '5dwFHw8aFWQUQtffRq', 'audescmLUzI3jw',
- ),
- (
- 'https://www.youtube.com/s/player/dc0c6770/player_ias.vflset/en_US/base.js',
- '5EHDMgYLV6HPGk_Mu-kk', 'n9lUJLHbxUI0GQ',
- ),
- (
- 'https://www.youtube.com/s/player/c2199353/player_ias.vflset/en_US/base.js',
- '5EHDMgYLV6HPGk_Mu-kk', 'AD5rgS85EkrE7',
- ),
- (
- 'https://www.youtube.com/s/player/113ca41c/player_ias.vflset/en_US/base.js',
- 'cgYl-tlYkhjT7A', 'hI7BBr2zUgcmMg',
- ),
- (
- 'https://www.youtube.com/s/player/c57c113c/player_ias.vflset/en_US/base.js',
- '-Txvy6bT5R6LqgnQNx', 'dcklJCnRUHbgSg',
- ),
- (
- 'https://www.youtube.com/s/player/5a3b6271/player_ias.vflset/en_US/base.js',
- 'B2j7f_UPT4rfje85Lu_e', 'm5DmNymaGQ5RdQ',
- ),
- (
- 'https://www.youtube.com/s/player/7a062b77/player_ias.vflset/en_US/base.js',
- 'NRcE3y3mVtm_cV-W', 'VbsCYUATvqlt5w',
- ),
- (
- 'https://www.youtube.com/s/player/dac945fd/player_ias.vflset/en_US/base.js',
- 'o8BkRxXhuYsBCWi6RplPdP', '3Lx32v_hmzTm6A',
- ),
- (
- 'https://www.youtube.com/s/player/6f20102c/player_ias.vflset/en_US/base.js',
- 'lE8DhoDmKqnmJJ', 'pJTTX6XyJP2BYw',
- ),
- (
- 'https://www.youtube.com/s/player/cfa9e7cb/player_ias.vflset/en_US/base.js',
- 'qO0NiMtYQ7TeJnfFG2', 'k9cuJDHNS5O7kQ',
- ),
- (
- 'https://www.youtube.com/s/player/8c7583ff/player_ias.vflset/en_US/base.js',
- '1wWCVpRR96eAmMI87L', 'KSkWAVv1ZQxC3A',
- ),
- (
- 'https://www.youtube.com/s/player/b7910ca8/player_ias.vflset/en_US/base.js',
- '_hXMCwMt9qE310D', 'LoZMgkkofRMCZQ',
- ),
- (
- 'https://www.youtube.com/s/player/590f65a6/player_ias.vflset/en_US/base.js',
- '1tm7-g_A9zsI8_Lay_', 'xI4Vem4Put_rOg',
- ),
- (
- 'https://www.youtube.com/s/player/b22ef6e7/player_ias.vflset/en_US/base.js',
- 'b6HcntHGkvBLk_FRf', 'kNPW6A7FyP2l8A',
- ),
- (
- 'https://www.youtube.com/s/player/3400486c/player_ias.vflset/en_US/base.js',
- 'lL46g3XifCKUZn1Xfw', 'z767lhet6V2Skl',
- ),
- (
- 'https://www.youtube.com/s/player/5604538d/player_ias.vflset/en_US/base.js',
- '7X-he4jjvMx7BCX', 'sViSydX8IHtdWA',
- ),
- (
- 'https://www.youtube.com/s/player/20dfca59/player_ias.vflset/en_US/base.js',
- '-fLCxedkAk4LUTK2', 'O8kfRq1y1eyHGw',
- ),
- (
- 'https://www.youtube.com/s/player/b12cc44b/player_ias.vflset/en_US/base.js',
- 'keLa5R2U00sR9SQK', 'N1OGyujjEwMnLw',
- ),
- (
- 'https://www.youtube.com/s/player/3bb1f723/player_ias.vflset/en_US/base.js',
- 'gK15nzVyaXE9RsMP3z', 'ZFFWFLPWx9DEgQ',
- ),
- (
- 'https://www.youtube.com/s/player/f8f53e1a/player_ias.vflset/en_US/base.js',
- 'VTQOUOv0mCIeJ7i8kZB', 'kcfD8wy0sNLyNQ',
- ),
- (
- 'https://www.youtube.com/s/player/2f1832d2/player_ias.vflset/en_US/base.js',
- 'YWt1qdbe8SAfkoPHW5d', 'RrRjWQOJmBiP',
- ),
- (
- 'https://www.youtube.com/s/player/9c6dfc4a/player_ias.vflset/en_US/base.js',
- 'jbu7ylIosQHyJyJV', 'uwI0ESiynAmhNg',
- ),
-]
-
-
-class TestPlayerInfo(unittest.TestCase):
- def test_youtube_extract_player_info(self):
- PLAYER_URLS = (
- ('https://www.youtube.com/s/player/4c3f79c5/player_ias.vflset/en_US/base.js', '4c3f79c5'),
- ('https://www.youtube.com/s/player/64dddad9/player_ias.vflset/en_US/base.js', '64dddad9'),
- ('https://www.youtube.com/s/player/64dddad9/player_ias.vflset/fr_FR/base.js', '64dddad9'),
- ('https://www.youtube.com/s/player/64dddad9/player-plasma-ias-phone-en_US.vflset/base.js', '64dddad9'),
- ('https://www.youtube.com/s/player/64dddad9/player-plasma-ias-phone-de_DE.vflset/base.js', '64dddad9'),
- ('https://www.youtube.com/s/player/64dddad9/player-plasma-ias-tablet-en_US.vflset/base.js', '64dddad9'),
- # obsolete
- ('https://www.youtube.com/yts/jsbin/player_ias-vfle4-e03/en_US/base.js', 'vfle4-e03'),
- ('https://www.youtube.com/yts/jsbin/player_ias-vfl49f_g4/en_US/base.js', 'vfl49f_g4'),
- ('https://www.youtube.com/yts/jsbin/player_ias-vflCPQUIL/en_US/base.js', 'vflCPQUIL'),
- ('https://www.youtube.com/yts/jsbin/player-vflzQZbt7/en_US/base.js', 'vflzQZbt7'),
- ('https://www.youtube.com/yts/jsbin/player-en_US-vflaxXRn1/base.js', 'vflaxXRn1'),
- ('https://s.ytimg.com/yts/jsbin/html5player-en_US-vflXGBaUN.js', 'vflXGBaUN'),
- ('https://s.ytimg.com/yts/jsbin/html5player-en_US-vflKjOTVq/html5player.js', 'vflKjOTVq'),
- )
- for player_url, expected_player_id in PLAYER_URLS:
- player_id = YoutubeIE._extract_player_info(player_url)
- self.assertEqual(player_id, expected_player_id)
-
-
-class TestSignature(unittest.TestCase):
- def setUp(self):
- TEST_DIR = os.path.dirname(os.path.abspath(__file__))
- self.TESTDATA_DIR = os.path.join(TEST_DIR, 'testdata/sigs')
- if not os.path.exists(self.TESTDATA_DIR):
- os.mkdir(self.TESTDATA_DIR)
-
- def tearDown(self):
- with compat_contextlib_suppress(OSError):
- for f in os.listdir(self.TESTDATA_DIR):
- os.remove(f)
-
-
-def t_factory(name, sig_func, url_pattern):
- def make_tfunc(url, sig_input, expected_sig):
- m = url_pattern.match(url)
- assert m, '%r should follow URL format' % url
- test_id = m.group('id')
-
- def test_func(self):
- basename = 'player-{0}-{1}.js'.format(name, test_id)
- fn = os.path.join(self.TESTDATA_DIR, basename)
-
- if not os.path.exists(fn):
- compat_urlretrieve(url, fn)
- with open(fn, encoding='utf-8') as testf:
- jscode = testf.read()
- self.assertEqual(sig_func(jscode, sig_input), expected_sig)
-
- test_func.__name__ = str('test_{0}_js_{1}'.format(name, test_id))
- setattr(TestSignature, test_func.__name__, test_func)
- return make_tfunc
-
-
-def signature(jscode, sig_input):
- func = YoutubeIE(FakeYDL())._parse_sig_js(jscode)
- src_sig = (
- compat_str(string.printable[:sig_input])
- if isinstance(sig_input, int) else sig_input)
- return func(src_sig)
-
-
-def n_sig(jscode, sig_input):
- funcname = YoutubeIE(FakeYDL())._extract_n_function_name(jscode)
- return JSInterpreter(jscode).call_function(
- funcname, sig_input, _ytdl_do_not_return=sig_input)
-
-
-make_sig_test = t_factory(
- 'signature', signature, re.compile(r'.*(?:-|/player/)(?P[a-zA-Z0-9_-]+)(?:/.+\.js|(?:/watch_as3|/html5player)?\.[a-z]+)$'))
-for test_spec in _SIG_TESTS:
- make_sig_test(*test_spec)
-
-make_nsig_test = t_factory(
- 'nsig', n_sig, re.compile(r'.+/player/(?P[a-zA-Z0-9_-]+)/.+.js$'))
-for test_spec in _NSIG_TESTS:
- make_nsig_test(*test_spec)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/testcert.pem b/test/testcert.pem
deleted file mode 100644
index b3e0f00c7..000000000
--- a/test/testcert.pem
+++ /dev/null
@@ -1,52 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDMF0bAzaHAdIyB
-HRmnIp4vv40lGqEePmWqicCl0QZ0wsb5dNysSxSa7330M2QeQopGfdaUYF1uTcNp
-Qx6ECgBSfg+RrOBI7r/u4F+sKX8MUXVaf/5QoBUrGNGSn/pp7HMGOuQqO6BVg4+h
-A1ySSwUG8mZItLRry1ISyErmW8b9xlqfd97uLME/5tX+sMelRFjUbAx8A4CK58Ev
-mMguHVTlXzx5RMdYcf1VScYcjlV/qA45uzP8zwI5aigfcmUD+tbGuQRhKxUhmw0J
-aobtOR6+JSOAULW5gYa/egE4dWLwbyM6b6eFbdnjlQzEA1EW7ChMPAW/Mo83KyiP
-tKMCSQulAgMBAAECggEALCfBDAexPjU5DNoh6bIorUXxIJzxTNzNHCdvgbCGiA54
-BBKPh8s6qwazpnjT6WQWDIg/O5zZufqjE4wM9x4+0Zoqfib742ucJO9wY4way6x4
-Clt0xzbLPabB+MoZ4H7ip+9n2+dImhe7pGdYyOHoNYeOL57BBi1YFW42Hj6u/8pd
-63YCXisto3Rz1YvRQVjwsrS+cRKZlzAFQRviL30jav7Wh1aWEfcXxjj4zhm8pJdk
-ITGtq6howz57M0NtX6hZnfe8ywzTnDFIGKIMA2cYHuYJcBh9bc4tCGubTvTKK9UE
-8fM+f6UbfGqfpKCq1mcgs0XMoFDSzKS9+mSJn0+5JQKBgQD+OCKaeH3Yzw5zGnlw
-XuQfMJGNcgNr+ImjmvzUAC2fAZUJLAcQueE5kzMv5Fmd+EFE2CEX1Vit3tg0SXvA
-G+bq609doILHMA03JHnV1npO/YNIhG3AAtJlKYGxQNfWH9mflYj9mEui8ZFxG52o
-zWhHYuifOjjZszUR+/eio6NPzwKBgQDNhUBTrT8LIX4SE/EFUiTlYmWIvOMgXYvN
-8Cm3IRNQ/yyphZaXEU0eJzfX5uCDfSVOgd6YM/2pRah+t+1Hvey4H8e0GVTu5wMP
-gkkqwKPGIR1YOmlw6ippqwvoJD7LuYrm6Q4D6e1PvkjwCq6lEndrOPmPrrXNd0JJ
-XO60y3U2SwKBgQDLkyZarryQXxcCI6Q10Tc6pskYDMIit095PUbTeiUOXNT9GE28
-Hi32ziLCakk9kCysNasii81MxtQ54tJ/f5iGbNMMddnkKl2a19Hc5LjjAm4cJzg/
-98KGEhvyVqvAo5bBDZ06/rcrD+lZOzUglQS5jcIcqCIYa0LHWQ/wJLxFzwKBgFcZ
-1SRhdSmDfUmuF+S4ZpistflYjC3IV5rk4NkS9HvMWaJS0nqdw4A3AMzItXgkjq4S
-DkOVLTkTI5Do5HAWRv/VwC5M2hkR4NMu1VGAKSisGiKtRsirBWSZMEenLNHshbjN
-Jrpz5rZ4H7NT46ZkCCZyFBpX4gb9NyOedjA7Via3AoGARF8RxbYjnEGGFuhnbrJB
-FTPR0vaL4faY3lOgRZ8jOG9V2c9Hzi/y8a8TU4C11jnJSDqYCXBTd5XN28npYxtD
-pjRsCwy6ze+yvYXPO7C978eMG3YRyj366NXUxnXN59ibwe/lxi2OD9z8J1LEdF6z
-VJua1Wn8HKxnXMI61DhTCSo=
------END PRIVATE KEY-----
------BEGIN CERTIFICATE-----
-MIIEEzCCAvugAwIBAgIJAK1haYi6gmSKMA0GCSqGSIb3DQEBCwUAMIGeMQswCQYD
-VQQGEwJERTEMMAoGA1UECAwDTlJXMRQwEgYDVQQHDAtEdWVzc2VsZG9yZjEbMBkG
-A1UECgwSeW91dHViZS1kbCBwcm9qZWN0MRkwFwYDVQQLDBB5b3V0dWJlLWRsIHRl
-c3RzMRIwEAYDVQQDDAlsb2NhbGhvc3QxHzAdBgkqhkiG9w0BCQEWEHBoaWhhZ0Bw
-aGloYWcuZGUwIBcNMTUwMTMwMDExNTA4WhgPMjExNTAxMDYwMTE1MDhaMIGeMQsw
-CQYDVQQGEwJERTEMMAoGA1UECAwDTlJXMRQwEgYDVQQHDAtEdWVzc2VsZG9yZjEb
-MBkGA1UECgwSeW91dHViZS1kbCBwcm9qZWN0MRkwFwYDVQQLDBB5b3V0dWJlLWRs
-IHRlc3RzMRIwEAYDVQQDDAlsb2NhbGhvc3QxHzAdBgkqhkiG9w0BCQEWEHBoaWhh
-Z0BwaGloYWcuZGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDMF0bA
-zaHAdIyBHRmnIp4vv40lGqEePmWqicCl0QZ0wsb5dNysSxSa7330M2QeQopGfdaU
-YF1uTcNpQx6ECgBSfg+RrOBI7r/u4F+sKX8MUXVaf/5QoBUrGNGSn/pp7HMGOuQq
-O6BVg4+hA1ySSwUG8mZItLRry1ISyErmW8b9xlqfd97uLME/5tX+sMelRFjUbAx8
-A4CK58EvmMguHVTlXzx5RMdYcf1VScYcjlV/qA45uzP8zwI5aigfcmUD+tbGuQRh
-KxUhmw0JaobtOR6+JSOAULW5gYa/egE4dWLwbyM6b6eFbdnjlQzEA1EW7ChMPAW/
-Mo83KyiPtKMCSQulAgMBAAGjUDBOMB0GA1UdDgQWBBTBUZoqhQkzHQ6xNgZfFxOd
-ZEVt8TAfBgNVHSMEGDAWgBTBUZoqhQkzHQ6xNgZfFxOdZEVt8TAMBgNVHRMEBTAD
-AQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCUOCl3T/J9B08Z+ijfOJAtkbUaEHuVZb4x
-5EpZSy2ZbkLvtsftMFieHVNXn9dDswQc5qjYStCC4o60LKw4M6Y63FRsAZ/DNaqb
-PY3jyCyuugZ8/sNf50vHYkAcF7SQYqOQFQX4TQsNUk2xMJIt7H0ErQFmkf/u3dg6
-cy89zkT462IwxzSG7NNhIlRkL9o5qg+Y1mF9eZA1B0rcL6hO24PPTHOd90HDChBu
-SZ6XMi/LzYQSTf0Vg2R+uMIVlzSlkdcZ6sqVnnqeLL8dFyIa4e9sj/D4ZCYP8Mqe
-Z73H5/NNhmwCHRqVUTgm307xblQaWGhwAiDkaRvRW2aJQ0qGEdZK
------END CERTIFICATE-----
diff --git a/test/testdata/cookies/httponly_cookies.txt b/test/testdata/cookies/httponly_cookies.txt
deleted file mode 100644
index c46541d6b..000000000
--- a/test/testdata/cookies/httponly_cookies.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-# Netscape HTTP Cookie File
-# http://curl.haxx.se/rfc/cookie_spec.html
-# This is a generated file! Do not edit.
-
-#HttpOnly_www.foobar.foobar FALSE / TRUE 2147483647 HTTPONLY_COOKIE HTTPONLY_COOKIE_VALUE
-www.foobar.foobar FALSE / TRUE 2147483647 JS_ACCESSIBLE_COOKIE JS_ACCESSIBLE_COOKIE_VALUE
diff --git a/test/testdata/cookies/malformed_cookies.txt b/test/testdata/cookies/malformed_cookies.txt
deleted file mode 100644
index 17bc40354..000000000
--- a/test/testdata/cookies/malformed_cookies.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-# Netscape HTTP Cookie File
-# http://curl.haxx.se/rfc/cookie_spec.html
-# This is a generated file! Do not edit.
-
-# Cookie file entry with invalid number of fields - 6 instead of 7
-www.foobar.foobar FALSE / FALSE 0 COOKIE
-
-# Cookie file entry with invalid expires at
-www.foobar.foobar FALSE / FALSE 1.7976931348623157e+308 COOKIE VALUE
diff --git a/test/testdata/cookies/session_cookies.txt b/test/testdata/cookies/session_cookies.txt
deleted file mode 100644
index f6996f031..000000000
--- a/test/testdata/cookies/session_cookies.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-# Netscape HTTP Cookie File
-# http://curl.haxx.se/rfc/cookie_spec.html
-# This is a generated file! Do not edit.
-
-www.foobar.foobar FALSE / TRUE YoutubeDLExpiresEmpty YoutubeDLExpiresEmptyValue
-www.foobar.foobar FALSE / TRUE 0 YoutubeDLExpires0 YoutubeDLExpires0Value
diff --git a/test/testdata/f4m/custom_base_url.f4m b/test/testdata/f4m/custom_base_url.f4m
deleted file mode 100644
index 74e1539e8..000000000
--- a/test/testdata/f4m/custom_base_url.f4m
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
- recorded
- http://vod.livestream.com/events/0000000000673980/
- 269.293
- AAAAm2Fic3QAAAAAAAAAAQAAAAPoAAAAAAAEG+0AAAAAAAAAAAAAAAAAAQAAABlhc3J0AAAAAAAAAAABAAAAAQAAAC4BAAAAVmFmcnQAAAAAAAAD6AAAAAAEAAAAAQAAAAAAAAAAAAAXcAAAAC0AAAAAAAQHQAAAE5UAAAAuAAAAAAAEGtUAAAEYAAAAAAAAAAAAAAAAAAAAAAA=
-
- AgAKb25NZXRhRGF0YQgAAAAIAAhkdXJhdGlvbgBAcNSwIMSbpgAFd2lkdGgAQJQAAAAAAAAABmhlaWdodABAhoAAAAAAAAAJZnJhbWVyYXRlAEA4/7DoLwW3AA12aWRlb2RhdGFyYXRlAECe1DLgjcobAAx2aWRlb2NvZGVjaWQAQBwAAAAAAAAADWF1ZGlvZGF0YXJhdGUAQGSimlvaPKQADGF1ZGlvY29kZWNpZABAJAAAAAAAAAAACQ==
-
-
diff --git a/test/testdata/m3u8/pluzz_francetv_11507.m3u8 b/test/testdata/m3u8/pluzz_francetv_11507.m3u8
deleted file mode 100644
index 0809f5aa0..000000000
--- a/test/testdata/m3u8/pluzz_francetv_11507.m3u8
+++ /dev/null
@@ -1,14 +0,0 @@
-#EXTM3U
-
#EXT-X-VERSION:5
-
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="Francais",DEFAULT=NO,FORCED=NO,URI="http://replayftv-pmd.francetv.fr/subtitles/2017/16/156589847-1492488987.m3u8",LANGUAGE="fra"
-
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",LANGUAGE="fra",NAME="Francais",DEFAULT=YES, AUTOSELECT=YES
-#EXT-X-STREAM-INF:SUBTITLES="subs",AUDIO="aac",PROGRAM-ID=1,BANDWIDTH=180000,RESOLUTION=256x144,CODECS="avc1.66.30, mp4a.40.2"
-http://replayftv-vh.akamaihd.net/i/streaming-adaptatif_france-dom-tom/2017/S16/J2/156589847-58f59130c1f52-,standard1,standard2,standard3,standard4,standard5,.mp4.csmil/index_0_av.m3u8?null=0
-#EXT-X-STREAM-INF:SUBTITLES="subs",AUDIO="aac",PROGRAM-ID=1,BANDWIDTH=303000,RESOLUTION=320x180,CODECS="avc1.66.30, mp4a.40.2"
-http://replayftv-vh.akamaihd.net/i/streaming-adaptatif_france-dom-tom/2017/S16/J2/156589847-58f59130c1f52-,standard1,standard2,standard3,standard4,standard5,.mp4.csmil/index_1_av.m3u8?null=0
-#EXT-X-STREAM-INF:SUBTITLES="subs",AUDIO="aac",PROGRAM-ID=1,BANDWIDTH=575000,RESOLUTION=512x288,CODECS="avc1.66.30, mp4a.40.2"
-http://replayftv-vh.akamaihd.net/i/streaming-adaptatif_france-dom-tom/2017/S16/J2/156589847-58f59130c1f52-,standard1,standard2,standard3,standard4,standard5,.mp4.csmil/index_2_av.m3u8?null=0
-#EXT-X-STREAM-INF:SUBTITLES="subs",AUDIO="aac",PROGRAM-ID=1,BANDWIDTH=831000,RESOLUTION=704x396,CODECS="avc1.77.30, mp4a.40.2"
-http://replayftv-vh.akamaihd.net/i/streaming-adaptatif_france-dom-tom/2017/S16/J2/156589847-58f59130c1f52-,standard1,standard2,standard3,standard4,standard5,.mp4.csmil/index_3_av.m3u8?null=0
-#EXT-X-STREAM-INF:SUBTITLES="subs",AUDIO="aac",PROGRAM-ID=1,BANDWIDTH=1467000,RESOLUTION=1024x576,CODECS="avc1.77.30, mp4a.40.2"
-http://replayftv-vh.akamaihd.net/i/streaming-adaptatif_france-dom-tom/2017/S16/J2/156589847-58f59130c1f52-,standard1,standard2,standard3,standard4,standard5,.mp4.csmil/index_4_av.m3u8?null=0
diff --git a/test/testdata/m3u8/teamcoco_11995.m3u8 b/test/testdata/m3u8/teamcoco_11995.m3u8
deleted file mode 100644
index a6e421697..000000000
--- a/test/testdata/m3u8/teamcoco_11995.m3u8
+++ /dev/null
@@ -1,16 +0,0 @@
-#EXTM3U
-#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio-0",NAME="Default",AUTOSELECT=YES,DEFAULT=YES,URI="hls/CONAN_020217_Highlight_show-audio-160k_v4.m3u8"
-#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio-1",NAME="Default",AUTOSELECT=YES,DEFAULT=YES,URI="hls/CONAN_020217_Highlight_show-audio-64k_v4.m3u8"
-#EXT-X-I-FRAME-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=37862000,CODECS="avc1.4d001f",URI="hls/CONAN_020217_Highlight_show-2m_iframe.m3u8"
-#EXT-X-I-FRAME-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=18750000,CODECS="avc1.4d001e",URI="hls/CONAN_020217_Highlight_show-1m_iframe.m3u8"
-#EXT-X-I-FRAME-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=6535000,CODECS="avc1.42001e",URI="hls/CONAN_020217_Highlight_show-400k_iframe.m3u8"
-#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2374000,RESOLUTION=1024x576,CODECS="avc1.4d001f,mp4a.40.2",AUDIO="audio-0"
-hls/CONAN_020217_Highlight_show-2m_v4.m3u8
-#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1205000,RESOLUTION=640x360,CODECS="avc1.4d001e,mp4a.40.2",AUDIO="audio-0"
-hls/CONAN_020217_Highlight_show-1m_v4.m3u8
-#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=522000,RESOLUTION=400x224,CODECS="avc1.42001e,mp4a.40.2",AUDIO="audio-0"
-hls/CONAN_020217_Highlight_show-400k_v4.m3u8
-#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=413000,RESOLUTION=400x224,CODECS="avc1.42001e,mp4a.40.5",AUDIO="audio-1"
-hls/CONAN_020217_Highlight_show-400k_v4.m3u8
-#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=71000,CODECS="mp4a.40.5",AUDIO="audio-1"
-hls/CONAN_020217_Highlight_show-audio-64k_v4.m3u8
diff --git a/test/testdata/m3u8/ted_18923.m3u8 b/test/testdata/m3u8/ted_18923.m3u8
deleted file mode 100644
index 52a27118b..000000000
--- a/test/testdata/m3u8/ted_18923.m3u8
+++ /dev/null
@@ -1,28 +0,0 @@
-#EXTM3U
-#EXT-X-VERSION:4
-#EXT-X-STREAM-INF:AUDIO="600k",BANDWIDTH=1255659,PROGRAM-ID=1,CODECS="avc1.42c01e,mp4a.40.2",RESOLUTION=640x360
-/videos/BorisHesser_2018S/video/600k.m3u8?nobumpers=true&uniqueId=76011e2b
-#EXT-X-STREAM-INF:AUDIO="600k",BANDWIDTH=163154,PROGRAM-ID=1,CODECS="avc1.42c00c,mp4a.40.2",RESOLUTION=320x180
-/videos/BorisHesser_2018S/video/64k.m3u8?nobumpers=true&uniqueId=76011e2b
-#EXT-X-STREAM-INF:AUDIO="600k",BANDWIDTH=481701,PROGRAM-ID=1,CODECS="avc1.42c015,mp4a.40.2",RESOLUTION=512x288
-/videos/BorisHesser_2018S/video/180k.m3u8?nobumpers=true&uniqueId=76011e2b
-#EXT-X-STREAM-INF:AUDIO="600k",BANDWIDTH=769968,PROGRAM-ID=1,CODECS="avc1.42c015,mp4a.40.2",RESOLUTION=512x288
-/videos/BorisHesser_2018S/video/320k.m3u8?nobumpers=true&uniqueId=76011e2b
-#EXT-X-STREAM-INF:AUDIO="600k",BANDWIDTH=984037,PROGRAM-ID=1,CODECS="avc1.42c015,mp4a.40.2",RESOLUTION=512x288
-/videos/BorisHesser_2018S/video/450k.m3u8?nobumpers=true&uniqueId=76011e2b
-#EXT-X-STREAM-INF:AUDIO="600k",BANDWIDTH=1693925,PROGRAM-ID=1,CODECS="avc1.4d401f,mp4a.40.2",RESOLUTION=853x480
-/videos/BorisHesser_2018S/video/950k.m3u8?nobumpers=true&uniqueId=76011e2b
-#EXT-X-STREAM-INF:AUDIO="600k",BANDWIDTH=2462469,PROGRAM-ID=1,CODECS="avc1.640028,mp4a.40.2",RESOLUTION=1280x720
-/videos/BorisHesser_2018S/video/1500k.m3u8?nobumpers=true&uniqueId=76011e2b
-#EXT-X-STREAM-INF:AUDIO="600k",BANDWIDTH=68101,PROGRAM-ID=1,CODECS="mp4a.40.2",DEFAULT=YES
-/videos/BorisHesser_2018S/audio/600k.m3u8?nobumpers=true&uniqueId=76011e2b
-
-#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=74298,PROGRAM-ID=1,CODECS="avc1.42c00c",RESOLUTION=320x180,URI="/videos/BorisHesser_2018S/video/64k_iframe.m3u8?nobumpers=true&uniqueId=76011e2b"
-#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=216200,PROGRAM-ID=1,CODECS="avc1.42c015",RESOLUTION=512x288,URI="/videos/BorisHesser_2018S/video/180k_iframe.m3u8?nobumpers=true&uniqueId=76011e2b"
-#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=304717,PROGRAM-ID=1,CODECS="avc1.42c015",RESOLUTION=512x288,URI="/videos/BorisHesser_2018S/video/320k_iframe.m3u8?nobumpers=true&uniqueId=76011e2b"
-#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=350933,PROGRAM-ID=1,CODECS="avc1.42c015",RESOLUTION=512x288,URI="/videos/BorisHesser_2018S/video/450k_iframe.m3u8?nobumpers=true&uniqueId=76011e2b"
-#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=495850,PROGRAM-ID=1,CODECS="avc1.42c01e",RESOLUTION=640x360,URI="/videos/BorisHesser_2018S/video/600k_iframe.m3u8?nobumpers=true&uniqueId=76011e2b"
-#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=810750,PROGRAM-ID=1,CODECS="avc1.4d401f",RESOLUTION=853x480,URI="/videos/BorisHesser_2018S/video/950k_iframe.m3u8?nobumpers=true&uniqueId=76011e2b"
-#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=1273700,PROGRAM-ID=1,CODECS="avc1.640028",RESOLUTION=1280x720,URI="/videos/BorisHesser_2018S/video/1500k_iframe.m3u8?nobumpers=true&uniqueId=76011e2b"
-
-#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="600k",LANGUAGE="en",NAME="Audio",AUTOSELECT=YES,DEFAULT=YES,URI="/videos/BorisHesser_2018S/audio/600k.m3u8?nobumpers=true&uniqueId=76011e2b",BANDWIDTH=614400
diff --git a/test/testdata/m3u8/toggle_mobile_12211.m3u8 b/test/testdata/m3u8/toggle_mobile_12211.m3u8
deleted file mode 100644
index 69604e683..000000000
--- a/test/testdata/m3u8/toggle_mobile_12211.m3u8
+++ /dev/null
@@ -1,13 +0,0 @@
-#EXTM3U
-#EXT-X-VERSION:4
-#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",LANGUAGE="eng",NAME="English",URI="http://k.toggle.sg/fhls/p/2082311/sp/208231100/serveFlavor/entryId/0_89q6e8ku/v/2/pv/1/flavorId/0_sa2ntrdg/name/a.mp4/index.m3u8"
-#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",LANGUAGE="und",NAME="Undefined",URI="http://k.toggle.sg/fhls/p/2082311/sp/208231100/serveFlavor/entryId/0_89q6e8ku/v/2/pv/1/flavorId/0_r7y0nitg/name/a.mp4/index.m3u8"
-
-#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=155648,RESOLUTION=320x180,AUDIO="audio"
-http://k.toggle.sg/fhls/p/2082311/sp/208231100/serveFlavor/entryId/0_89q6e8ku/v/2/pv/1/flavorId/0_qlk9hlzr/name/a.mp4/index.m3u8
-#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=502784,RESOLUTION=480x270,AUDIO="audio"
-http://k.toggle.sg/fhls/p/2082311/sp/208231100/serveFlavor/entryId/0_89q6e8ku/v/2/pv/1/flavorId/0_oefackmi/name/a.mp4/index.m3u8
-#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=827392,RESOLUTION=640x360,AUDIO="audio"
-http://k.toggle.sg/fhls/p/2082311/sp/208231100/serveFlavor/entryId/0_89q6e8ku/v/12/pv/1/flavorId/0_vyg9pj7k/name/a.mp4/index.m3u8
-#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1396736,RESOLUTION=854x480,AUDIO="audio"
-http://k.toggle.sg/fhls/p/2082311/sp/208231100/serveFlavor/entryId/0_89q6e8ku/v/12/pv/1/flavorId/0_50n4psvx/name/a.mp4/index.m3u8
diff --git a/test/testdata/m3u8/twitch_vod.m3u8 b/test/testdata/m3u8/twitch_vod.m3u8
deleted file mode 100644
index 7617277ca..000000000
--- a/test/testdata/m3u8/twitch_vod.m3u8
+++ /dev/null
@@ -1,20 +0,0 @@
-#EXTM3U
-#EXT-X-TWITCH-INFO:ORIGIN="s3",CLUSTER="edgecast_vod",REGION="EU",MANIFEST-CLUSTER="edgecast_vod",USER-IP="109.171.17.81"
-#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="chunked",NAME="Source",AUTOSELECT=YES,DEFAULT=YES
-#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=3214134,CODECS="avc1.100.31,mp4a.40.2",RESOLUTION="1280x720",VIDEO="chunked"
-https://vod.edgecast.hls.ttvnw.net/e5da31ab49_riotgames_15001215120_261543898/chunked/index-muted-HM49I092CC.m3u8
-#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="high",NAME="High",AUTOSELECT=YES,DEFAULT=YES
-#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1603789,CODECS="avc1.42C01F,mp4a.40.2",RESOLUTION="1280x720",VIDEO="high"
-https://vod.edgecast.hls.ttvnw.net/e5da31ab49_riotgames_15001215120_261543898/high/index-muted-HM49I092CC.m3u8
-#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="medium",NAME="Medium",AUTOSELECT=YES,DEFAULT=YES
-#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=893387,CODECS="avc1.42C01E,mp4a.40.2",RESOLUTION="852x480",VIDEO="medium"
-https://vod.edgecast.hls.ttvnw.net/e5da31ab49_riotgames_15001215120_261543898/medium/index-muted-HM49I092CC.m3u8
-#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="low",NAME="Low",AUTOSELECT=YES,DEFAULT=YES
-#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=628347,CODECS="avc1.42C01E,mp4a.40.2",RESOLUTION="640x360",VIDEO="low"
-https://vod.edgecast.hls.ttvnw.net/e5da31ab49_riotgames_15001215120_261543898/low/index-muted-HM49I092CC.m3u8
-#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="mobile",NAME="Mobile",AUTOSELECT=YES,DEFAULT=YES
-#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=280474,CODECS="avc1.42C00D,mp4a.40.2",RESOLUTION="400x226",VIDEO="mobile"
-https://vod.edgecast.hls.ttvnw.net/e5da31ab49_riotgames_15001215120_261543898/mobile/index-muted-HM49I092CC.m3u8
-#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="audio_only",NAME="Audio Only",AUTOSELECT=NO,DEFAULT=NO
-#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=182725,CODECS="mp4a.40.2",VIDEO="audio_only"
-https://vod.edgecast.hls.ttvnw.net/e5da31ab49_riotgames_15001215120_261543898/audio_only/index-muted-HM49I092CC.m3u8
diff --git a/test/testdata/m3u8/vidio.m3u8 b/test/testdata/m3u8/vidio.m3u8
deleted file mode 100644
index 89c244469..000000000
--- a/test/testdata/m3u8/vidio.m3u8
+++ /dev/null
@@ -1,10 +0,0 @@
-#EXTM3U
-
-#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=300000,RESOLUTION=480x270,NAME="270p 3G"
-https://cdn1-a.production.vidio.static6.com/uploads/165683/dj_ambred-4383-b300.mp4.m3u8
-
-#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=600000,RESOLUTION=640x360,NAME="360p SD"
-https://cdn1-a.production.vidio.static6.com/uploads/165683/dj_ambred-4383-b600.mp4.m3u8
-
-#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1200000,RESOLUTION=1280x720,NAME="720p HD"
-https://cdn1-a.production.vidio.static6.com/uploads/165683/dj_ambred-4383-b1200.mp4.m3u8
diff --git a/test/testdata/mpd/float_duration.mpd b/test/testdata/mpd/float_duration.mpd
deleted file mode 100644
index 8dc1d2d5e..000000000
--- a/test/testdata/mpd/float_duration.mpd
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/test/testdata/mpd/range_only.mpd b/test/testdata/mpd/range_only.mpd
deleted file mode 100644
index e0c2152d1..000000000
--- a/test/testdata/mpd/range_only.mpd
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
- manifest.mpd generated by GPAC
-
-
-
-
-
- video_dashinit.mp4
-
-
-
-
-
-
-
-
-
-
-
-
- audio_dashinit.mp4
-
-
-
-
-
-
-
-
-
-
-
diff --git a/test/testdata/mpd/subtitles.mpd b/test/testdata/mpd/subtitles.mpd
deleted file mode 100644
index 6f948adba..000000000
--- a/test/testdata/mpd/subtitles.mpd
+++ /dev/null
@@ -1,351 +0,0 @@
-
-
-
-
- dash/
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/test/testdata/mpd/unfragmented.mpd b/test/testdata/mpd/unfragmented.mpd
deleted file mode 100644
index 5a3720be7..000000000
--- a/test/testdata/mpd/unfragmented.mpd
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
-
- DASH_360
-
-
-
-
-
- DASH_240
-
-
-
-
-
-
-
-
- audio
-
-
-
-
-
-
-
diff --git a/test/testdata/mpd/url_and_range.mpd b/test/testdata/mpd/url_and_range.mpd
deleted file mode 100644
index b8c68aad2..000000000
--- a/test/testdata/mpd/url_and_range.mpd
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/test/testdata/mpd/urls_only.mpd b/test/testdata/mpd/urls_only.mpd
deleted file mode 100644
index 2b9d595d3..000000000
--- a/test/testdata/mpd/urls_only.mpd
+++ /dev/null
@@ -1,218 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/test/testdata/xspf/foo_xspf.xspf b/test/testdata/xspf/foo_xspf.xspf
deleted file mode 100644
index b7f0086b3..000000000
--- a/test/testdata/xspf/foo_xspf.xspf
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
- 2018-03-09T18:01:43Z
-
-
-
-
-
-
diff --git a/test/versions.json b/test/versions.json
deleted file mode 100644
index 6cccc2259..000000000
--- a/test/versions.json
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- "latest": "2013.01.06",
- "signature": "72158cdba391628569ffdbea259afbcf279bbe3d8aeb7492690735dc1cfa6afa754f55c61196f3871d429599ab22f2667f1fec98865527b32632e7f4b3675a7ef0f0fbe084d359256ae4bba68f0d33854e531a70754712f244be71d4b92e664302aa99653ee4df19800d955b6c4149cd2b3f24288d6e4b40b16126e01f4c8ce6",
- "versions": {
- "2013.01.02": {
- "bin": [
- "http://youtube-dl.org/downloads/2013.01.02/youtube-dl",
- "f5b502f8aaa77675c4884938b1e4871ebca2611813a0c0e74f60c0fbd6dcca6b"
- ],
- "exe": [
- "http://youtube-dl.org/downloads/2013.01.02/youtube-dl.exe",
- "75fa89d2ce297d102ff27675aa9d92545bbc91013f52ec52868c069f4f9f0422"
- ],
- "tar": [
- "http://youtube-dl.org/downloads/2013.01.02/youtube-dl-2013.01.02.tar.gz",
- "6a66d022ac8e1c13da284036288a133ec8dba003b7bd3a5179d0c0daca8c8196"
- ]
- },
- "2013.01.06": {
- "bin": [
- "http://youtube-dl.org/downloads/2013.01.06/youtube-dl",
- "64b6ed8865735c6302e836d4d832577321b4519aa02640dc508580c1ee824049"
- ],
- "exe": [
- "http://youtube-dl.org/downloads/2013.01.06/youtube-dl.exe",
- "58609baf91e4389d36e3ba586e21dab882daaaee537e4448b1265392ae86ff84"
- ],
- "tar": [
- "http://youtube-dl.org/downloads/2013.01.06/youtube-dl-2013.01.06.tar.gz",
- "fe77ab20a95d980ed17a659aa67e371fdd4d656d19c4c7950e7b720b0c2f1a86"
- ]
- }
- }
-}
\ No newline at end of file