def test_keep_unknown_html_tags(): # see issue #26 text = dedent("""\ 1 00:00:10,500 --> 00:00:13,000 <i>Elephant's <sub>Little</sub> Dream</i> 2 00:00:15,000 --> 00:00:18,000 <font color="cyan">At the left we can see...</font> """) ref_default = SSAFile() ref_default.append(SSAEvent(start=make_time(s=10.5), end=make_time(s=13), text="{\\i1}Elephant's Little Dream{\\i0}")) ref_default.append(SSAEvent(start=make_time(s=15), end=make_time(s=18), text="At the left we can see...")) ref_keep = SSAFile() ref_keep.append(SSAEvent(start=make_time(s=10.5), end=make_time(s=13), text="{\\i1}Elephant's <sub>Little</sub> Dream{\\i0}")) ref_keep.append(SSAEvent(start=make_time(s=15), end=make_time(s=18), text="<font color=\"cyan\">At the left we can see...</font>")) subs_default = SSAFile.from_string(text) subs_keep = SSAFile.from_string(text, keep_unknown_html_tags=True) assert subs_default.equals(ref_default) assert subs_keep.equals(ref_keep) assert subs_keep.to_string("srt") == ref_keep.to_string("srt")
def test_repr_comment(): ev = SSAEvent(start=make_time(m=1, s=30), end=make_time(m=1, s=35), text="Hello\\Nworld!") ev.is_comment = True ref = r"<SSAEvent type=Comment start=0:01:30 end=0:01:35 text='Hello\\Nworld!'>" assert repr(ev) == ref
def test_simple_parsing(): test_input1 = "[123][456] Line 1" subs1 = SSAFile.from_string(test_input1) assert len(subs1) == 1 assert subs1[0] == SSAEvent(start=make_time(ms=12300), end=make_time(ms=45600), text="Line 1") test_input2 = "[123][456] / Line 1| Line 2/2" subs2 = SSAFile.from_string(test_input2) assert len(subs2) == 1 assert subs2[0] == SSAEvent(start=make_time(ms=12300), end=make_time(ms=45600), text="{\i1}Line 1{\i0}\\NLine2/2") test_input3 = dedent(""" [123][456] Line 1 [321][456] / Line 2| Line 3 (123)(456)This line should not be parsed This line should also not be parsed [789][1234] /Line 4""") subs3 = SSAFile.from_string(test_input3) assert len(subs3) == 3 assert subs3[0] == SSAEvent(start=make_time(ms=12300), end=make_time(ms=45600), text="Line 1") assert subs3[1] == SSAEvent(start=make_time(ms=32100), end=make_time(ms=45600), text="{\i1}Line 2{\i0}\\NLine 3") assert subs3[2] == SSAEvent(start=make_time(ms=78900), end=make_time(ms=123400), text="{\i1}Line 4{\i0}")
def create_ass_file(subtitle_blocks: List[SubtitleBlock], ass_file, styles: Dict[str, StyleConfig]): subs = SSAFile() colors = [Color(255, 255, 255), Color(100, 100, 255), Color(255, 100, 100)] for k, name in enumerate(subtitle_blocks[0].names): my_style = subs.styles["Default"].copy() my_style.primarycolor = colors[k] my_style.fontsize = styles[name].fontsize my_style.shadow = 0 subs.styles[name] = my_style for sb in subtitle_blocks: start, end = None, None for name, text in sb.name_texts: if len(text) > 0: text = text.replace("_", " ") if start is None: start = sb.start end = sb.end sub_line = SSAEvent( start=start, end=end, text=text, ) sub_line.style = name subs.append(sub_line) else: print(f"WARNING: got empty block! {name} ") subs.save(ass_file)
def test_write_drawing(): # test for 7bde9a6c3a250cf0880a8a9fe31d1b6a69ff21a0 subs = SSAFile() e1 = SSAEvent() e1.start = 0 e1.end = 60000 e1.text = r"{\p1}m 0 0 l 100 0 100 100 0 100{\p0}test" e2 = SSAEvent() e2.start = 60000 e2.end = 120000 e2.text = "Subtitle number\\Ntwo." subs.append(e1) subs.append(e2) ref = dedent("""\ 1 00:01:00,000 --> 00:02:00,000 Subtitle number two. """) text = subs.to_string("srt") assert text.strip() == ref.strip()
def test_empty_subtitles(): # regression test for issue #11 text = dedent(""" 392 00:29:27,46 --> 00:29:29,83 I'm Liza Minnelli.. 393 00:00:00,00 --> 00:00:00,00 394 00:00:00,00 --> 00:00:00,00 """) ref = SSAFile() ref.append( SSAEvent(start=make_time(m=29, s=27, ms=460), end=make_time(m=29, s=29, ms=830), text="I'm Liza Minnelli..")) ref.append(SSAEvent(start=0, end=0, text="")) ref.append(SSAEvent(start=0, end=0, text="")) subs = SSAFile.from_string(text) assert subs.equals(ref)
def test_read_position_styling(): """position is ignored, italic is converted, color is ignored""" text = dedent("""\ 1 00:00:10,500 --> 00:00:13,000 X1:63 X2:223 Y1:43 Y2:58 <i>Elephant's Dream</i> 2 00:00:15,000 --> 00:00:18,000 X1:53 X2:303 Y1:438 Y2:453 <font color="cyan">At the left we can see...</font> """) ref = SSAFile() ref.append( SSAEvent(start=make_time(s=10.5), end=make_time(s=13), text="{\\i1}Elephant's Dream{\\i0}")) ref.append( SSAEvent(start=make_time(s=15), end=make_time(s=18), text="At the left we can see...")) subs = SSAFile.from_string(text) assert subs.equals(ref)
def test_read_complex(): # regression test for #30 text = dedent("""\ WEBVTT X-TIMESTAMP-MAP=LOCAL:00:00:00.000,MPEGTS:0 00:50.099 --> 00:53.299 line:85% align:middle Cuidem do seu grupo. Cuidem de suas fileiras. 01:54.255 --> 01:55.455 line:85% align:middle Parem! 01:58.155 --> 01:59.555 line:85% align:middle E, parem! """) ref = SSAFile() ref.append( SSAEvent(start=make_time(s=50, ms=99), end=make_time(s=53, ms=299), text=r"Cuidem do seu grupo.\NCuidem de suas fileiras.")) ref.append( SSAEvent(start=make_time(m=1, s=54, ms=255), end=make_time(m=1, s=55, ms=455), text="Parem!")) ref.append( SSAEvent(start=make_time(m=1, s=58, ms=155), end=make_time(m=1, s=59, ms=555), text="E, parem!")) subs = SSAFile.from_string(text) assert subs.equals(ref)
def test_repr_simple(): subs = SSAFile() subs.append(SSAEvent(start=make_time(m=5), end=make_time(m=6))) subs.append(SSAEvent(start=make_time(m=125), end=make_time(m=126))) subs.append(SSAEvent(start=make_time(m=15), end=make_time(m=16))) subs.styles["style1"] = SSAStyle() subs.styles["style2"] = SSAStyle() ref = "<SSAFile with 3 events and 3 styles, last timestamp 2:06:00>" assert repr(subs) == ref
def build_ref(): subs = SSAFile() subs.info["My Custom Info"] = "Some: Test, String." subs.styles["left"] = SSAStyle(alignment=7, bold=True) subs.styles["topleft"] = SSAStyle(alignment=4) subs.append(SSAEvent(start=0, end=make_time(m=1), text="An, example, subtitle.")) subs.append(SSAEvent(start=0, end=make_time(m=1), type="Comment", text="You can't see this one.")) subs.append(SSAEvent(start=make_time(m=1), end=make_time(m=2), text="Subtitle number\\Ntwo.")) return subs
def save_to_subtitles(results, f): subs = create_ssa_file() for result in results: event = SSAEvent(start=make_time(s=result['start']), end=make_time(s=result['end']), text=f(result)) if 'highlight' in result and result['highlight']: event.style = 'red' subs.append(event) logger.info(f'Processed {len(results)} results to subtitle events') return subs
def test_plaintext(): e = SSAEvent(text=r"First\NSecond\NThird\hline{with hidden text}") assert e.plaintext == "First\nSecond\nThird line" e.plaintext = "My\n Text " assert e.text == r"My\N Text " # SubStation has no way to escape braces, thus this wart text = "My text{with braces}" e.plaintext = text assert e.plaintext != text
def test_simple_read(): text = dedent("""\ 00:00:00:ten--chars 00:01:00:ten--chars-ten-chars """) #calculate endtime from starttime + 500 miliseconds + 67 miliseconds per each character (15 chars per second) ref = SSAFile() ref.append(SSAEvent(start=0, end=make_time(ms=1840), text="ten--chars")) ref.append(SSAEvent(start=make_time(m=1), end=make_time(ms=62510), text="ten--chars-ten-chars")) subs = SSAFile.from_string(text) assert subs.equals(ref)
def test_writer_skips_comment_lines(): subs = SSAFile() subs.append(SSAEvent(start=0, end=10, text="Hello!")) subs.append(SSAEvent(start=0, end=10, text="World!")) subs[0].is_comment = True f = dedent("""\ {0}{0}1000 {0}{10}World! """) assert subs.to_string("microdvd", fps=1000) == f
def test_write_drawing(): subs = SSAFile() subs.append( SSAEvent(start=0, end=10, text=r"{\p1}m 0 0 l 100 0 100 100 0 100{\p0}test")) subs.append(SSAEvent(start=10, end=20, text="Let me tell you.")) f = dedent("""\ {0}{0}1000 {10}{20}Let me tell you. """) assert subs.to_string("microdvd", fps=1000) == f
def test_duration(): e = SSAEvent(start=0, end=10) assert e.duration == 10 e.duration = 20 assert e.start == 0 and e.end == 20 e.duration = 5 assert e.start == 0 and e.end == 5 e.duration = 0 assert e.start == 0 and e.end == 0 with assert_raises(ValueError): e.duration = -20
def test_write_read(): subs = SSAFile() e1 = SSAEvent(text="Hello, world!") e2 = SSAEvent(text="The other subtitle.\\NWith two lines.", style="custom style") s1 = SSAStyle(italic=True, primarycolor=Color(r=255, g=0, b=0, a=0)) subs.append(e1) subs.append(e2) subs.styles["custom style"] = s1 json_text = subs.to_string("json") subs2 = SSAFile.from_string(json_text, "json") assert subs2.equals(subs)
def build(self, **extra): from pysubs2 import SSAFile, SSAEvent, Color # type: ignore[import] millis = lambda td: td / timedelta(milliseconds=1) subs = ( SSAEvent( start=millis(t - self.start), end =millis(t - self.start + timedelta(seconds=length)), text=text.replace('\n', r'\N'), # \N necessary for SSA files ) for t, text, length in self.l ) sf = SSAFile() style = sf.styles['Default'].copy() style.fontsize = 16 # default is 20, bit too much?? style.outlinecolor = Color(0, 0, 0, 50) # semitransparent style.shadow = 0.0 style.outline = 0.1 style.borderstyle = 3 # no idea why 3, but it makes the background apperar in conjunction with outline for k, v in extra.items(): setattr(style, k, v) sf.styles['Default'] = style for s in subs: sf.append(s) return sf.to_string('ass')
def test_read_malformed(): """no line number, no empty line, leading whitespace, bad timestamp format""" text = dedent("""\ 00:00:00.000 ->00:01:00.000 An example subtitle. 0:01:00,00 --> 0:02:00,00 Subtitle number two. """) ref = SSAFile() ref.append(SSAEvent(start=0, end=make_time(m=1), text="An example subtitle.")) ref.append(SSAEvent(start=make_time(m=1), end=make_time(m=2), text="Subtitle number\\Ntwo.")) subs = SSAFile.from_string(text) assert subs.equals(ref)
def test_transform_framerate(): subs = SSAFile() subs.append(SSAEvent(start=0, end=10)) subs.append(SSAEvent(start=1000, end=1010)) with assert_raises(ValueError): subs.transform_framerate(1, 0) with assert_raises(ValueError): subs.transform_framerate(1, -1) with assert_raises(ValueError): subs.transform_framerate(0, 1) with assert_raises(ValueError): subs.transform_framerate(-1, 1) subs.transform_framerate(10, 20) assert subs[0] == SSAEvent(start=0, end=5) assert subs[1] == SSAEvent(start=500, end=505)
def save_to_subtitles(results, formatter): """ Save to subtitle file :param results: Dictionary containing info and start/end times :param formatter: Apply text formating to the subtitle :return: New subtitle file """ subs = SSAFile() for result in results: event = SSAEvent(start=make_time(s=result['start']), end=make_time(s=result['end']), text=formatter(result)) if 'highlight' in result and result['highlight']: event.style = 'red' subs.append(event) logger.info(f'Processed {len(results)} results to subtitle events') return subs
def save_to_srt(results, file_name): """Converts the output of the model to the standard subtitle format .srt""" subs = SSAFile() for result in results: event = SSAEvent(start=make_time(s=result['start']), end=make_time(s=result['end']), text=result['word']) subs.append(event) subs.save(file_name)
def test_simple_read(): text = dedent("""\ 1 00:00:00,000 --> 00:01:00,000 An example subtitle. 2 00:01:00,000 --> 00:02:00,000 Subtitle number two. """) ref = SSAFile() ref.append(SSAEvent(start=0, end=make_time(m=1), text="An example subtitle.")) ref.append(SSAEvent(start=make_time(m=1), end=make_time(m=2), text="Subtitle number\\Ntwo.")) subs = SSAFile.from_string(text) assert subs.equals(ref)
def test_framerate_inference(): fps = 1000.0 has_fps = dedent("""\ {0}{0}1000.0 {10}{20}Hello! """) no_fps = dedent("""\ {10}{20}Hello! """) ignored_fps = dedent("""\ {0}{0}23.976 {10}{20}Hello! """) illegal_fps = dedent("""\ {0}{0}-23.976 {10}{20}Hello! """) subs1 = SSAFile.from_string(has_fps) assert subs1.fps == fps assert len(subs1) == 1 assert subs1[0] == SSAEvent(start=10, end=20, text="Hello!") subs2 = SSAFile.from_string(no_fps, fps=fps) assert subs2.fps == fps assert len(subs2) == 1 assert subs2[0] == SSAEvent(start=10, end=20, text="Hello!") # fps argument takes preference over what the file says, first line is kept subs3 = SSAFile.from_string(ignored_fps, fps=fps) assert subs3.fps == fps assert len(subs3) == 2 assert subs3[0] == SSAEvent(start=0, end=0, text="23.976") assert subs3[1] == SSAEvent(start=10, end=20, text="Hello!") with assert_raises(UnknownFPSError): SSAFile.from_string(no_fps) with assert_raises(ValueError): SSAFile.from_string(illegal_fps)
def combine_subs(first_subs, second_subs, third_subs, fourth_subs, one_only=False): # Only ass files keep styling information properly combined_subs = create_ssa_file() for sub in second_subs: combined_subs.append( SSAEvent(start=sub.start, end=sub.end, text=sub.text, style='bottom')) for sub in first_subs: combined_subs.append( SSAEvent(start=sub.start, end=sub.end, text=f'({sub.text})', style='top')) for sub in third_subs: if sub.style == 'red': combined_subs.append( SSAEvent(start=sub.start, end=sub.end, text=f'[{sub.text}]', style='left_red')) else: combined_subs.append( SSAEvent(start=sub.start, end=sub.end, text=f'[{sub.text}]', style='left')) for sub in fourth_subs: combined_subs.append( SSAEvent(start=sub.start, end=sub.end, text=f'[{sub.text}]', style='right')) combined_subs.sort() if one_only: combined_subs = filter_subs(combined_subs) logger.info(f'Combined subtitles into {len(combined_subs)} subtitles') return combined_subs
def test_insertion_of_wrong_type(): subs = SSAFile() subs.append(SSAEvent()) with assert_raises(TypeError): subs.append(42) with assert_raises(TypeError): subs.insert(42) with assert_raises(TypeError): subs[0] = 42
def test_writer_strips_tags(): subs = SSAFile() subs.append(SSAEvent(start=0, end=10, text="Let me tell you{a secret}.")) f = dedent("""\ {0}{0}1000 {0}{10}Let me tell you. """) assert subs.to_string("microdvd", fps=1000) == f
def test_writer_uses_original_fps(): subs = SSAFile() subs.append(SSAEvent(start=0, end=10, text="Hello!")) subs.fps = 1000 f = dedent("""\ {0}{0}1000 {0}{10}Hello! """) assert subs.to_string("microdvd") == f
def to_subtitles(response): subtitles = SSAFile() subtitles.events = [ SSAEvent( text=result.alternatives[0].transcript, start=duration_to_ms(result.alternatives[0].words[0].start_time), end=duration_to_ms(result.alternatives[0].words[-1].end_time), ) for result in response.results ] return subtitles
def test_extra_whitespace_parsing(): f = dedent("""\ { 0 } { 0 } 1000.0 { 10 }{ 20} Hello! """) subs = SSAFile.from_string(f) assert subs[0] == SSAEvent(start=10, end=20, text="Hello!")
def test_writer_handles_whitespace(): subs = SSAFile() subs.append( SSAEvent(start=0, end=10, text=r"Hello,\hworld!\NSo many\N\nNewlines.")) f = dedent("""\ {0}{0}1000 {0}{10}Hello, world!|So many||Newlines. """) assert subs.to_string("microdvd", fps=1000) == f
def test_simple_write(): subs = SSAFile() e1 = SSAEvent() e1.start = 0 e1.end = 60000 e1.text = "An example subtitle." e2 = SSAEvent() e2.start = 60000 e2.end = 120000 e2.text = "Subtitle number\\Ntwo." e3 = SSAEvent() e3.start = 60000 e3.end = 120000 e3.text = "Invisible subtitle." e3.is_comment = True subs.append(e1) subs.append(e2) subs.append(e3) ref = dedent("""\ 1 00:00:00,000 --> 00:01:00,000 An example subtitle. 2 00:01:00,000 --> 00:02:00,000 Subtitle number two. """) text = subs.to_string("srt") assert text.strip() == ref.strip()
def test_shift(): e = SSAEvent(start=0, end=10) with assert_raises(ValueError): e.shift(frames=5) with assert_raises(ValueError): e.shift(fps=23.976) with assert_raises(ValueError): e.shift(frames=5, fps=-1) e2 = e.copy(); e2.shift(ms=5) assert e2 == SSAEvent(start=5, end=15) e2 = e.copy(); e2.shift(ms=-5) assert e2 == SSAEvent(start=-5, end=5) e2 = e.copy(); e2.shift(frames=1, fps=100.0) assert e2 == SSAEvent(start=10, end=20) e2 = e.copy(); e2.shift(frames=-1, fps=100.0) assert e2 == SSAEvent(start=-10, end=0) e2 = e.copy(); e2.shift(h=1, m=-60, s=2, ms=-2000) assert e2 == e
def test_repr_comment(): ev = SSAEvent(start=make_time(m=1, s=30), end=make_time(m=1, s=35), text="Hello\\Nworld!") ev.is_comment = True ref = "<SSAEvent type=Comment start=0:01:30 end=0:01:35 text='Hello\\Nworld!'>" assert repr(ev) == ref