Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
mikf
GitHub Repository: mikf/gallery-dl
Path: blob/master/test/test_ytdl.py
8881 views
1
#!/usr/bin/env python3
2
# -*- coding: utf-8 -*-
3
4
# Copyright 2022-2025 Mike Fährmann
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License version 2 as
8
# published by the Free Software Foundation.
9
10
import os
11
import sys
12
import unittest
13
14
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
15
from gallery_dl import ytdl, util, config # noqa E402
16
17
18
class Test_CommandlineArguments(unittest.TestCase):
19
module_name = "youtube_dl"
20
21
@classmethod
22
def setUpClass(cls):
23
try:
24
cls.module = __import__(cls.module_name)
25
except (ImportError, SyntaxError):
26
raise unittest.SkipTest(
27
f"cannot import module '{cls.module_name}'")
28
cls.default = ytdl.parse_command_line(cls.module, [])
29
cls.ytdlp = hasattr(cls.module, "cookies")
30
31
def test_ignore_errors(self):
32
self._("--ignore-errors" , "ignoreerrors", True)
33
self._("--abort-on-error", "ignoreerrors", False)
34
35
def test_default_search(self):
36
self._(["--default-search", "foo"] , "default_search", "foo")
37
38
def test_mark_watched(self):
39
self._("--mark-watched" , "mark_watched", True)
40
self._("--no-mark-watched", "mark_watched", False)
41
42
def test_proxy(self):
43
self._(["--proxy", "socks5://127.0.0.1:1080/"],
44
"proxy", "socks5://127.0.0.1:1080/")
45
self._(["--geo-verification-proxy", "127.0.0.1"],
46
"geo_verification_proxy", "127.0.0.1")
47
48
def test_network_options(self):
49
self._(["--socket-timeout", "3.5"],
50
"socket_timeout", 3.5)
51
self._(["--source-address", "127.0.0.1"],
52
"source_address", "127.0.0.1")
53
self._("-4" , "source_address", "0.0.0.0")
54
self._("--force-ipv4", "source_address", "0.0.0.0")
55
self._("-6" , "source_address", "::")
56
self._("--force-ipv6", "source_address", "::")
57
58
def test_thumbnail_options(self):
59
self._("--write-thumbnail", "writethumbnail", True)
60
self._("--write-all-thumbnails", "write_all_thumbnails", True)
61
62
def test_authentication_options(self):
63
self._(["-u" , "foo"], "username", "foo")
64
self._(["--username", "foo"], "username", "foo")
65
66
self._(["-p" , "bar"], "password", "bar")
67
self._(["--password", "bar"], "password", "bar")
68
69
self._(["--ap-mso" , "mso"], "ap_mso", "mso")
70
self._(["--ap-username", "foo"], "ap_username", "foo")
71
self._(["--ap-password", "bar"], "ap_password", "bar")
72
73
self._(["-2" , "pass"], "twofactor", "pass")
74
self._(["--twofactor", "pass"], "twofactor", "pass")
75
76
self._(["--video-password", "pass"], "videopassword", "pass")
77
78
self._("-n" , "usenetrc", True)
79
self._("--netrc", "usenetrc", True)
80
81
def test_subtitle_options(self):
82
self._("--write-sub" , "writesubtitles" , True)
83
self._("--write-auto-sub", "writeautomaticsub", True)
84
85
self._(["--sub-format", "best"], "subtitlesformat", "best")
86
self._(["--sub-langs", "en,ru"], "subtitleslangs", ["en", "ru"])
87
88
def test_retries(self):
89
inf = float("inf")
90
91
self._(["--retries", "5"], "retries", 5)
92
self._(["--retries", "inf"], "retries", inf)
93
self._(["--retries", "infinite"], "retries", inf)
94
self._(["--fragment-retries", "8"], "fragment_retries", 8)
95
self._(["--fragment-retries", "inf"], "fragment_retries", inf)
96
self._(["--fragment-retries", "infinite"], "fragment_retries", inf)
97
98
def test_geo_bypass(self):
99
self._("--geo-bypass", "geo_bypass", True)
100
self._("--no-geo-bypass", "geo_bypass", False)
101
self._(["--geo-bypass-country", "EN"], "geo_bypass_country", "EN")
102
self._(["--geo-bypass-ip-block", "198.51.100.14/24"],
103
"geo_bypass_ip_block", "198.51.100.14/24")
104
105
def test_headers(self):
106
try:
107
headers = self.module.utils.networking.std_headers
108
except AttributeError:
109
headers = self.module.std_headers
110
111
self.assertNotEqual(headers["User-Agent"], "Foo/1.0")
112
self._(["--user-agent", "Foo/1.0"])
113
self.assertEqual(headers["User-Agent"], "Foo/1.0")
114
115
self.assertNotIn("Referer", headers)
116
self._(["--referer", "http://example.org/"])
117
self.assertEqual(headers["Referer"], "http://example.org/")
118
119
self.assertNotEqual(headers["Accept"], "*/*")
120
self.assertNotIn("DNT", headers)
121
self._([
122
"--add-header", "accept:*/*",
123
"--add-header", "dnt:1",
124
])
125
self.assertEqual(headers["accept"], "*/*")
126
self.assertEqual(headers["dnt"], "1")
127
128
def test_extract_audio(self):
129
opts = self._(["--extract-audio"])
130
self.assertEqual(opts["postprocessors"][0], {
131
"key": "FFmpegExtractAudio",
132
"preferredcodec": "best",
133
"preferredquality": "5",
134
"nopostoverwrites": False,
135
})
136
137
opts = self._([
138
"--extract-audio",
139
"--audio-format", "opus",
140
"--audio-quality", "9",
141
"--no-post-overwrites",
142
])
143
self.assertEqual(opts["postprocessors"][0], {
144
"key": "FFmpegExtractAudio",
145
"preferredcodec": "opus",
146
"preferredquality": "9",
147
"nopostoverwrites": True,
148
})
149
150
def test_recode_video(self):
151
opts = self._(["--recode-video", " mkv "])
152
self.assertEqual(opts["postprocessors"][0], {
153
"key": "FFmpegVideoConvertor",
154
"preferedformat": "mkv",
155
})
156
157
def test_subs(self):
158
opts = self._(["--convert-subs", "srt"])
159
conv = {"key": "FFmpegSubtitlesConvertor", "format": "srt"}
160
if self.ytdlp:
161
conv["when"] = "before_dl"
162
self.assertEqual(opts["postprocessors"][0], conv)
163
164
def test_embed(self):
165
subs = {"key": "FFmpegEmbedSubtitle"}
166
thumb = {"key": "EmbedThumbnail", "already_have_thumbnail": False}
167
if self.ytdlp:
168
subs["already_have_subtitle"] = False
169
170
opts = self._(["--embed-subs", "--embed-thumbnail"])
171
self.assertEqual(opts["postprocessors"][:2], [subs, thumb])
172
173
thumb["already_have_thumbnail"] = True
174
if self.ytdlp:
175
subs["already_have_subtitle"] = True
176
thumb["already_have_thumbnail"] = "all"
177
178
opts = self._([
179
"--embed-thumbnail",
180
"--embed-subs",
181
"--write-sub",
182
"--write-all-thumbnails",
183
])
184
self.assertEqual(opts["postprocessors"][:2], [subs, thumb])
185
186
def test_metadata(self):
187
opts = self._("--add-metadata")
188
self.assertEqual(opts["postprocessors"][0], {"key": "FFmpegMetadata"})
189
190
def test_metadata_from_title(self):
191
opts = self._(["--metadata-from-title", "%(artist)s - %(title)s"])
192
self.assertEqual(opts["postprocessors"][0], {
193
"key": "MetadataFromTitle",
194
"titleformat": "%(artist)s - %(title)s",
195
})
196
197
def test_xattr(self):
198
opts = self._("--xattrs")
199
self.assertEqual(opts["postprocessors"][0], {"key": "XAttrMetadata"})
200
201
def test_noop(self):
202
cmdline = [
203
"--update",
204
"--dump-user-agent",
205
"-F",
206
"--list-formats",
207
"--list-extractors",
208
"--list-thumbnails",
209
"--list-subs",
210
"--ap-list-mso",
211
"--extractor-descriptions",
212
"--ignore-config",
213
]
214
215
if not self.ytdlp:
216
cmdline.extend((
217
"--dump-json",
218
"--dump-single-json",
219
"--config-location", "~",
220
))
221
222
result = self._(cmdline)
223
result["daterange"] = self.default["daterange"]
224
self.assertEqual(result, self.default)
225
226
def _(self, cmdline, option=util.SENTINEL, expected=None):
227
if isinstance(cmdline, str):
228
cmdline = [cmdline]
229
result = ytdl.parse_command_line(self.module, cmdline)
230
if option is not util.SENTINEL:
231
self.assertEqual(result[option], expected, option)
232
return result
233
234
235
class Test_CommandlineArguments_YtDlp(Test_CommandlineArguments):
236
module_name = "yt_dlp"
237
238
def test_retries_extractor(self):
239
inf = float("inf")
240
241
self._(["--extractor-retries", "5"], "extractor_retries", 5)
242
self._(["--extractor-retries", "inf"], "extractor_retries", inf)
243
self._(["--extractor-retries", "infinite"], "extractor_retries", inf)
244
245
def test_remuxs_video(self):
246
opts = self._(["--remux-video", " mkv "])
247
self.assertEqual(opts["postprocessors"][0], {
248
"key": "FFmpegVideoRemuxer",
249
"preferedformat": "mkv",
250
})
251
252
def test_metadata(self):
253
opts = self._(["--embed-metadata",
254
"--no-embed-chapters",
255
"--embed-info-json"])
256
self.assertEqual(opts["postprocessors"][0], {
257
"key": "FFmpegMetadata",
258
"add_chapters": False,
259
"add_metadata": True,
260
"add_infojson": True,
261
})
262
263
def test_metadata_from_title(self):
264
opts = self._(["--metadata-from-title", "%(artist)s - %(title)s"])
265
self.assertEqual(opts["postprocessors"][0], {
266
"key" : "MetadataParser",
267
"when" : "pre_process",
268
"actions": [self.module.MetadataFromFieldPP.to_action(
269
"title:%(artist)s - %(title)s")],
270
})
271
272
def test_geo_bypass(self):
273
try:
274
ytdl.parse_command_line(self.module, ["--xff", "default"])
275
except Exception:
276
# before --xff (c16644642)
277
return Test_CommandlineArguments.test_geo_bypass(self)
278
279
self._(["--xff", "default"],
280
"geo_bypass", "default")
281
self._(["--xff", "never"],
282
"geo_bypass", "never")
283
self._(["--xff", "EN"],
284
"geo_bypass", "EN")
285
self._(["--xff", "198.51.100.14/24"],
286
"geo_bypass", "198.51.100.14/24")
287
288
self._("--geo-bypass",
289
"geo_bypass", "default")
290
self._("--no-geo-bypass",
291
"geo_bypass", "never")
292
self._(["--geo-bypass-country", "EN"],
293
"geo_bypass", "EN")
294
self._(["--geo-bypass-ip-block", "198.51.100.14/24"],
295
"geo_bypass", "198.51.100.14/24")
296
297
def test_cookiesfrombrowser(self):
298
self._(["--cookies-from-browser", "firefox"],
299
"cookiesfrombrowser", ("firefox", None, None, None))
300
self._(["--cookies-from-browser", "firefox:profile"],
301
"cookiesfrombrowser", ("firefox", "profile", None, None))
302
self._(["--cookies-from-browser", "firefox+keyring"],
303
"cookiesfrombrowser", ("firefox", None, "KEYRING", None))
304
self._(["--cookies-from-browser", "firefox::container"],
305
"cookiesfrombrowser", ("firefox", None, None, "container"))
306
self._(["--cookies-from-browser",
307
"firefox+keyring:profile::container"],
308
"cookiesfrombrowser",
309
("firefox", "profile", "KEYRING", "container"))
310
311
312
if __name__ == "__main__":
313
unittest.main(warnings="ignore")
314
315