]>
Commit | Line | Data |
---|---|---|
cc52de43 | 1 | #!/usr/bin/env python3 |
54007a45 | 2 | |
88cf6fb3 JMF |
3 | # Allow direct execution |
4 | import os | |
5 | import sys | |
6 | import unittest | |
7a340e0d | 7 | |
88cf6fb3 JMF |
8 | sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) |
9 | ||
54007a45 | 10 | |
752cda38 | 11 | from yt_dlp import YoutubeDL |
add96eb9 | 12 | from yt_dlp.utils import shell_quote |
337e0c62 | 13 | from yt_dlp.postprocessor import ( |
ad3dc496 | 14 | ExecPP, |
337e0c62 | 15 | FFmpegThumbnailsConvertorPP, |
16 | MetadataFromFieldPP, | |
e9f4ccd1 | 17 | MetadataParserPP, |
f8271158 | 18 | ModifyChaptersPP, |
63c547d7 | 19 | SponsorBlockPP, |
337e0c62 | 20 | ) |
5bfa4862 | 21 | |
22 | ||
23 | class TestMetadataFromField(unittest.TestCase): | |
88cf6fb3 | 24 | |
88cf6fb3 | 25 | def test_format_to_regex(self): |
e9f4ccd1 | 26 | self.assertEqual( |
27 | MetadataParserPP.format_to_regex('%(title)s - %(artist)s'), | |
28 | r'(?P<title>.+)\ \-\ (?P<artist>.+)') | |
29 | self.assertEqual(MetadataParserPP.format_to_regex(r'(?P<x>.+)'), r'(?P<x>.+)') | |
30 | ||
31 | def test_field_to_template(self): | |
32 | self.assertEqual(MetadataParserPP.field_to_template('title'), '%(title)s') | |
33 | self.assertEqual(MetadataParserPP.field_to_template('1'), '1') | |
34 | self.assertEqual(MetadataParserPP.field_to_template('foo bar'), 'foo bar') | |
35 | self.assertEqual(MetadataParserPP.field_to_template(' literal'), ' literal') | |
36 | ||
37 | def test_metadatafromfield(self): | |
38 | self.assertEqual( | |
39 | MetadataFromFieldPP.to_action('%(title)s \\: %(artist)s:%(title)s : %(artist)s'), | |
40 | (MetadataParserPP.Actions.INTERPRET, '%(title)s : %(artist)s', '%(title)s : %(artist)s')) | |
337e0c62 | 41 | |
42 | ||
43 | class TestConvertThumbnail(unittest.TestCase): | |
44 | def test_escaping(self): | |
45 | pp = FFmpegThumbnailsConvertorPP() | |
46 | if not pp.available: | |
47 | print('Skipping: ffmpeg not found') | |
48 | return | |
49 | ||
50 | file = 'test/testdata/thumbnails/foo %d bar/foo_%d.{}' | |
51 | tests = (('webp', 'png'), ('png', 'jpg')) | |
52 | ||
53 | for inp, out in tests: | |
54 | out_file = file.format(out) | |
55 | if os.path.exists(out_file): | |
56 | os.remove(out_file) | |
57 | pp.convert_thumbnail(file.format(inp), out) | |
58 | assert os.path.exists(out_file) | |
59 | ||
60 | for _, out in tests: | |
61 | os.remove(file.format(out)) | |
752cda38 | 62 | |
63 | ||
ad3dc496 | 64 | class TestExec(unittest.TestCase): |
752cda38 | 65 | def test_parse_cmd(self): |
ad3dc496 | 66 | pp = ExecPP(YoutubeDL(), '') |
752cda38 | 67 | info = {'filepath': 'file name'} |
add96eb9 | 68 | cmd = 'echo {}'.format(shell_quote(info['filepath'])) |
752cda38 | 69 | |
ad3dc496 | 70 | self.assertEqual(pp.parse_cmd('echo', info), cmd) |
71 | self.assertEqual(pp.parse_cmd('echo {}', info), cmd) | |
72 | self.assertEqual(pp.parse_cmd('echo %(filepath)q', info), cmd) | |
7a340e0d NA |
73 | |
74 | ||
75 | class TestModifyChaptersPP(unittest.TestCase): | |
76 | def setUp(self): | |
77 | self._pp = ModifyChaptersPP(YoutubeDL()) | |
78 | ||
79 | @staticmethod | |
63c547d7 AR |
80 | def _sponsor_chapter(start, end, cat, remove=False, title=None): |
81 | if title is None: | |
82 | title = SponsorBlockPP.CATEGORIES[cat] | |
83 | return { | |
84 | 'start_time': start, | |
85 | 'end_time': end, | |
86 | '_categories': [(cat, start, end, title)], | |
87 | **({'remove': True} if remove else {}), | |
88 | } | |
7a340e0d NA |
89 | |
90 | @staticmethod | |
91 | def _chapter(start, end, title=None, remove=False): | |
92 | c = {'start_time': start, 'end_time': end} | |
93 | if title is not None: | |
94 | c['title'] = title | |
95 | if remove: | |
96 | c['remove'] = True | |
97 | return c | |
98 | ||
99 | def _chapters(self, ends, titles): | |
100 | self.assertEqual(len(ends), len(titles)) | |
101 | start = 0 | |
102 | chapters = [] | |
103 | for e, t in zip(ends, titles): | |
104 | chapters.append(self._chapter(start, e, t)) | |
105 | start = e | |
106 | return chapters | |
107 | ||
108 | def _remove_marked_arrange_sponsors_test_impl( | |
109 | self, chapters, expected_chapters, expected_removed): | |
110 | actual_chapters, actual_removed = ( | |
111 | self._pp._remove_marked_arrange_sponsors(chapters)) | |
112 | for c in actual_removed: | |
113 | c.pop('title', None) | |
114 | c.pop('_categories', None) | |
115 | actual_chapters = [{ | |
116 | 'start_time': c['start_time'], | |
117 | 'end_time': c['end_time'], | |
118 | 'title': c['title'], | |
119 | } for c in actual_chapters] | |
120 | self.assertSequenceEqual(expected_chapters, actual_chapters) | |
121 | self.assertSequenceEqual(expected_removed, actual_removed) | |
122 | ||
123 | def test_remove_marked_arrange_sponsors_CanGetThroughUnaltered(self): | |
124 | chapters = self._chapters([10, 20, 30, 40], ['c1', 'c2', 'c3', 'c4']) | |
125 | self._remove_marked_arrange_sponsors_test_impl(chapters, chapters, []) | |
126 | ||
127 | def test_remove_marked_arrange_sponsors_ChapterWithSponsors(self): | |
add96eb9 | 128 | chapters = [ |
129 | *self._chapters([70], ['c']), | |
7a340e0d NA |
130 | self._sponsor_chapter(10, 20, 'sponsor'), |
131 | self._sponsor_chapter(30, 40, 'preview'), | |
8157a09d | 132 | self._sponsor_chapter(50, 60, 'filler')] |
7a340e0d NA |
133 | expected = self._chapters( |
134 | [10, 20, 30, 40, 50, 60, 70], | |
135 | ['c', '[SponsorBlock]: Sponsor', 'c', '[SponsorBlock]: Preview/Recap', | |
8157a09d | 136 | 'c', '[SponsorBlock]: Filler Tangent', 'c']) |
7a340e0d NA |
137 | self._remove_marked_arrange_sponsors_test_impl(chapters, expected, []) |
138 | ||
63c547d7 | 139 | def test_remove_marked_arrange_sponsors_SponsorBlockChapters(self): |
add96eb9 | 140 | chapters = [ |
141 | *self._chapters([70], ['c']), | |
63c547d7 AR |
142 | self._sponsor_chapter(10, 20, 'chapter', title='sb c1'), |
143 | self._sponsor_chapter(15, 16, 'chapter', title='sb c2'), | |
144 | self._sponsor_chapter(30, 40, 'preview'), | |
145 | self._sponsor_chapter(50, 60, 'filler')] | |
146 | expected = self._chapters( | |
147 | [10, 15, 16, 20, 30, 40, 50, 60, 70], | |
148 | ['c', '[SponsorBlock]: sb c1', '[SponsorBlock]: sb c1, sb c2', '[SponsorBlock]: sb c1', | |
149 | 'c', '[SponsorBlock]: Preview/Recap', | |
150 | 'c', '[SponsorBlock]: Filler Tangent', 'c']) | |
151 | self._remove_marked_arrange_sponsors_test_impl(chapters, expected, []) | |
152 | ||
7a340e0d | 153 | def test_remove_marked_arrange_sponsors_UniqueNamesForOverlappingSponsors(self): |
add96eb9 | 154 | chapters = [ |
155 | *self._chapters([120], ['c']), | |
156 | self._sponsor_chapter(10, 45, 'sponsor'), | |
157 | self._sponsor_chapter(20, 40, 'selfpromo'), | |
158 | self._sponsor_chapter(50, 70, 'sponsor'), | |
159 | self._sponsor_chapter(60, 85, 'selfpromo'), | |
160 | self._sponsor_chapter(90, 120, 'selfpromo'), | |
161 | self._sponsor_chapter(100, 110, 'sponsor')] | |
7a340e0d NA |
162 | expected = self._chapters( |
163 | [10, 20, 40, 45, 50, 60, 70, 85, 90, 100, 110, 120], | |
164 | ['c', '[SponsorBlock]: Sponsor', '[SponsorBlock]: Sponsor, Unpaid/Self Promotion', | |
165 | '[SponsorBlock]: Sponsor', | |
166 | 'c', '[SponsorBlock]: Sponsor', '[SponsorBlock]: Sponsor, Unpaid/Self Promotion', | |
167 | '[SponsorBlock]: Unpaid/Self Promotion', | |
168 | 'c', '[SponsorBlock]: Unpaid/Self Promotion', '[SponsorBlock]: Unpaid/Self Promotion, Sponsor', | |
169 | '[SponsorBlock]: Unpaid/Self Promotion']) | |
170 | self._remove_marked_arrange_sponsors_test_impl(chapters, expected, []) | |
171 | ||
172 | def test_remove_marked_arrange_sponsors_ChapterWithCuts(self): | |
173 | cuts = [self._chapter(10, 20, remove=True), | |
174 | self._sponsor_chapter(30, 40, 'sponsor', remove=True), | |
175 | self._chapter(50, 60, remove=True)] | |
176 | chapters = self._chapters([70], ['c']) + cuts | |
177 | self._remove_marked_arrange_sponsors_test_impl( | |
178 | chapters, self._chapters([40], ['c']), cuts) | |
179 | ||
180 | def test_remove_marked_arrange_sponsors_ChapterWithSponsorsAndCuts(self): | |
add96eb9 | 181 | chapters = [ |
182 | *self._chapters([70], ['c']), | |
7a340e0d NA |
183 | self._sponsor_chapter(10, 20, 'sponsor'), |
184 | self._sponsor_chapter(30, 40, 'selfpromo', remove=True), | |
185 | self._sponsor_chapter(50, 60, 'interaction')] | |
186 | expected = self._chapters([10, 20, 40, 50, 60], | |
187 | ['c', '[SponsorBlock]: Sponsor', 'c', | |
188 | '[SponsorBlock]: Interaction Reminder', 'c']) | |
189 | self._remove_marked_arrange_sponsors_test_impl( | |
190 | chapters, expected, [self._chapter(30, 40, remove=True)]) | |
191 | ||
192 | def test_remove_marked_arrange_sponsors_ChapterWithSponsorCutInTheMiddle(self): | |
193 | cuts = [self._sponsor_chapter(20, 30, 'selfpromo', remove=True), | |
194 | self._chapter(40, 50, remove=True)] | |
add96eb9 | 195 | chapters = [ |
196 | *self._chapters([70], ['c']), | |
197 | self._sponsor_chapter(10, 60, 'sponsor'), | |
198 | *cuts] | |
7a340e0d NA |
199 | expected = self._chapters( |
200 | [10, 40, 50], ['c', '[SponsorBlock]: Sponsor', 'c']) | |
201 | self._remove_marked_arrange_sponsors_test_impl(chapters, expected, cuts) | |
202 | ||
203 | def test_remove_marked_arrange_sponsors_ChapterWithCutHidingSponsor(self): | |
63c547d7 | 204 | cuts = [self._sponsor_chapter(20, 50, 'selfpromo', remove=True)] |
add96eb9 | 205 | chapters = [ |
206 | *self._chapters([60], ['c']), | |
7a340e0d NA |
207 | self._sponsor_chapter(10, 20, 'intro'), |
208 | self._sponsor_chapter(30, 40, 'sponsor'), | |
209 | self._sponsor_chapter(50, 60, 'outro'), | |
add96eb9 | 210 | *cuts] |
7a340e0d NA |
211 | expected = self._chapters( |
212 | [10, 20, 30], ['c', '[SponsorBlock]: Intermission/Intro Animation', '[SponsorBlock]: Endcards/Credits']) | |
213 | self._remove_marked_arrange_sponsors_test_impl(chapters, expected, cuts) | |
214 | ||
215 | def test_remove_marked_arrange_sponsors_ChapterWithAdjacentSponsors(self): | |
add96eb9 | 216 | chapters = [ |
217 | *self._chapters([70], ['c']), | |
7a340e0d NA |
218 | self._sponsor_chapter(10, 20, 'sponsor'), |
219 | self._sponsor_chapter(20, 30, 'selfpromo'), | |
220 | self._sponsor_chapter(30, 40, 'interaction')] | |
221 | expected = self._chapters( | |
222 | [10, 20, 30, 40, 70], | |
223 | ['c', '[SponsorBlock]: Sponsor', '[SponsorBlock]: Unpaid/Self Promotion', | |
224 | '[SponsorBlock]: Interaction Reminder', 'c']) | |
225 | self._remove_marked_arrange_sponsors_test_impl(chapters, expected, []) | |
226 | ||
227 | def test_remove_marked_arrange_sponsors_ChapterWithAdjacentCuts(self): | |
add96eb9 | 228 | chapters = [ |
229 | *self._chapters([70], ['c']), | |
7a340e0d NA |
230 | self._sponsor_chapter(10, 20, 'sponsor'), |
231 | self._sponsor_chapter(20, 30, 'interaction', remove=True), | |
232 | self._chapter(30, 40, remove=True), | |
63c547d7 | 233 | self._sponsor_chapter(40, 50, 'selfpromo', remove=True), |
7a340e0d NA |
234 | self._sponsor_chapter(50, 60, 'interaction')] |
235 | expected = self._chapters([10, 20, 30, 40], | |
236 | ['c', '[SponsorBlock]: Sponsor', | |
237 | '[SponsorBlock]: Interaction Reminder', 'c']) | |
238 | self._remove_marked_arrange_sponsors_test_impl( | |
239 | chapters, expected, [self._chapter(20, 50, remove=True)]) | |
240 | ||
241 | def test_remove_marked_arrange_sponsors_ChapterWithOverlappingSponsors(self): | |
add96eb9 | 242 | chapters = [ |
243 | *self._chapters([70], ['c']), | |
7a340e0d NA |
244 | self._sponsor_chapter(10, 30, 'sponsor'), |
245 | self._sponsor_chapter(20, 50, 'selfpromo'), | |
246 | self._sponsor_chapter(40, 60, 'interaction')] | |
247 | expected = self._chapters( | |
248 | [10, 20, 30, 40, 50, 60, 70], | |
249 | ['c', '[SponsorBlock]: Sponsor', '[SponsorBlock]: Sponsor, Unpaid/Self Promotion', | |
250 | '[SponsorBlock]: Unpaid/Self Promotion', '[SponsorBlock]: Unpaid/Self Promotion, Interaction Reminder', | |
251 | '[SponsorBlock]: Interaction Reminder', 'c']) | |
252 | self._remove_marked_arrange_sponsors_test_impl(chapters, expected, []) | |
253 | ||
254 | def test_remove_marked_arrange_sponsors_ChapterWithOverlappingCuts(self): | |
add96eb9 | 255 | chapters = [ |
256 | *self._chapters([70], ['c']), | |
7a340e0d NA |
257 | self._sponsor_chapter(10, 30, 'sponsor', remove=True), |
258 | self._sponsor_chapter(20, 50, 'selfpromo', remove=True), | |
259 | self._sponsor_chapter(40, 60, 'interaction', remove=True)] | |
260 | self._remove_marked_arrange_sponsors_test_impl( | |
261 | chapters, self._chapters([20], ['c']), [self._chapter(10, 60, remove=True)]) | |
262 | ||
263 | def test_remove_marked_arrange_sponsors_ChapterWithRunsOfOverlappingSponsors(self): | |
add96eb9 | 264 | chapters = [ |
265 | *self._chapters([170], ['c']), | |
7a340e0d NA |
266 | self._sponsor_chapter(0, 30, 'intro'), |
267 | self._sponsor_chapter(20, 50, 'sponsor'), | |
268 | self._sponsor_chapter(40, 60, 'selfpromo'), | |
269 | self._sponsor_chapter(70, 90, 'sponsor'), | |
270 | self._sponsor_chapter(80, 100, 'sponsor'), | |
271 | self._sponsor_chapter(90, 110, 'sponsor'), | |
272 | self._sponsor_chapter(120, 140, 'selfpromo'), | |
273 | self._sponsor_chapter(130, 160, 'interaction'), | |
274 | self._sponsor_chapter(150, 170, 'outro')] | |
275 | expected = self._chapters( | |
276 | [20, 30, 40, 50, 60, 70, 110, 120, 130, 140, 150, 160, 170], | |
277 | ['[SponsorBlock]: Intermission/Intro Animation', '[SponsorBlock]: Intermission/Intro Animation, Sponsor', '[SponsorBlock]: Sponsor', | |
278 | '[SponsorBlock]: Sponsor, Unpaid/Self Promotion', '[SponsorBlock]: Unpaid/Self Promotion', 'c', | |
279 | '[SponsorBlock]: Sponsor', 'c', '[SponsorBlock]: Unpaid/Self Promotion', | |
280 | '[SponsorBlock]: Unpaid/Self Promotion, Interaction Reminder', | |
281 | '[SponsorBlock]: Interaction Reminder', | |
282 | '[SponsorBlock]: Interaction Reminder, Endcards/Credits', '[SponsorBlock]: Endcards/Credits']) | |
283 | self._remove_marked_arrange_sponsors_test_impl(chapters, expected, []) | |
284 | ||
285 | def test_remove_marked_arrange_sponsors_ChapterWithRunsOfOverlappingCuts(self): | |
add96eb9 | 286 | chapters = [ |
287 | *self._chapters([170], ['c']), | |
7a340e0d NA |
288 | self._chapter(0, 30, remove=True), |
289 | self._sponsor_chapter(20, 50, 'sponsor', remove=True), | |
290 | self._chapter(40, 60, remove=True), | |
291 | self._sponsor_chapter(70, 90, 'sponsor', remove=True), | |
292 | self._chapter(80, 100, remove=True), | |
293 | self._chapter(90, 110, remove=True), | |
294 | self._sponsor_chapter(120, 140, 'sponsor', remove=True), | |
295 | self._sponsor_chapter(130, 160, 'selfpromo', remove=True), | |
296 | self._chapter(150, 170, remove=True)] | |
297 | expected_cuts = [self._chapter(0, 60, remove=True), | |
298 | self._chapter(70, 110, remove=True), | |
299 | self._chapter(120, 170, remove=True)] | |
300 | self._remove_marked_arrange_sponsors_test_impl( | |
301 | chapters, self._chapters([20], ['c']), expected_cuts) | |
302 | ||
303 | def test_remove_marked_arrange_sponsors_OverlappingSponsorsDifferentTitlesAfterCut(self): | |
add96eb9 | 304 | chapters = [ |
305 | *self._chapters([60], ['c']), | |
7a340e0d NA |
306 | self._sponsor_chapter(10, 60, 'sponsor'), |
307 | self._sponsor_chapter(10, 40, 'intro'), | |
308 | self._sponsor_chapter(30, 50, 'interaction'), | |
309 | self._sponsor_chapter(30, 50, 'selfpromo', remove=True), | |
310 | self._sponsor_chapter(40, 50, 'interaction'), | |
311 | self._sponsor_chapter(50, 60, 'outro')] | |
312 | expected = self._chapters( | |
313 | [10, 30, 40], ['c', '[SponsorBlock]: Sponsor, Intermission/Intro Animation', '[SponsorBlock]: Sponsor, Endcards/Credits']) | |
314 | self._remove_marked_arrange_sponsors_test_impl( | |
315 | chapters, expected, [self._chapter(30, 50, remove=True)]) | |
316 | ||
317 | def test_remove_marked_arrange_sponsors_SponsorsNoLongerOverlapAfterCut(self): | |
add96eb9 | 318 | chapters = [ |
319 | *self._chapters([70], ['c']), | |
7a340e0d NA |
320 | self._sponsor_chapter(10, 30, 'sponsor'), |
321 | self._sponsor_chapter(20, 50, 'interaction'), | |
63c547d7 | 322 | self._sponsor_chapter(30, 50, 'selfpromo', remove=True), |
7a340e0d NA |
323 | self._sponsor_chapter(40, 60, 'sponsor'), |
324 | self._sponsor_chapter(50, 60, 'interaction')] | |
325 | expected = self._chapters( | |
326 | [10, 20, 40, 50], ['c', '[SponsorBlock]: Sponsor', | |
327 | '[SponsorBlock]: Sponsor, Interaction Reminder', 'c']) | |
328 | self._remove_marked_arrange_sponsors_test_impl( | |
329 | chapters, expected, [self._chapter(30, 50, remove=True)]) | |
330 | ||
331 | def test_remove_marked_arrange_sponsors_SponsorsStillOverlapAfterCut(self): | |
add96eb9 | 332 | chapters = [ |
333 | *self._chapters([70], ['c']), | |
7a340e0d NA |
334 | self._sponsor_chapter(10, 60, 'sponsor'), |
335 | self._sponsor_chapter(20, 60, 'interaction'), | |
336 | self._sponsor_chapter(30, 50, 'selfpromo', remove=True)] | |
337 | expected = self._chapters( | |
338 | [10, 20, 40, 50], ['c', '[SponsorBlock]: Sponsor', | |
339 | '[SponsorBlock]: Sponsor, Interaction Reminder', 'c']) | |
340 | self._remove_marked_arrange_sponsors_test_impl( | |
341 | chapters, expected, [self._chapter(30, 50, remove=True)]) | |
342 | ||
343 | def test_remove_marked_arrange_sponsors_ChapterWithRunsOfOverlappingSponsorsAndCuts(self): | |
add96eb9 | 344 | chapters = [ |
345 | *self._chapters([200], ['c']), | |
7a340e0d NA |
346 | self._sponsor_chapter(10, 40, 'sponsor'), |
347 | self._sponsor_chapter(10, 30, 'intro'), | |
348 | self._chapter(20, 30, remove=True), | |
349 | self._sponsor_chapter(30, 40, 'selfpromo'), | |
350 | self._sponsor_chapter(50, 70, 'sponsor'), | |
351 | self._sponsor_chapter(60, 80, 'interaction'), | |
352 | self._chapter(70, 80, remove=True), | |
353 | self._sponsor_chapter(70, 90, 'sponsor'), | |
354 | self._sponsor_chapter(80, 100, 'interaction'), | |
355 | self._sponsor_chapter(120, 170, 'selfpromo'), | |
356 | self._sponsor_chapter(130, 180, 'outro'), | |
357 | self._chapter(140, 150, remove=True), | |
358 | self._chapter(150, 160, remove=True)] | |
359 | expected = self._chapters( | |
360 | [10, 20, 30, 40, 50, 70, 80, 100, 110, 130, 140, 160], | |
361 | ['c', '[SponsorBlock]: Sponsor, Intermission/Intro Animation', '[SponsorBlock]: Sponsor, Unpaid/Self Promotion', | |
362 | 'c', '[SponsorBlock]: Sponsor', '[SponsorBlock]: Sponsor, Interaction Reminder', | |
363 | '[SponsorBlock]: Interaction Reminder', 'c', '[SponsorBlock]: Unpaid/Self Promotion', | |
364 | '[SponsorBlock]: Unpaid/Self Promotion, Endcards/Credits', '[SponsorBlock]: Endcards/Credits', 'c']) | |
365 | expected_cuts = [self._chapter(20, 30, remove=True), | |
366 | self._chapter(70, 80, remove=True), | |
367 | self._chapter(140, 160, remove=True)] | |
368 | self._remove_marked_arrange_sponsors_test_impl(chapters, expected, expected_cuts) | |
369 | ||
370 | def test_remove_marked_arrange_sponsors_SponsorOverlapsMultipleChapters(self): | |
add96eb9 | 371 | chapters = [ |
372 | *self._chapters([20, 40, 60, 80, 100], ['c1', 'c2', 'c3', 'c4', 'c5']), | |
373 | self._sponsor_chapter(10, 90, 'sponsor')] | |
7a340e0d NA |
374 | expected = self._chapters([10, 90, 100], ['c1', '[SponsorBlock]: Sponsor', 'c5']) |
375 | self._remove_marked_arrange_sponsors_test_impl(chapters, expected, []) | |
376 | ||
377 | def test_remove_marked_arrange_sponsors_CutOverlapsMultipleChapters(self): | |
378 | cuts = [self._chapter(10, 90, remove=True)] | |
379 | chapters = self._chapters([20, 40, 60, 80, 100], ['c1', 'c2', 'c3', 'c4', 'c5']) + cuts | |
380 | expected = self._chapters([10, 20], ['c1', 'c5']) | |
381 | self._remove_marked_arrange_sponsors_test_impl(chapters, expected, cuts) | |
382 | ||
383 | def test_remove_marked_arrange_sponsors_SponsorsWithinSomeChaptersAndOverlappingOthers(self): | |
add96eb9 | 384 | chapters = [ |
385 | *self._chapters([10, 40, 60, 80], ['c1', 'c2', 'c3', 'c4']), | |
386 | self._sponsor_chapter(20, 30, 'sponsor'), | |
387 | self._sponsor_chapter(50, 70, 'selfpromo')] | |
7a340e0d NA |
388 | expected = self._chapters([10, 20, 30, 40, 50, 70, 80], |
389 | ['c1', 'c2', '[SponsorBlock]: Sponsor', 'c2', 'c3', | |
390 | '[SponsorBlock]: Unpaid/Self Promotion', 'c4']) | |
391 | self._remove_marked_arrange_sponsors_test_impl(chapters, expected, []) | |
392 | ||
393 | def test_remove_marked_arrange_sponsors_CutsWithinSomeChaptersAndOverlappingOthers(self): | |
394 | cuts = [self._chapter(20, 30, remove=True), self._chapter(50, 70, remove=True)] | |
395 | chapters = self._chapters([10, 40, 60, 80], ['c1', 'c2', 'c3', 'c4']) + cuts | |
396 | expected = self._chapters([10, 30, 40, 50], ['c1', 'c2', 'c3', 'c4']) | |
397 | self._remove_marked_arrange_sponsors_test_impl(chapters, expected, cuts) | |
398 | ||
399 | def test_remove_marked_arrange_sponsors_ChaptersAfterLastSponsor(self): | |
add96eb9 | 400 | chapters = [ |
401 | *self._chapters([20, 40, 50, 60], ['c1', 'c2', 'c3', 'c4']), | |
402 | self._sponsor_chapter(10, 30, 'music_offtopic')] | |
7a340e0d NA |
403 | expected = self._chapters( |
404 | [10, 30, 40, 50, 60], | |
405 | ['c1', '[SponsorBlock]: Non-Music Section', 'c2', 'c3', 'c4']) | |
406 | self._remove_marked_arrange_sponsors_test_impl(chapters, expected, []) | |
407 | ||
408 | def test_remove_marked_arrange_sponsors_ChaptersAfterLastCut(self): | |
409 | cuts = [self._chapter(10, 30, remove=True)] | |
410 | chapters = self._chapters([20, 40, 50, 60], ['c1', 'c2', 'c3', 'c4']) + cuts | |
411 | expected = self._chapters([10, 20, 30, 40], ['c1', 'c2', 'c3', 'c4']) | |
412 | self._remove_marked_arrange_sponsors_test_impl(chapters, expected, cuts) | |
413 | ||
414 | def test_remove_marked_arrange_sponsors_SponsorStartsAtChapterStart(self): | |
add96eb9 | 415 | chapters = [ |
416 | *self._chapters([10, 20, 40], ['c1', 'c2', 'c3']), | |
417 | self._sponsor_chapter(20, 30, 'sponsor')] | |
7a340e0d NA |
418 | expected = self._chapters([10, 20, 30, 40], ['c1', 'c2', '[SponsorBlock]: Sponsor', 'c3']) |
419 | self._remove_marked_arrange_sponsors_test_impl(chapters, expected, []) | |
420 | ||
421 | def test_remove_marked_arrange_sponsors_CutStartsAtChapterStart(self): | |
422 | cuts = [self._chapter(20, 30, remove=True)] | |
423 | chapters = self._chapters([10, 20, 40], ['c1', 'c2', 'c3']) + cuts | |
424 | expected = self._chapters([10, 20, 30], ['c1', 'c2', 'c3']) | |
425 | self._remove_marked_arrange_sponsors_test_impl(chapters, expected, cuts) | |
426 | ||
427 | def test_remove_marked_arrange_sponsors_SponsorEndsAtChapterEnd(self): | |
add96eb9 | 428 | chapters = [ |
429 | *self._chapters([10, 30, 40], ['c1', 'c2', 'c3']), | |
430 | self._sponsor_chapter(20, 30, 'sponsor')] | |
7a340e0d NA |
431 | expected = self._chapters([10, 20, 30, 40], ['c1', 'c2', '[SponsorBlock]: Sponsor', 'c3']) |
432 | self._remove_marked_arrange_sponsors_test_impl(chapters, expected, []) | |
433 | ||
434 | def test_remove_marked_arrange_sponsors_CutEndsAtChapterEnd(self): | |
435 | cuts = [self._chapter(20, 30, remove=True)] | |
436 | chapters = self._chapters([10, 30, 40], ['c1', 'c2', 'c3']) + cuts | |
437 | expected = self._chapters([10, 20, 30], ['c1', 'c2', 'c3']) | |
438 | self._remove_marked_arrange_sponsors_test_impl(chapters, expected, cuts) | |
439 | ||
440 | def test_remove_marked_arrange_sponsors_SponsorCoincidesWithChapters(self): | |
add96eb9 | 441 | chapters = [ |
442 | *self._chapters([10, 20, 30, 40], ['c1', 'c2', 'c3', 'c4']), | |
443 | self._sponsor_chapter(10, 30, 'sponsor')] | |
7a340e0d NA |
444 | expected = self._chapters([10, 30, 40], ['c1', '[SponsorBlock]: Sponsor', 'c4']) |
445 | self._remove_marked_arrange_sponsors_test_impl(chapters, expected, []) | |
446 | ||
447 | def test_remove_marked_arrange_sponsors_CutCoincidesWithChapters(self): | |
448 | cuts = [self._chapter(10, 30, remove=True)] | |
449 | chapters = self._chapters([10, 20, 30, 40], ['c1', 'c2', 'c3', 'c4']) + cuts | |
450 | expected = self._chapters([10, 20], ['c1', 'c4']) | |
451 | self._remove_marked_arrange_sponsors_test_impl(chapters, expected, cuts) | |
452 | ||
453 | def test_remove_marked_arrange_sponsors_SponsorsAtVideoBoundaries(self): | |
add96eb9 | 454 | chapters = [ |
455 | *self._chapters([20, 40, 60], ['c1', 'c2', 'c3']), | |
456 | self._sponsor_chapter(0, 10, 'intro'), self._sponsor_chapter(50, 60, 'outro')] | |
7a340e0d NA |
457 | expected = self._chapters( |
458 | [10, 20, 40, 50, 60], ['[SponsorBlock]: Intermission/Intro Animation', 'c1', 'c2', 'c3', '[SponsorBlock]: Endcards/Credits']) | |
459 | self._remove_marked_arrange_sponsors_test_impl(chapters, expected, []) | |
460 | ||
461 | def test_remove_marked_arrange_sponsors_CutsAtVideoBoundaries(self): | |
462 | cuts = [self._chapter(0, 10, remove=True), self._chapter(50, 60, remove=True)] | |
463 | chapters = self._chapters([20, 40, 60], ['c1', 'c2', 'c3']) + cuts | |
464 | expected = self._chapters([10, 30, 40], ['c1', 'c2', 'c3']) | |
465 | self._remove_marked_arrange_sponsors_test_impl(chapters, expected, cuts) | |
466 | ||
467 | def test_remove_marked_arrange_sponsors_SponsorsOverlapChaptersAtVideoBoundaries(self): | |
add96eb9 | 468 | chapters = [ |
469 | *self._chapters([10, 40, 50], ['c1', 'c2', 'c3']), | |
470 | self._sponsor_chapter(0, 20, 'intro'), | |
471 | self._sponsor_chapter(30, 50, 'outro')] | |
7a340e0d NA |
472 | expected = self._chapters( |
473 | [20, 30, 50], ['[SponsorBlock]: Intermission/Intro Animation', 'c2', '[SponsorBlock]: Endcards/Credits']) | |
474 | self._remove_marked_arrange_sponsors_test_impl(chapters, expected, []) | |
475 | ||
476 | def test_remove_marked_arrange_sponsors_CutsOverlapChaptersAtVideoBoundaries(self): | |
477 | cuts = [self._chapter(0, 20, remove=True), self._chapter(30, 50, remove=True)] | |
478 | chapters = self._chapters([10, 40, 50], ['c1', 'c2', 'c3']) + cuts | |
479 | expected = self._chapters([10], ['c2']) | |
480 | self._remove_marked_arrange_sponsors_test_impl(chapters, expected, cuts) | |
481 | ||
482 | def test_remove_marked_arrange_sponsors_EverythingSponsored(self): | |
add96eb9 | 483 | chapters = [ |
484 | *self._chapters([10, 20, 30, 40], ['c1', 'c2', 'c3', 'c4']), | |
485 | self._sponsor_chapter(0, 20, 'intro'), | |
486 | self._sponsor_chapter(20, 40, 'outro')] | |
7a340e0d NA |
487 | expected = self._chapters([20, 40], ['[SponsorBlock]: Intermission/Intro Animation', '[SponsorBlock]: Endcards/Credits']) |
488 | self._remove_marked_arrange_sponsors_test_impl(chapters, expected, []) | |
489 | ||
490 | def test_remove_marked_arrange_sponsors_EverythingCut(self): | |
491 | cuts = [self._chapter(0, 20, remove=True), self._chapter(20, 40, remove=True)] | |
492 | chapters = self._chapters([10, 20, 30, 40], ['c1', 'c2', 'c3', 'c4']) + cuts | |
493 | self._remove_marked_arrange_sponsors_test_impl( | |
494 | chapters, [], [self._chapter(0, 40, remove=True)]) | |
495 | ||
496 | def test_remove_marked_arrange_sponsors_TinyChaptersInTheOriginalArePreserved(self): | |
497 | chapters = self._chapters([0.1, 0.2, 0.3, 0.4], ['c1', 'c2', 'c3', 'c4']) | |
498 | self._remove_marked_arrange_sponsors_test_impl(chapters, chapters, []) | |
499 | ||
500 | def test_remove_marked_arrange_sponsors_TinySponsorsAreIgnored(self): | |
501 | chapters = [self._sponsor_chapter(0, 0.1, 'intro'), self._chapter(0.1, 0.2, 'c1'), | |
502 | self._sponsor_chapter(0.2, 0.3, 'sponsor'), self._chapter(0.3, 0.4, 'c2'), | |
503 | self._sponsor_chapter(0.4, 0.5, 'outro')] | |
504 | self._remove_marked_arrange_sponsors_test_impl( | |
505 | chapters, self._chapters([0.3, 0.5], ['c1', 'c2']), []) | |
506 | ||
507 | def test_remove_marked_arrange_sponsors_TinyChaptersResultingFromCutsAreIgnored(self): | |
508 | cuts = [self._chapter(1.5, 2.5, remove=True)] | |
509 | chapters = self._chapters([2, 3, 3.5], ['c1', 'c2', 'c3']) + cuts | |
510 | self._remove_marked_arrange_sponsors_test_impl( | |
511 | chapters, self._chapters([2, 2.5], ['c1', 'c3']), cuts) | |
512 | ||
c6af2dd8 NA |
513 | def test_remove_marked_arrange_sponsors_SingleTinyChapterIsPreserved(self): |
514 | cuts = [self._chapter(0.5, 2, remove=True)] | |
515 | chapters = self._chapters([2], ['c']) + cuts | |
516 | self._remove_marked_arrange_sponsors_test_impl( | |
517 | chapters, self._chapters([0.5], ['c']), cuts) | |
518 | ||
519 | def test_remove_marked_arrange_sponsors_TinyChapterAtTheStartPrependedToTheNext(self): | |
520 | cuts = [self._chapter(0.5, 2, remove=True)] | |
521 | chapters = self._chapters([2, 4], ['c1', 'c2']) + cuts | |
522 | self._remove_marked_arrange_sponsors_test_impl( | |
523 | chapters, self._chapters([2.5], ['c2']), cuts) | |
524 | ||
7a340e0d | 525 | def test_remove_marked_arrange_sponsors_TinyChaptersResultingFromSponsorOverlapAreIgnored(self): |
add96eb9 | 526 | chapters = [ |
527 | *self._chapters([1, 3, 4], ['c1', 'c2', 'c3']), | |
7a340e0d NA |
528 | self._sponsor_chapter(1.5, 2.5, 'sponsor')] |
529 | self._remove_marked_arrange_sponsors_test_impl( | |
c6af2dd8 | 530 | chapters, self._chapters([1.5, 2.5, 4], ['c1', '[SponsorBlock]: Sponsor', 'c3']), []) |
7a340e0d NA |
531 | |
532 | def test_remove_marked_arrange_sponsors_TinySponsorsOverlapsAreIgnored(self): | |
add96eb9 | 533 | chapters = [ |
534 | *self._chapters([2, 3, 5], ['c1', 'c2', 'c3']), | |
7a340e0d | 535 | self._sponsor_chapter(1, 3, 'sponsor'), |
add96eb9 | 536 | self._sponsor_chapter(2.5, 4, 'selfpromo')] |
7a340e0d NA |
537 | self._remove_marked_arrange_sponsors_test_impl( |
538 | chapters, self._chapters([1, 3, 4, 5], [ | |
539 | 'c1', '[SponsorBlock]: Sponsor', '[SponsorBlock]: Unpaid/Self Promotion', 'c3']), []) | |
540 | ||
c6af2dd8 | 541 | def test_remove_marked_arrange_sponsors_TinySponsorsPrependedToTheNextSponsor(self): |
add96eb9 | 542 | chapters = [ |
543 | *self._chapters([4], ['c']), | |
c6af2dd8 | 544 | self._sponsor_chapter(1.5, 2, 'sponsor'), |
add96eb9 | 545 | self._sponsor_chapter(2, 4, 'selfpromo')] |
c6af2dd8 NA |
546 | self._remove_marked_arrange_sponsors_test_impl( |
547 | chapters, self._chapters([1.5, 4], ['c', '[SponsorBlock]: Unpaid/Self Promotion']), []) | |
548 | ||
549 | def test_remove_marked_arrange_sponsors_SmallestSponsorInTheOverlapGetsNamed(self): | |
550 | self._pp._sponsorblock_chapter_title = '[SponsorBlock]: %(name)s' | |
add96eb9 | 551 | chapters = [ |
552 | *self._chapters([10], ['c']), | |
c6af2dd8 | 553 | self._sponsor_chapter(2, 8, 'sponsor'), |
add96eb9 | 554 | self._sponsor_chapter(4, 6, 'selfpromo')] |
c6af2dd8 NA |
555 | self._remove_marked_arrange_sponsors_test_impl( |
556 | chapters, self._chapters([2, 4, 6, 8, 10], [ | |
557 | 'c', '[SponsorBlock]: Sponsor', '[SponsorBlock]: Unpaid/Self Promotion', | |
add96eb9 | 558 | '[SponsorBlock]: Sponsor', 'c', |
c6af2dd8 NA |
559 | ]), []) |
560 | ||
7a340e0d NA |
561 | def test_make_concat_opts_CommonCase(self): |
562 | sponsor_chapters = [self._chapter(1, 2, 's1'), self._chapter(10, 20, 's2')] | |
563 | expected = '''ffconcat version 1.0 | |
564 | file 'file:test' | |
565 | outpoint 1.000000 | |
566 | file 'file:test' | |
567 | inpoint 2.000000 | |
568 | outpoint 10.000000 | |
569 | file 'file:test' | |
570 | inpoint 20.000000 | |
571 | ''' | |
572 | opts = self._pp._make_concat_opts(sponsor_chapters, 30) | |
573 | self.assertEqual(expected, ''.join(self._pp._concat_spec(['test'] * len(opts), opts))) | |
574 | ||
575 | def test_make_concat_opts_NoZeroDurationChunkAtVideoStart(self): | |
576 | sponsor_chapters = [self._chapter(0, 1, 's1'), self._chapter(10, 20, 's2')] | |
577 | expected = '''ffconcat version 1.0 | |
578 | file 'file:test' | |
579 | inpoint 1.000000 | |
580 | outpoint 10.000000 | |
581 | file 'file:test' | |
582 | inpoint 20.000000 | |
583 | ''' | |
584 | opts = self._pp._make_concat_opts(sponsor_chapters, 30) | |
585 | self.assertEqual(expected, ''.join(self._pp._concat_spec(['test'] * len(opts), opts))) | |
586 | ||
587 | def test_make_concat_opts_NoZeroDurationChunkAtVideoEnd(self): | |
588 | sponsor_chapters = [self._chapter(1, 2, 's1'), self._chapter(10, 20, 's2')] | |
589 | expected = '''ffconcat version 1.0 | |
590 | file 'file:test' | |
591 | outpoint 1.000000 | |
592 | file 'file:test' | |
593 | inpoint 2.000000 | |
594 | outpoint 10.000000 | |
595 | ''' | |
596 | opts = self._pp._make_concat_opts(sponsor_chapters, 20) | |
597 | self.assertEqual(expected, ''.join(self._pp._concat_spec(['test'] * len(opts), opts))) | |
598 | ||
599 | def test_quote_for_concat_RunsOfQuotes(self): | |
600 | self.assertEqual( | |
601 | r"'special '\'' '\'\''characters'\'\'\''galore'", | |
602 | self._pp._quote_for_ffmpeg("special ' ''characters'''galore")) | |
603 | ||
604 | def test_quote_for_concat_QuotesAtStart(self): | |
605 | self.assertEqual( | |
606 | r"\'\'\''special '\'' characters '\'' galore'", | |
607 | self._pp._quote_for_ffmpeg("'''special ' characters ' galore")) | |
608 | ||
609 | def test_quote_for_concat_QuotesAtEnd(self): | |
610 | self.assertEqual( | |
611 | r"'special '\'' characters '\'' galore'\'\'\'", | |
612 | self._pp._quote_for_ffmpeg("special ' characters ' galore'''")) |