#!/usr/bin/env python3
-from __future__ import unicode_literals
-
# Allow direct execution
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+
from yt_dlp import YoutubeDL
from yt_dlp.compat import compat_shlex_quote
from yt_dlp.postprocessor import (
FFmpegThumbnailsConvertorPP,
MetadataFromFieldPP,
MetadataParserPP,
- ModifyChaptersPP
+ ModifyChaptersPP,
+ SponsorBlockPP,
)
self._pp = ModifyChaptersPP(YoutubeDL())
@staticmethod
- def _sponsor_chapter(start, end, cat, remove=False):
- c = {'start_time': start, 'end_time': end, '_categories': [(cat, start, end)]}
- if remove:
- c['remove'] = True
- return c
+ def _sponsor_chapter(start, end, cat, remove=False, title=None):
+ if title is None:
+ title = SponsorBlockPP.CATEGORIES[cat]
+ return {
+ 'start_time': start,
+ 'end_time': end,
+ '_categories': [(cat, start, end, title)],
+ **({'remove': True} if remove else {}),
+ }
@staticmethod
def _chapter(start, end, title=None, remove=False):
chapters = self._chapters([70], ['c']) + [
self._sponsor_chapter(10, 20, 'sponsor'),
self._sponsor_chapter(30, 40, 'preview'),
- self._sponsor_chapter(50, 60, 'sponsor')]
+ self._sponsor_chapter(50, 60, 'filler')]
expected = self._chapters(
[10, 20, 30, 40, 50, 60, 70],
['c', '[SponsorBlock]: Sponsor', 'c', '[SponsorBlock]: Preview/Recap',
- 'c', '[SponsorBlock]: Sponsor', 'c'])
+ 'c', '[SponsorBlock]: Filler Tangent', 'c'])
+ self._remove_marked_arrange_sponsors_test_impl(chapters, expected, [])
+
+ def test_remove_marked_arrange_sponsors_SponsorBlockChapters(self):
+ chapters = self._chapters([70], ['c']) + [
+ self._sponsor_chapter(10, 20, 'chapter', title='sb c1'),
+ self._sponsor_chapter(15, 16, 'chapter', title='sb c2'),
+ self._sponsor_chapter(30, 40, 'preview'),
+ self._sponsor_chapter(50, 60, 'filler')]
+ expected = self._chapters(
+ [10, 15, 16, 20, 30, 40, 50, 60, 70],
+ ['c', '[SponsorBlock]: sb c1', '[SponsorBlock]: sb c1, sb c2', '[SponsorBlock]: sb c1',
+ 'c', '[SponsorBlock]: Preview/Recap',
+ 'c', '[SponsorBlock]: Filler Tangent', 'c'])
self._remove_marked_arrange_sponsors_test_impl(chapters, expected, [])
def test_remove_marked_arrange_sponsors_UniqueNamesForOverlappingSponsors(self):
self._remove_marked_arrange_sponsors_test_impl(chapters, expected, cuts)
def test_remove_marked_arrange_sponsors_ChapterWithCutHidingSponsor(self):
- cuts = [self._sponsor_chapter(20, 50, 'selpromo', remove=True)]
+ cuts = [self._sponsor_chapter(20, 50, 'selfpromo', remove=True)]
chapters = self._chapters([60], ['c']) + [
self._sponsor_chapter(10, 20, 'intro'),
self._sponsor_chapter(30, 40, 'sponsor'),
self._sponsor_chapter(10, 20, 'sponsor'),
self._sponsor_chapter(20, 30, 'interaction', remove=True),
self._chapter(30, 40, remove=True),
- self._sponsor_chapter(40, 50, 'selpromo', remove=True),
+ self._sponsor_chapter(40, 50, 'selfpromo', remove=True),
self._sponsor_chapter(50, 60, 'interaction')]
expected = self._chapters([10, 20, 30, 40],
['c', '[SponsorBlock]: Sponsor',
chapters = self._chapters([70], ['c']) + [
self._sponsor_chapter(10, 30, 'sponsor'),
self._sponsor_chapter(20, 50, 'interaction'),
- self._sponsor_chapter(30, 50, 'selpromo', remove=True),
+ self._sponsor_chapter(30, 50, 'selfpromo', remove=True),
self._sponsor_chapter(40, 60, 'sponsor'),
self._sponsor_chapter(50, 60, 'interaction')]
expected = self._chapters(
self._remove_marked_arrange_sponsors_test_impl(
chapters, self._chapters([2, 2.5], ['c1', 'c3']), cuts)
+ def test_remove_marked_arrange_sponsors_SingleTinyChapterIsPreserved(self):
+ cuts = [self._chapter(0.5, 2, remove=True)]
+ chapters = self._chapters([2], ['c']) + cuts
+ self._remove_marked_arrange_sponsors_test_impl(
+ chapters, self._chapters([0.5], ['c']), cuts)
+
+ def test_remove_marked_arrange_sponsors_TinyChapterAtTheStartPrependedToTheNext(self):
+ cuts = [self._chapter(0.5, 2, remove=True)]
+ chapters = self._chapters([2, 4], ['c1', 'c2']) + cuts
+ self._remove_marked_arrange_sponsors_test_impl(
+ chapters, self._chapters([2.5], ['c2']), cuts)
+
def test_remove_marked_arrange_sponsors_TinyChaptersResultingFromSponsorOverlapAreIgnored(self):
chapters = self._chapters([1, 3, 4], ['c1', 'c2', 'c3']) + [
self._sponsor_chapter(1.5, 2.5, 'sponsor')]
self._remove_marked_arrange_sponsors_test_impl(
- chapters, self._chapters([1.5, 3, 4], ['c1', '[SponsorBlock]: Sponsor', 'c3']), [])
+ chapters, self._chapters([1.5, 2.5, 4], ['c1', '[SponsorBlock]: Sponsor', 'c3']), [])
def test_remove_marked_arrange_sponsors_TinySponsorsOverlapsAreIgnored(self):
chapters = self._chapters([2, 3, 5], ['c1', 'c2', 'c3']) + [
chapters, self._chapters([1, 3, 4, 5], [
'c1', '[SponsorBlock]: Sponsor', '[SponsorBlock]: Unpaid/Self Promotion', 'c3']), [])
+ def test_remove_marked_arrange_sponsors_TinySponsorsPrependedToTheNextSponsor(self):
+ chapters = self._chapters([4], ['c']) + [
+ self._sponsor_chapter(1.5, 2, 'sponsor'),
+ self._sponsor_chapter(2, 4, 'selfpromo')
+ ]
+ self._remove_marked_arrange_sponsors_test_impl(
+ chapters, self._chapters([1.5, 4], ['c', '[SponsorBlock]: Unpaid/Self Promotion']), [])
+
+ def test_remove_marked_arrange_sponsors_SmallestSponsorInTheOverlapGetsNamed(self):
+ self._pp._sponsorblock_chapter_title = '[SponsorBlock]: %(name)s'
+ chapters = self._chapters([10], ['c']) + [
+ self._sponsor_chapter(2, 8, 'sponsor'),
+ self._sponsor_chapter(4, 6, 'selfpromo')
+ ]
+ self._remove_marked_arrange_sponsors_test_impl(
+ chapters, self._chapters([2, 4, 6, 8, 10], [
+ 'c', '[SponsorBlock]: Sponsor', '[SponsorBlock]: Unpaid/Self Promotion',
+ '[SponsorBlock]: Sponsor', 'c'
+ ]), [])
+
def test_make_concat_opts_CommonCase(self):
sponsor_chapters = [self._chapter(1, 2, 's1'), self._chapter(10, 20, 's2')]
expected = '''ffconcat version 1.0