-
Notifications
You must be signed in to change notification settings - Fork 0
/
insert-comments.py
executable file
·143 lines (107 loc) · 3.93 KB
/
insert-comments.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#!/usr/bin/env python3
# license: the Unlicense, see UNLICENSE file
import argparse
import json
import re
def pad_message(message, align, width):
return '{{message:{align}{width}s}}'.format(**locals()).format(**locals())
def merge_iterables(*iterables, key=lambda x: x):
def keyfunc(kv):
return key(kv[1])
def consume(iterator):
try:
value = next(iterator)
except StopIteration:
del iterables[iterator]
else:
iterables[iterator] = value
iterables = {iter(it): None for it in iterables}
for iterator in list(iterables):
consume(iterator)
while iterables:
iterator, value = min(iterables.items(), key=keyfunc)
yield value
consume(iterator)
def inserts_to_records(fd, y, width):
for line in fd:
line = line.strip()
m = re.fullmatch(
r'(?P<start>\d+(?:\.\d*)?)'
r'(?:\s*-\s*(?P<end>\d+(?:\.\d*)?)|\s*:\s*(?P<duration>\d+(?:\.\d*)?))?'
r'(?:\s+(?P<style>[r<^>]+\s+)?(?P<message>.*))?',
line,
)
if not m:
raise NotImplementedError(f"oops: {line!r}")
start = float(m['start'])
end = None
if m['end']:
end = float(m['end'])
duration = None
if m['duration']:
duration = float(m['duration'])
end = start + duration
message = m['message'] or ''
style = m['style'] or ''
align = (re.search('[<^>]', style) or ['^'])[0]
rev_start = rev_end = ''
if 'r' in style:
rev_start = '\u001b[7m'
rev_end = '\u001b[m'
records = []
padded = pad_message(message, align, width)
records.append([start, 'o', f"\u001b[s\u001b[{y};1H{rev_start}{padded}{rev_end}\u001b[u"])
if end:
padded = pad_message('', '^', width)
records.append([end, 'o', f"\u001b[s\u001b[{y};1H{padded}\u001b[u"])
for data in records:
line = json.dumps(data) + '\n'
yield data, line
def parse_srt_time(strtime):
m = list(map(int, re.search(r'(\d+):(\d+):(\d+),(\d+)', strtime).groups()))
return m[0] * 3600 + m[1] * 60 + m[2] + m[3] / 1000
def srt_to_records(fd, y, width):
while True:
if not fd.readline(): # EOF
break
timestamps = fd.readline()
message = ''
for line in fd:
if not line.strip():
break
message += line.strip()
start, end = map(parse_srt_time, timestamps.split(' --> '))
records = []
padded = pad_message(message, '^', width)
records.append([start, 'o', f"\u001b[s\u001b[{y};1H{padded}\u001b[u"])
padded = pad_message('', '^', width)
records.append([end, 'o', f"\u001b[s\u001b[{y};1H{padded}\u001b[u"])
for data in records:
line = json.dumps(data) + '\n'
yield data, line
def rec_to_records(fd):
for line in fd:
data = json.loads(line)
yield data, line
parser = argparse.ArgumentParser()
parser.add_argument('rec_file', type=argparse.FileType('r'))
parser.add_argument('inserts_file', type=argparse.FileType('r'))
parser.add_argument('output', type=argparse.FileType('w'))
parser.add_argument('--top', action='store_true', default=False)
args = parser.parse_args()
with args.rec_file, args.inserts_file:
with args.output:
line = args.rec_file.readline()
data = json.loads(line)
args.output.write(line)
if args.top:
y = 1
else:
y = data['height']
if args.inserts_file.name.endswith('.srt'):
subtitles_it = srt_to_records(args.inserts_file, y, data['width'])
else:
subtitles_it = inserts_to_records(args.inserts_file, y, data['width'])
it = merge_iterables(rec_to_records(args.rec_file), subtitles_it)
for data, line in it:
args.output.write(line)