1import re 2from .formatbase import FormatBase 3from .ssaevent import SSAEvent 4from .ssastyle import SSAStyle 5from .substation import parse_tags 6from .time import ms_to_times, make_time, tmptimestamp_to_ms 7 8#: Pattern that matches TMP timestamp 9TMPTIMESTAMP = re.compile(r"(\d{1,2}):(\d{2}):(\d{2})") 10#: Pattern that matches TMP line 11TMP_LINE = re.compile(r"(\d{1,2}:\d{2}:\d{2}):(.+)") 12 13#: Largest timestamp allowed in Tmp, ie. 99:59:59. 14MAX_REPRESENTABLE_TIME = make_time(h=100) - 1 15 16 17def ms_to_timestamp(ms): 18 """Convert ms to 'HH:MM:SS'""" 19 # XXX throw on overflow/underflow? 20 if ms < 0: ms = 0 21 if ms > MAX_REPRESENTABLE_TIME: ms = MAX_REPRESENTABLE_TIME 22 h, m, s, ms = ms_to_times(ms) 23 return "%02d:%02d:%02d" % (h, m, s) 24 25 26class TmpFormat(FormatBase): 27 """TMP subtitle format implementation""" 28 @classmethod 29 def guess_format(cls, text): 30 """See :meth:`pysubs2.formats.FormatBase.guess_format()`""" 31 if "[Script Info]" in text or "[V4+ Styles]" in text: 32 # disambiguation vs. SSA/ASS 33 return None 34 35 for line in text.splitlines(): 36 if TMP_LINE.match(line) and len(TMP_LINE.findall(line)) == 1: 37 return "tmp" 38 39 @classmethod 40 def from_file(cls, subs, fp, format_, **kwargs): 41 """See :meth:`pysubs2.formats.FormatBase.from_file()`""" 42 events = [] 43 44 def prepare_text(text): 45 text = text.replace("|", r"\N") # convert newlines 46 text = re.sub(r"< *u *>", "{\\\\u1}", text) # not r" for Python 2.7 compat, triggers unicodeescape 47 text = re.sub(r"< */? *[a-zA-Z][^>]*>", "", text) # strip other HTML tags 48 return text 49 50 for line in fp: 51 match = TMP_LINE.match(line) 52 if not match: 53 continue 54 55 start, text = match.groups() 56 start = tmptimestamp_to_ms(TMPTIMESTAMP.match(start).groups()) 57 58 # Unfortunately, end timestamp is not given; try to estimate something reasonable: 59 # start + 500 ms + 67 ms/character (15 chars per second) 60 end_guess = start + 500 + (len(line) * 67) 61 62 event = SSAEvent(start=start, end=end_guess, text=prepare_text(text)) 63 events.append(event) 64 65 # correct any overlapping subtitles created by end_guess 66 for i in range(len(events) - 1): 67 events[i].end = min(events[i].end, events[i+1].start) 68 69 subs.events = events 70 71 @classmethod 72 def to_file(cls, subs, fp, format_, apply_styles=True, **kwargs): 73 """ 74 See :meth:`pysubs2.formats.FormatBase.to_file()` 75 76 Italic, underline and strikeout styling is supported. 77 78 Keyword args: 79 apply_styles: If False, do not write any styling. 80 81 """ 82 def prepare_text(text, style): 83 body = [] 84 skip = False 85 for fragment, sty in parse_tags(text, style, subs.styles): 86 fragment = fragment.replace(r"\h", " ") 87 fragment = fragment.replace(r"\n", "\n") 88 fragment = fragment.replace(r"\N", "\n") 89 if apply_styles: 90 if sty.italic: fragment = "<i>%s</i>" % fragment 91 if sty.underline: fragment = "<u>%s</u>" % fragment 92 if sty.strikeout: fragment = "<s>%s</s>" % fragment 93 if sty.drawing: skip = True 94 body.append(fragment) 95 96 if skip: 97 return "" 98 else: 99 return re.sub("\n+", "\n", "".join(body).strip()) 100 101 visible_lines = (line for line in subs if not line.is_comment) 102 103 for line in visible_lines: 104 start = ms_to_timestamp(line.start) 105 text = prepare_text(line.text, subs.styles.get(line.style, SSAStyle.DEFAULT_STYLE)) 106 107 print(start + ":" + text, end="\n", file=fp) 108