" if s[1] in cursive_ids else u"")
text = has_cursive[-1].join(text.split(s[0], 1))
return text, has_cursive
def xml_cleanup_spans_end(span_end_re, text, has_cursive):
span_end_tags = re.findall(span_end_re, text)
for s, cursive in zip(span_end_tags, has_cursive):
cursive = u"" if cursive else u""
text = cursive.join(text.split(s, 1))
return text
def to_srt(text, extension):
if extension.lower() == ".xml":
return xml_to_srt(text)
if extension.lower() == ".vtt":
return vtt_to_srt(text)
def convert_vtt_time(line):
times = line.replace(".", ",").split(" --> ")
if len(times[0]) == 9:
times = ["00:" + t for t in times]
return "{} --> {}".format(times[0], times[1].split(" ")[0])
def vtt_to_srt(text):
if not text.startswith(u"\ufeffWEBVTT") and not text.startswith(u"WEBVTT"):
raise Exception(".vtt format must start with WEBVTT, wrong file?")
styles = get_vtt_styles(text)
style_tag_re = re.compile(u'(.*)')
lines = []
current_sub_line = []
for line in text.split("\n"):
if current_sub_line:
if line:
style_tag = re.search(style_tag_re, line)
if style_tag:
line = style_tag.group(2) # line is just the text part
color = styles.get(style_tag.group(1).split(".")[0])
if color:
line = u"{}".format(
color, line)
current_sub_line.append(line)
else:
lines.append("\n".join(current_sub_line) + "\n\n")
current_sub_line = []
elif " --> " in line:
current_sub_line = [convert_vtt_time(line)]
if current_sub_line:
lines.append("\n".join(current_sub_line))
return "".join((u"{}\n{}".format(i, l) for i, l in enumerate(lines, 1)))
def get_vtt_styles(text): # just using it for color ATM
styles = {}
lines = text.split("\n")
n = 0
style_name_re = re.compile(u'::cue\(\.(.*)\).*')
color_re = re.compile(u'.*color: (\#.*);')
while n < len(lines): # not efficient to go through all text, but it's ok
style_name = re.search(style_name_re, lines[n])
if style_name and style_name.groups():
name = style_name.group(1)
color = re.search(color_re, lines[n + 1])
if color and color.groups():
styles[name] = color.group(1)
n += 1
return styles
def xml_to_srt(text):
def append_subs(start, end, prev_content, format_time):
subs.append({
"start_time": convert_time(start) if format_time else start,
"end_time": convert_time(end) if format_time else end,
"content": u"\n".join(prev_content),
})
display_align_before = xml_id_display_align_before(text)
begin_re = re.compile(u"(?=.*begin\=)\s*)")
sub_lines = (l for l in text.split("\n") if re.search(begin_re, l))
subs = []
prev_time = {"start": 0, "end": 0}
prev_content = []
start = end = ''
start_re = re.compile(u'begin\="([0-9:\.]*)')
end_re = re.compile(u'end\="([0-9:\.]*)')
content_re = re.compile(u'\">(.*)
')
# some span tags are used for italics, we'll replace them by and ,
# which is the standard for .srt files. We ignore all other uses.
cursive_ids = xml_get_cursive_style_ids(text)
span_id_re = re.compile(u'()+')
span_end_re = re.compile(u'()+')
br_re = re.compile(u'(
)+')
fmt_t = True
for s in sub_lines:
s, has_cursive = xml_cleanup_spans_start(
span_id_re, cursive_ids, s)
string_region_re = r'(.*)
'
s = re.sub(string_region_re, r'{\\an8}\2
', s)
content = re.search(content_re, s).group(1)
br_tags = re.search(br_re, content)
if br_tags:
content = u"\n".join(content.split(br_tags.group()))
content = xml_cleanup_spans_end(
span_end_re, content, has_cursive)
prev_start = prev_time["start"]
start = re.search(start_re, s).group(1)
end = re.search(end_re, s).group(1)
if len(start.split(":")) > 1:
fmt_t = False
start = start.replace(".", ",")
end = end.replace(".", ",")
if (prev_start == start and prev_time["end"] == end) or not prev_start:
# Fix for multiple lines starting at the same time
prev_time = {"start": start, "end": end}
prev_content.append(content)
continue
append_subs(prev_time["start"], prev_time["end"], prev_content, fmt_t)
prev_time = {"start": start, "end": end}
prev_content = [content]
append_subs(start, end, prev_content, fmt_t)
lines = (u"{}\n{} --> {}\n{}\n".format(
s + 1, subs[s]["start_time"], subs[s]["end_time"], subs[s]["content"])
for s in range(len(subs)))
return u"\n".join(lines)
def main():
directory = "."
help_text = u"path to the {} directory (defaults to current directory)"
parser = argparse.ArgumentParser()
parser.add_argument("-i", "--input", type=str, default=directory,
help=help_text.format("input", directory))
parser.add_argument("-o", "--output", type=str, default=directory,
help=help_text.format("output", directory))
a = parser.parse_args()
filenames = [fn for fn in os.listdir(a.input)
if fn[-4:].lower() in SUPPORTED_EXTENSIONS]
for fn in filenames:
with codecs.open(u"{}/{}".format(a.input, fn), 'rb', "utf-8") as f:
text = f.read()
with codecs.open(u"{}/{}.srt".format(a.output, fn), 'wb', "utf-8") as f:
f.write(to_srt(text, fn[-4:]))
if __name__ == '__main__':
main()