def test_frames(self): ttml_doc_str = """<?xml version="1.0" encoding="UTF-8"?> <tt xml:lang="en" xmlns="http://www.w3.org/ns/ttml" > <body begin="5s"/> </tt> """ ttml_doc = et.ElementTree(et.fromstring(ttml_doc_str)) config = imsc_config.IMSCWriterConfiguration.parse({ "time_format": "frames", "fps": "30/1" }) xml_from_model = imsc_writer.from_model(imsc_reader.to_model(ttml_doc), config) body_element = xml_from_model.find("tt:body", {"tt": xml_ns.TTML}) self.assertEqual(body_element.get("begin"), "150f") config = imsc_config.IMSCWriterConfiguration.parse({"fps": "30/1"}) xml_from_model = imsc_writer.from_model(imsc_reader.to_model(ttml_doc), config) body_element = xml_from_model.find("tt:body", {"tt": xml_ns.TTML}) self.assertEqual(body_element.get("begin"), "150f") config = imsc_config.IMSCWriterConfiguration.parse( {"time_format": "frames"}) with self.assertRaises(ValueError): imsc_writer.from_model(imsc_reader.to_model(ttml_doc), config)
def test_basic_time_containment_001(self): tree = et.parse( 'src/test/resources/ttml/imsc-tests/imsc1/ttml/timing/BasicTimeContainment001.ttml' ) doc = imsc_reader.to_model(tree) body = doc.get_body() self.assertIsNone(body.get_begin()) self.assertEqual(body.get_end(), Fraction(10)) div = list(body)[0] self.assertIsNone(div.get_begin()) self.assertEqual(div.get_end(), Fraction(10)) p = list(div)[0] self.assertIsNone(p.get_begin()) self.assertIsNone(p.get_end()) span_children = [ v for v in list(p) if len(list(v)[0].get_text().strip()) > 0 ] self.assertIsNone(span_children[0].get_begin()) self.assertEqual(span_children[0].get_end(), Fraction(5)) self.assertIsNone(span_children[1].get_begin()) self.assertEqual(span_children[1].get_end(), Fraction(10))
def test_referential_styling(self): tree = et.parse('src/test/resources/ttml/referential_styling.ttml') doc = imsc_reader.to_model(tree) divs = list(doc.get_body()) self.assertEqual(divs[0].get_style(styles.StyleProperties.Color), styles.NamedColors.green.value) self.assertEqual( divs[0].get_style(styles.StyleProperties.BackgroundColor), styles.NamedColors.blue.value) self.assertEqual(divs[1].get_style(styles.StyleProperties.Color), styles.NamedColors.black.value) self.assertEqual( divs[1].get_style(styles.StyleProperties.BackgroundColor), styles.NamedColors.blue.value) regions = list(doc.iter_regions()) self.assertEqual(regions[0].get_style(styles.StyleProperties.Color), styles.NamedColors.blue.value) self.assertEqual( regions[0].get_style(styles.StyleProperties.BackgroundColor), styles.NamedColors.yellow.value) self.assertEqual(regions[1].get_style(styles.StyleProperties.Color), styles.NamedColors.red.value) self.assertEqual( regions[1].get_style(styles.StyleProperties.BackgroundColor), styles.NamedColors.yellow.value)
def test_basic_timing_007(self): tree = et.parse( 'src/test/resources/ttml/imsc-tests/imsc1/ttml/timing/BasicTiming007.ttml' ) doc = imsc_reader.to_model(tree) body = doc.get_body() self.assertIsNone(body.get_begin()) self.assertEqual(body.get_end(), Fraction(20)) div = list(body)[0] self.assertIsNone(div.get_begin()) self.assertEqual(div.get_end(), Fraction(20)) p = list(div)[0] self.assertEqual(p.get_begin(), 5) self.assertEqual(p.get_end(), 20) span_children = [v for v in list(p) if isinstance(v, model.Span)] self.assertEqual(len(span_children), 1) self.assertEqual(span_children[0].get_begin(), None) self.assertEqual(span_children[0].get_end(), Fraction(10))
def test_lwsp_default(self): tree = et.parse('src/test/resources/ttml/lwsp_default.ttml') doc = imsc_reader.to_model(tree) isd = ISD.from_model(doc, 0) p0 = list(isd.iter_regions())[0][0][0][0] spans = list(p0) self.assertEqual(len(spans), 3) self.assertEqual(spans[0][0].get_text(), "hello ") self.assertEqual(spans[1][0].get_text(), "my name") self.assertEqual(spans[2][0].get_text(), " is Mathilda") p1 = list(isd.iter_regions())[0][0][0][1] spans = list(p1) self.assertEqual(len(spans), 4) self.assertEqual(spans[0][0].get_text(), "bonjour") self.assertEqual(spans[1][0].get_text(), " mon nom") self.assertIsInstance(spans[2], model.Br) self.assertEqual(spans[3][0].get_text(), "est")
def test_imsc_1_1_test_suite(self): for root, _subdirs, files in os.walk( "src/test/resources/ttml/imsc-tests/imsc1_1/ttml"): for filename in files: (name, ext) = os.path.splitext(filename) if ext == ".ttml": with self.subTest(name): tree = et.parse(os.path.join(root, filename)) self.assertIsNotNone(imsc_reader.to_model(tree))
def test_frame_rate(self): tree = et.parse( 'src/test/resources/ttml/imsc-tests/imsc1/ttml/timing/TimeExpressions001.ttml' ) doc = imsc_reader.to_model(tree) # <p begin="0s" end="24f">24f = 1.001s</p> p = list(list(doc.get_body())[0])[3] self.assertEqual(p.get_end(), Fraction(4394201, 1000))
def test_clock_time(self): ttml_doc_str = """<?xml version="1.0" encoding="UTF-8"?> <tt xml:lang="en" xmlns="http://www.w3.org/ns/ttml" > <body begin="2.3s"/> </tt> """ ttml_doc = et.ElementTree(et.fromstring(ttml_doc_str)) config = imsc_config.IMSCWriterConfiguration.parse( {"time_format": "clock_time"}) xml_from_model = imsc_writer.from_model(imsc_reader.to_model(ttml_doc), config) body_element = xml_from_model.find("tt:body", {"tt": xml_ns.TTML}) self.assertEqual(body_element.get("begin"), "00:00:02.300") xml_from_model = imsc_writer.from_model(imsc_reader.to_model(ttml_doc)) body_element = xml_from_model.find("tt:body", {"tt": xml_ns.TTML}) self.assertEqual(body_element.get("begin"), "00:00:02.300")
def test_imsc_1_test_suite(self): for root, _subdirs, files in os.walk( "src/test/resources/ttml/imsc-tests/imsc1/ttml"): for filename in files: (name, ext) = os.path.splitext(filename) if ext == ".ttml": with self.subTest(name): tree = et.parse(os.path.join(root, filename)) doc = imsc_reader.to_model(tree) srt_file = srt_writer.from_model(doc) srt_reader.to_model(io.StringIO(srt_file))
def test_initial(self): tree = et.parse( 'src/test/resources/ttml/imsc-tests/imsc1_1/ttml/initial/initial002.ttml' ) doc = imsc_reader.to_model(tree) self.assertEqual(doc.get_initial_value(styles.StyleProperties.Color), styles.NamedColors.green.value) self.assertEqual( doc.get_initial_value(styles.StyleProperties.FontStyle), styles.FontStyleType.italic)
def test_imsc_1_test_suite(self): for root, _subdirs, files in os.walk( "src/test/resources/ttml/imsc-tests/imsc1/ttml"): for filename in files: (name, ext) = os.path.splitext(filename) if ext == ".ttml": with self.subTest(name), self.assertLogs() as logs: logging.getLogger().info( "*****dummy*****") # dummy log tree = et.parse(os.path.join(root, filename)) self.assertIsNotNone(imsc_reader.to_model(tree)) if len(logs.output) > 1: self.fail(logs.output)
def test_animation_001(self): file_to_parse = "src/test/resources/ttml/imsc-tests/imsc1/ttml/animation/Animation001.ttml" tree = et.parse(file_to_parse) # create the model test_model = imsc_reader.to_model(tree) # convert from a model to a ttml document tree_from_model = imsc_writer.from_model(test_model) # write the document out to a file self.write_pretty_xml(tree_from_model, 'build/out.ttml')
def test_imsc_1_2_test_suite(self): for root, _subdirs, files in os.walk( "src/test/resources/ttml/imsc-tests/imsc1_2/ttml"): for filename in files: (name, ext) = os.path.splitext(filename) if ext == ".ttml": with self.subTest(name): path = os.path.join(root, filename) tree = et.parse(path) test_model = imsc_reader.to_model(tree) srt_from_model = srt_writer.from_model(test_model) self._check_output_srt(test_model, srt_from_model, path)
def test_display_none_handling(self): xml_doc = et.parse("src/test/resources/ttml/imsc-tests/imsc1/ttml/timing/MediaParTiming002.ttml") doc = imsc_reader.to_model(xml_doc) isd = ISD.from_model(doc, 0) regions = list(isd.iter_regions()) # single default region self.assertEqual(len(regions), 1) # no content self.assertEqual(len(regions[0]), 0)
def test_empty_isds(self): tree = et.parse( 'src/test/resources/ttml/imsc-tests/imsc1/ttml/timing/BasicTiming010.ttml' ) doc = imsc_reader.to_model(tree) srt_from_model = srt_writer.from_model(doc) self.assertEqual( srt_from_model, """1 00:00:10,000 --> 00:00:24,400 This text must appear at 10 seconds and disappear at 24.4 seconds 2 00:00:25,000 --> 00:00:35,000 This text must appear at 25 seconds and disappear at 35 seconds """)
def test_reader_tt_element_not_root_element(self): xml_str = """<?xml version="1.0" encoding="UTF-8"?> <not_tt xml:lang="en" xmlns="http://www.w3.org/ns/ttml" xmlns:ttm="http://www.w3.org/ns/ttml#metadata" xmlns:tts="http://www.w3.org/ns/ttml#styling" xmlns:ttp="http://www.w3.org/ns/ttml#parameter" xmlns:ittp="http://www.w3.org/ns/ttml/profile/imsc1#parameter" ittp:activeArea="50% 50% 80% 80%" tts:extent="640px 480px" ttp:profile="http://www.w3.org/ns/ttml/profile/imsc1/text"> </not_tt>""" tt_not_root = et.ElementTree(et.fromstring(xml_str)) self.assertIsNone(imsc_reader.to_model(tt_not_root))
def test_imsc_1_test_suite(self): if not os.path.exists('build/imsc1'): os.makedirs('build/imsc1') for root, _subdirs, files in os.walk( "src/test/resources/ttml/imsc-tests/imsc1/ttml"): for filename in files: (name, ext) = os.path.splitext(filename) if ext == ".ttml": with self.subTest(name), self.assertLogs() as logs: logging.getLogger().info( "*****dummy*****") # dummy log tree = et.parse(os.path.join(root, filename)) test_model = imsc_reader.to_model(tree) tree_from_model = imsc_writer.from_model(test_model) self.write_pretty_xml(tree_from_model, f'build/imsc1/{name}.ttml') if len(logs.output) > 1: self.fail(logs.output)
def test_lwsp_preserve(self): tree = et.parse('src/test/resources/ttml/lwsp_preserve.ttml') doc = imsc_reader.to_model(tree) isd = ISD.from_model(doc, 0) p0 = list(isd.iter_regions())[0][0][0][0] spans = list(p0) self.assertEqual(len(spans), 3) self.assertEqual(spans[0][0].get_text(), "hello ") self.assertEqual(spans[1][0].get_text(), " my \nname ") self.assertEqual(spans[2][0].get_text(), "is Mathilda")
def test_fps(self): ttml_doc_str = """<?xml version="1.0" encoding="UTF-8"?> <tt xml:lang="en" xmlns="http://www.w3.org/ns/ttml" > <body begin="5s"/> </tt> """ ttml_doc = et.ElementTree(et.fromstring(ttml_doc_str)) config = imsc_config.IMSCWriterConfiguration( time_format=imsc_config.TimeExpressionEnum.frames, fps=Fraction(30, 1)) xml_from_model = imsc_writer.from_model(imsc_reader.to_model(ttml_doc), config) body_element = xml_from_model.find("tt:body", {"tt": xml_ns.TTML}) self.assertEqual(body_element.get("begin"), "150f")
def test_imsc_1_test_suite(self): manifest = [] base_path = "build/imsc1" for root, _subdirs, files in os.walk( "src/test/resources/ttml/imsc-tests/imsc1/ttml"): for filename in files: (name, ext) = os.path.splitext(filename) if ext == ".ttml": with self.subTest(name), self.assertLogs() as logs: logging.getLogger().info( "*****dummy*****") # dummy log tree = et.parse(os.path.join(root, filename)) test_model = imsc_reader.to_model(tree) tree_from_model = imsc_writer.from_model(test_model) test_dir_relative_path = os.path.basename(root) test_relative_path = os.path.join( test_dir_relative_path, filename) os.makedirs(os.path.join(base_path, "ttml", test_dir_relative_path), exist_ok=True) with open( os.path.join(base_path, "ttml", test_relative_path), "wb") as f: f.write( et.tostring(tree_from_model.getroot(), 'utf-8')) manifest.append({ "path": str(test_relative_path).replace('\\', '/') }) if len(logs.output) > 1: self.fail(logs.output) with open(os.path.join(base_path, "tests.json"), "w", encoding="utf8") as fp: json.dump(manifest, fp)
def test_position(self): ttml_doc_str = """<?xml version="1.0" encoding="UTF-8"?> <tt xml:lang="en-US" xmlns="http://www.w3.org/ns/ttml" xmlns:tts="http://www.w3.org/ns/ttml#styling" xmlns:ttp="http://www.w3.org/ns/ttml#parameter" xmlns:ttm="http://www.w3.org/ns/ttml#metadata" ttp:frameRate="24" ttp:frameRateMultiplier="1000 1001" ttp:profile="http://www.w3.org/ns/ttml/profile/imsc1/text" ttp:timeBase="media"> <head> <styling> <style xml:id="style.center" tts:fontFamily="Arial" tts:fontSize="100%" tts:fontStyle="normal" tts:fontWeight="normal" tts:backgroundColor="transparent" tts:color="white" tts:textAlign="center"/> </styling> <layout> <region xml:id="region.after" tts:displayAlign="after" tts:backgroundColor="transparent" tts:origin="10% 10%" tts:extent="80% 80%"/> <region xml:id="region.before" tts:displayAlign="before" tts:backgroundColor="transparent" tts:origin="10% 10%" tts:extent="80% 80%"/> </layout> </head> <body> <div> <p style="style.center" region="region.after" begin="00:00:03:12" end="00:00:12:00">Only one or two short samples are needed<br/>to make sure the conversion basically works</p> <p style="style.center" region="region.before" begin="00:00:14:09" end="00:00:25:17">Cool, got it, will do it by end of next week.</p> </div> </body> </tt>""" expected_vtt = """WEBVTT 1 00:00:03.501 --> 00:00:12.000 line:90%,end Only one or two short samples are needed to make sure the conversion basically works 2 00:00:14.375 --> 00:00:25.709 line:10%,start Cool, got it, will do it by end of next week. """ model = imsc_reader.to_model( et.ElementTree(et.fromstring(ttml_doc_str))) config = VTTWriterConfiguration() config.line_position = True vtt_from_model = vtt_writer.from_model(model, config) self.assertEqual(expected_vtt, vtt_from_model) config = VTTWriterConfiguration.parse( json.loads('{"line_position":true}')) vtt_from_model = vtt_writer.from_model(model, config) self.assertEqual(expected_vtt, vtt_from_model)
def test_basic_time_containment_002(self): tree = et.parse( 'src/test/resources/ttml/imsc-tests/imsc1/ttml/timing/BasicTimeContainment002.ttml' ) doc = imsc_reader.to_model(tree) body = doc.get_body() self.assertIsNone(body.get_begin()) self.assertEqual(body.get_end(), Fraction(20)) div = list(body)[0] self.assertIsNone(div.get_begin()) self.assertEqual(div.get_end(), Fraction(20)) p_children = [v for v in list(div) if isinstance(v, model.P)] self.assertIsNone(p_children[0].get_begin()) self.assertEqual(p_children[0].get_end(), Fraction(10)) self.assertEqual(p_children[1].get_begin(), Fraction(10)) self.assertEqual(p_children[1].get_end(), Fraction(20))
def test_body_only(self): tree = et.parse('src/test/resources/ttml/body_only.ttml') imsc_reader.to_model(tree)
def convert(args): '''Process input and output through the reader, converter, and writer''' inputfile = args.input outputfile = args.output # Note - Loading config data from a file takes priority over # data passed in as a json string json_config_data = None if args.config is not None: json_config_data = json.loads(args.config) if args.config_file is not None: with open(args.config_file) as json_file: json_config_data = json.load(json_file) general_config = read_config_from_json(GeneralConfiguration, json_config_data) if general_config is not None: if general_config.progress_bar is not None: progress.display_progress_bar = general_config.progress_bar if general_config.log_level is not None: LOGGER.setLevel(general_config.log_level) LOGGER.info("Input file is %s", inputfile) LOGGER.info("Output file is %s", outputfile) _input_filename, input_file_extension = os.path.splitext(inputfile) _output_filename, output_file_extension = os.path.splitext(outputfile) reader_type = FileTypes.get_file_type(args.itype, input_file_extension) writer_type = FileTypes.get_file_type(args.otype, output_file_extension) if reader_type is FileTypes.TTML: # # Parse the xml input file into an ElementTree # tree = et.parse(inputfile) # # Pass the parsed xml to the reader # model = imsc_reader.to_model(tree, progress_callback_read) elif reader_type is FileTypes.SCC: file_as_str = Path(inputfile).read_text() # # Read the config # reader_config = read_config_from_json(SccReaderConfiguration, json_config_data) # # Pass the parsed xml to the reader # model = scc_reader.to_model(file_as_str, reader_config, progress_callback_read) elif reader_type is FileTypes.STL: # # Read the config # reader_config = read_config_from_json(STLReaderConfiguration, json_config_data) # # Open the file and pass it to the reader # with open(inputfile, "rb") as f: model = stl_reader.to_model(f, reader_config, progress_callback_read) elif reader_type is FileTypes.SRT: # # Open the file and pass it to the reader # with open(inputfile, "r", encoding="utf-8") as f: model = srt_reader.to_model(f, None, progress_callback_read) else: if args.itype is not None: exit_str = f'Input type {args.itype} is not supported' else: exit_str = f'Input file {args.input} is not supported' LOGGER.error(exit_str) sys.exit(exit_str) if writer_type is FileTypes.TTML: # # Read the config # writer_config = read_config_from_json(IMSCWriterConfiguration, json_config_data) # # Construct and configure the writer # tree_from_model = imsc_writer.from_model(model, writer_config, progress_callback_write) # # Write out the converted file # tree_from_model.write(outputfile, encoding="utf-8") elif writer_type is FileTypes.SRT: # # Read the config # writer_config = read_config_from_json(ISDConfiguration, json_config_data) # # Construct and configure the writer # srt_document = srt_writer.from_model(model, writer_config, progress_callback_write) # # Write out the converted file # with open(outputfile, "w", encoding="utf-8") as srt_file: srt_file.write(srt_document) elif writer_type is FileTypes.VTT: # # Read the config # writer_config = read_config_from_json(VTTWriterConfiguration, json_config_data) # # Construct and configure the writer # vtt_document = vtt_writer.from_model(model, writer_config, progress_callback_write) # # Write out the converted file # with open(outputfile, "w", encoding="utf-8") as vtt_file: vtt_file.write(vtt_document) else: if args.otype is not None: exit_str = f'Output type {args.otype} is not supported' else: exit_str = f'Output file is {args.output} is not supported' LOGGER.error(exit_str) sys.exit(exit_str)
def convert(args): '''Process input and output through the reader, converter, and writer''' inputfile = args.input outputfile = args.output LOGGER.info("Input file is %s", inputfile) LOGGER.info("Output file is %s", outputfile) _input_filename, input_file_extension = os.path.splitext(inputfile) _output_filename, output_file_extension = os.path.splitext(outputfile) reader_type = FileTypes.get_file_type(args.itype, input_file_extension) writer_type = FileTypes.get_file_type(args.otype, output_file_extension) if reader_type is FileTypes.TTML: # # Parse the xml input file into an ElementTree # tree = et.parse(inputfile) # # Pass the parsed xml to the reader # model = imsc_reader.to_model(tree) elif reader_type is FileTypes.SCC: file_as_str = Path(inputfile).read_text() # # Pass the parsed xml to the reader # model = scc_reader.to_model(file_as_str) else: if args.itype is not None: exit_str = f'Input type {args.itype} is not supported' else: exit_str = f'Input file is {args.input} is not supported' LOGGER.error(exit_str) sys.exit(exit_str) if writer_type is FileTypes.TTML: # # Construct and configure the writer # tree_from_model = imsc_writer.from_model(model) # # Write out the converted file # tree_from_model.write(outputfile) elif writer_type is FileTypes.SRT: # # Construct and configure the writer # srt_document = srt_writer.from_model(model) # # Write out the converted file # with open(outputfile, "w") as srt_file: srt_file.write(srt_document) else: if args.otype is not None: exit_str = f'Output type {args.otype} is not supported' else: exit_str = f'Output file is {args.output} is not supported' LOGGER.error(exit_str) sys.exit(exit_str)