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