Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
mikf
GitHub Repository: mikf/gallery-dl
Path: blob/master/test/test_ytdl.py
5457 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._(["--cn-verification-proxy", "https://127.0.0.1"],
46
"cn_verification_proxy", "https://127.0.0.1")
47
self._(["--geo-verification-proxy", "127.0.0.1"],
48
"geo_verification_proxy", "127.0.0.1")
49
50
def test_network_options(self):
51
self._(["--socket-timeout", "3.5"],
52
"socket_timeout", 3.5)
53
self._(["--source-address", "127.0.0.1"],
54
"source_address", "127.0.0.1")
55
self._("-4" , "source_address", "0.0.0.0")
56
self._("--force-ipv4", "source_address", "0.0.0.0")
57
self._("-6" , "source_address", "::")
58
self._("--force-ipv6", "source_address", "::")
59
60
def test_thumbnail_options(self):
61
self._("--write-thumbnail", "writethumbnail", True)
62
self._("--write-all-thumbnails", "write_all_thumbnails", True)
63
64
def test_authentication_options(self):
65
self._(["-u" , "foo"], "username", "foo")
66
self._(["--username", "foo"], "username", "foo")
67
68
self._(["-p" , "bar"], "password", "bar")
69
self._(["--password", "bar"], "password", "bar")
70
71
self._(["--ap-mso" , "mso"], "ap_mso", "mso")
72
self._(["--ap-username", "foo"], "ap_username", "foo")
73
self._(["--ap-password", "bar"], "ap_password", "bar")
74
75
self._(["-2" , "pass"], "twofactor", "pass")
76
self._(["--twofactor", "pass"], "twofactor", "pass")
77
78
self._(["--video-password", "pass"], "videopassword", "pass")
79
80
self._("-n" , "usenetrc", True)
81
self._("--netrc", "usenetrc", True)
82
83
def test_subtitle_options(self):
84
self._("--write-sub" , "writesubtitles" , True)
85
self._("--write-auto-sub", "writeautomaticsub", True)
86
87
self._(["--sub-format", "best"], "subtitlesformat", "best")
88
self._(["--sub-langs", "en,ru"], "subtitleslangs", ["en", "ru"])
89
90
def test_retries(self):
91
inf = float("inf")
92
93
self._(["--retries", "5"], "retries", 5)
94
self._(["--retries", "inf"], "retries", inf)
95
self._(["--retries", "infinite"], "retries", inf)
96
self._(["--fragment-retries", "8"], "fragment_retries", 8)
97
self._(["--fragment-retries", "inf"], "fragment_retries", inf)
98
self._(["--fragment-retries", "infinite"], "fragment_retries", inf)
99
100
def test_geo_bypass(self):
101
self._("--geo-bypass", "geo_bypass", True)
102
self._("--no-geo-bypass", "geo_bypass", False)
103
self._(["--geo-bypass-country", "EN"], "geo_bypass_country", "EN")
104
self._(["--geo-bypass-ip-block", "198.51.100.14/24"],
105
"geo_bypass_ip_block", "198.51.100.14/24")
106
107
def test_headers(self):
108
headers = self.module.std_headers
109
110
self.assertNotEqual(headers["User-Agent"], "Foo/1.0")
111
self._(["--user-agent", "Foo/1.0"])
112
self.assertEqual(headers["User-Agent"], "Foo/1.0")
113
114
self.assertNotIn("Referer", headers)
115
self._(["--referer", "http://example.org/"])
116
self.assertEqual(headers["Referer"], "http://example.org/")
117
118
self.assertNotEqual(headers["Accept"], "*/*")
119
self.assertNotIn("DNT", headers)
120
self._([
121
"--add-header", "accept:*/*",
122
"--add-header", "dnt:1",
123
])
124
self.assertEqual(headers["accept"], "*/*")
125
self.assertEqual(headers["dnt"], "1")
126
127
def test_extract_audio(self):
128
opts = self._(["--extract-audio"])
129
self.assertEqual(opts["postprocessors"][0], {
130
"key": "FFmpegExtractAudio",
131
"preferredcodec": "best",
132
"preferredquality": "5",
133
"nopostoverwrites": False,
134
})
135
136
opts = self._([
137
"--extract-audio",
138
"--audio-format", "opus",
139
"--audio-quality", "9",
140
"--no-post-overwrites",
141
])
142
self.assertEqual(opts["postprocessors"][0], {
143
"key": "FFmpegExtractAudio",
144
"preferredcodec": "opus",
145
"preferredquality": "9",
146
"nopostoverwrites": True,
147
})
148
149
def test_recode_video(self):
150
opts = self._(["--recode-video", " mkv "])
151
self.assertEqual(opts["postprocessors"][0], {
152
"key": "FFmpegVideoConvertor",
153
"preferedformat": "mkv",
154
})
155
156
def test_subs(self):
157
opts = self._(["--convert-subs", "srt"])
158
conv = {"key": "FFmpegSubtitlesConvertor", "format": "srt"}
159
if self.ytdlp:
160
conv["when"] = "before_dl"
161
self.assertEqual(opts["postprocessors"][0], conv)
162
163
def test_embed(self):
164
subs = {"key": "FFmpegEmbedSubtitle"}
165
thumb = {"key": "EmbedThumbnail", "already_have_thumbnail": False}
166
if self.ytdlp:
167
subs["already_have_subtitle"] = False
168
169
opts = self._(["--embed-subs", "--embed-thumbnail"])
170
self.assertEqual(opts["postprocessors"][:2], [subs, thumb])
171
172
thumb["already_have_thumbnail"] = True
173
if self.ytdlp:
174
subs["already_have_subtitle"] = True
175
thumb["already_have_thumbnail"] = "all"
176
177
opts = self._([
178
"--embed-thumbnail",
179
"--embed-subs",
180
"--write-sub",
181
"--write-all-thumbnails",
182
])
183
self.assertEqual(opts["postprocessors"][:2], [subs, thumb])
184
185
def test_metadata(self):
186
opts = self._("--add-metadata")
187
self.assertEqual(opts["postprocessors"][0], {"key": "FFmpegMetadata"})
188
189
def test_metadata_from_title(self):
190
opts = self._(["--metadata-from-title", "%(artist)s - %(title)s"])
191
self.assertEqual(opts["postprocessors"][0], {
192
"key": "MetadataFromTitle",
193
"titleformat": "%(artist)s - %(title)s",
194
})
195
196
def test_xattr(self):
197
self._("--xattr-set-filesize", "xattr_set_filesize", True)
198
199
opts = self._("--xattrs")
200
self.assertEqual(opts["postprocessors"][0], {"key": "XAttrMetadata"})
201
202
def test_noop(self):
203
cmdline = [
204
"--update",
205
"--dump-user-agent",
206
"-F",
207
"--list-formats",
208
"--list-extractors",
209
"--list-thumbnails",
210
"--list-subs",
211
"--ap-list-mso",
212
"--extractor-descriptions",
213
"--ignore-config",
214
]
215
216
if not self.ytdlp:
217
cmdline.extend((
218
"--dump-json",
219
"--dump-single-json",
220
"--config-location", "~",
221
))
222
223
result = self._(cmdline)
224
result["daterange"] = self.default["daterange"]
225
self.assertEqual(result, self.default)
226
227
def _(self, cmdline, option=util.SENTINEL, expected=None):
228
if isinstance(cmdline, str):
229
cmdline = [cmdline]
230
result = ytdl.parse_command_line(self.module, cmdline)
231
if option is not util.SENTINEL:
232
self.assertEqual(result[option], expected, option)
233
return result
234
235
236
class Test_CommandlineArguments_YtDlp(Test_CommandlineArguments):
237
module_name = "yt_dlp"
238
239
def test_retries_extractor(self):
240
inf = float("inf")
241
242
self._(["--extractor-retries", "5"], "extractor_retries", 5)
243
self._(["--extractor-retries", "inf"], "extractor_retries", inf)
244
self._(["--extractor-retries", "infinite"], "extractor_retries", inf)
245
246
def test_remuxs_video(self):
247
opts = self._(["--remux-video", " mkv "])
248
self.assertEqual(opts["postprocessors"][0], {
249
"key": "FFmpegVideoRemuxer",
250
"preferedformat": "mkv",
251
})
252
253
def test_metadata(self):
254
opts = self._(["--embed-metadata",
255
"--no-embed-chapters",
256
"--embed-info-json"])
257
self.assertEqual(opts["postprocessors"][0], {
258
"key": "FFmpegMetadata",
259
"add_chapters": False,
260
"add_metadata": True,
261
"add_infojson": True,
262
})
263
264
def test_metadata_from_title(self):
265
opts = self._(["--metadata-from-title", "%(artist)s - %(title)s"])
266
self.assertEqual(opts["postprocessors"][0], {
267
"key" : "MetadataParser",
268
"when" : "pre_process",
269
"actions": [self.module.MetadataFromFieldPP.to_action(
270
"title:%(artist)s - %(title)s")],
271
})
272
273
def test_geo_bypass(self):
274
try:
275
ytdl.parse_command_line(self.module, ["--xff", "default"])
276
except Exception:
277
# before --xff (c16644642)
278
return Test_CommandlineArguments.test_geo_bypass(self)
279
280
self._(["--xff", "default"],
281
"geo_bypass", "default")
282
self._(["--xff", "never"],
283
"geo_bypass", "never")
284
self._(["--xff", "EN"],
285
"geo_bypass", "EN")
286
self._(["--xff", "198.51.100.14/24"],
287
"geo_bypass", "198.51.100.14/24")
288
289
self._("--geo-bypass",
290
"geo_bypass", "default")
291
self._("--no-geo-bypass",
292
"geo_bypass", "never")
293
self._(["--geo-bypass-country", "EN"],
294
"geo_bypass", "EN")
295
self._(["--geo-bypass-ip-block", "198.51.100.14/24"],
296
"geo_bypass", "198.51.100.14/24")
297
298
def test_cookiesfrombrowser(self):
299
self._(["--cookies-from-browser", "firefox"],
300
"cookiesfrombrowser", ("firefox", None, None, None))
301
self._(["--cookies-from-browser", "firefox:profile"],
302
"cookiesfrombrowser", ("firefox", "profile", None, None))
303
self._(["--cookies-from-browser", "firefox+keyring"],
304
"cookiesfrombrowser", ("firefox", None, "KEYRING", None))
305
self._(["--cookies-from-browser", "firefox::container"],
306
"cookiesfrombrowser", ("firefox", None, None, "container"))
307
self._(["--cookies-from-browser",
308
"firefox+keyring:profile::container"],
309
"cookiesfrombrowser",
310
("firefox", "profile", "KEYRING", "container"))
311
312
313
if __name__ == "__main__":
314
unittest.main(warnings="ignore")
315
316