Skip to content

Commit

Permalink
Remove TextSubtitle, add dialogue property
Browse files Browse the repository at this point in the history
AssSubtitle is used even for non ASS/SSA formats. These changes
make that more obvious to users. FFmpeg does not export ass_split.h,
so the dialogue getter is implemented directly in Cython.
  • Loading branch information
WyattBlue committed Jul 15, 2024
1 parent 6488603 commit 5730ef0
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 24 deletions.
13 changes: 7 additions & 6 deletions av/subtitles/subtitle.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@ class BitmapSubtitlePlane:
index: int
buffer_size: int

class TextSubtitle(Subtitle):
type: Literal[b"text"]
text: bytes

class AssSubtitle(Subtitle):
type: Literal[b"ass"]
ass: bytes
type: Literal[b"ass", b"text"]
@property
def ass(self) -> bytes: ...
@property
def dialogue(self) -> bytes: ...
@property
def text(self) -> bytes: ...
69 changes: 52 additions & 17 deletions av/subtitles/subtitle.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,7 @@ cdef Subtitle build_subtitle(SubtitleSet subtitle, int index):

if ptr.type == lib.SUBTITLE_BITMAP:
return BitmapSubtitle(subtitle, index)
elif ptr.type == lib.SUBTITLE_TEXT:
return TextSubtitle(subtitle, index)
elif ptr.type == lib.SUBTITLE_ASS:
elif ptr.type == lib.SUBTITLE_ASS or ptr.type == lib.SUBTITLE_TEXT:
return AssSubtitle(subtitle, index)
else:
raise ValueError("unknown subtitle type %r" % ptr.type)
Expand Down Expand Up @@ -141,29 +139,66 @@ cdef class BitmapSubtitlePlane:
PyBuffer_FillInfo(view, self, self._buffer, self.buffer_size, 0, flags)


cdef class TextSubtitle(Subtitle):
cdef class AssSubtitle(Subtitle):
"""
Represents an ASS/Text subtitle format, as opposed to a bitmap Subtitle format.
"""
def __repr__(self):
return (
f"<{self.__class__.__module__}.{self.__class__.__name__} "
f"{self.text!r} at 0x{id(self):x}>"
)

@property
def text(self):
if self.ptr.text is not NULL:
return PyBytes_FromString(self.ptr.text)
def ass(self):
"""
Returns the subtitle in the ASS/SSA format. Used by the vast majority of subtitle formats.
"""
if self.ptr.ass is not NULL:
return PyBytes_FromString(self.ptr.ass)
return b""


cdef class AssSubtitle(Subtitle):
def __repr__(self):
return (
f"<{self.__class__.__module__}.{self.__class__.__name__} "
f"{self.ass!r} at 0x{id(self):x}>"
)
@property
def dialogue(self):
"""
Extract the dialogue from the ass format. Strip comments.
"""
comma_count = 0
i = 0
cdef bytes ass_text = self.ass
cdef bytes result = b""

while comma_count < 8 and i < len(ass_text):
if bytes([ass_text[i]]) == b",":
comma_count += 1
i += 1

state = False
while i < len(ass_text):
char = bytes([ass_text[i]])
next_char = b"" if i + 1 >= len(ass_text) else bytes([ass_text[i + 1]])

if char == b"\\" and next_char == b"N":
result += b"\n"
i += 2
continue

if not state:
if char == b"{" and next_char != b"\\":
state = True
else:
result += char
elif char == b"}":
state = False
i += 1

return result

@property
def ass(self):
if self.ptr.ass is not NULL:
return PyBytes_FromString(self.ptr.ass)
def text(self):
"""
Rarely used attribute. You're probably looking for dialogue.
"""
if self.ptr.text is not NULL:
return PyBytes_FromString(self.ptr.text)
return b""
6 changes: 5 additions & 1 deletion tests/test_subtitles.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@


class TestSubtitle(TestCase):
def test_movtext(self):
def test_movtext(self) -> None:
path = fate_suite("sub/MovText_capability_tester.mp4")

subs = []
Expand All @@ -23,8 +23,12 @@ def test_movtext(self):

sub = subset[0]
self.assertIsInstance(sub, AssSubtitle)
assert isinstance(sub, AssSubtitle)

self.assertEqual(sub.type, b"ass")
self.assertEqual(sub.text, b"")
self.assertEqual(sub.ass, b"0,0,Default,,0,0,0,,- Test 1.\\N- Test 2.")
self.assertEqual(sub.dialogue, b"- Test 1.\n- Test 2.")

def test_vobsub(self):
path = fate_suite("sub/vobsub.sub")
Expand Down

0 comments on commit 5730ef0

Please sign in to comment.