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