-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtransltool.py
179 lines (147 loc) · 6.41 KB
/
transltool.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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
import argparse
import json
import os
import shutil
import sys
def dumpDatabase(database_path, output_path, indented):
# open and parse database JSON
with open(database_path, encoding="utf8") as f:
data = json.load(f)
# delete old dump directory
shutil.rmtree(output_path, ignore_errors=True)
# dump conversations
for conversation in data["conversations"]:
# generate human-readable filename
filename = ''.join(a for a in conversation["title"].title() if a.isalnum())
filename = filename[0].lower() + filename[1:] + ".transl"
filename = conversation["type"] + "/" + filename
# dump dialogue-less orbs into one file
append = False
if conversation["type"] == "orb" and len(conversation["entries"]) == 0:
filename = "orb/orbs.transl"
append = True
# dump to file
dumpConversation(conversation, os.path.join(output_path, filename), append, indented)
# dump misc
for category in data["miscellaneous"]:
# get filename and output path
filename = category + ".transl"
filepath = os.path.join(output_path, filename)
# write to file
entries = data["miscellaneous"][category]
with open(filepath, "a", encoding="utf8") as f:
for key in entries:
f.write("{}: # {}\n".format(key, entries[key].replace("\n", "\\\n#")))
def buildConversationTree(conversation):
# resolve entries dictionary
entries = conversation["entries"]
# add additional fields to entries
for entry in entries.values():
entry["in_reply_to"] = []
entry["assigned_number"] = -1
entry["indent"] = 0
entry["visited"] = False
# build reply graph
for entry_id, entry in entries.items():
for lead in entry["leadsTo"]:
# skip exit leads
if lead in entries:
entries[lead]["in_reply_to"] += [entry_id]
# ordered entries to be printed
output = []
# add roots and their branches
root_number = 0
for root in conversation["roots"]:
root_number = buildBranch(root, root_number, 0, entries, output)
# resolve reply ids
for entry in output:
resolved_ids = sorted([entries[id]["assigned_number"] for id in entry["in_reply_to"]])
resolved_ids = [id for id in resolved_ids if id < entry["assigned_number"]]
resolved_ids = [str(id) for id in resolved_ids]
resolved_ids = ", ".join(resolved_ids)
entry["in_reply_to_resolved"] = resolved_ids or None
return output
def buildBranch(root, root_number, indent, entries, output):
# add current node to output if it's a top root
if indent == 0:
entries[root]["assigned_number"] = root_number
entries[root]["indent"] = indent
entries[root]["visited"] = True
output += [entries[root]]
indent += 1
root_number += 1
# add children to output
added_children = []
for lead in entries[root]["leadsTo"]:
# skip previously visited nodes and exit nodes
if lead not in entries or entries[lead]["visited"]:
continue
# register child
entries[lead]["assigned_number"] = root_number
entries[lead]["indent"] = indent
entries[lead]["visited"] = True
output += [entries[lead]]
added_children += [lead]
root_number += 1
# add grandchildren
for child in added_children:
root_number = buildBranch(child, root_number, indent + 1, entries, output)
# return next available number
return root_number
def dumpConversation(conversation, path, append, indented):
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, "a" if append else "w", encoding="utf8") as f:
# dump metadata
f.write("# CONVERSATION METADATA\n")
for key in conversation["metadata"]:
f.write("{}: # {}\n".format(key, conversation["metadata"][key].replace("\n", "\\\n#")))
# skip entries if there are none
if len(conversation["entries"]) == 0:
return
# dump conversation entries
f.write("\n# CONVERSATION ENTRIES\n")
# construct conversation tree
ordered_entries = buildConversationTree(conversation)
# print ordered entries
for entry in ordered_entries:
indent = "\t" * entry["indent"]
number = entry["assigned_number"]
actor = entry["actor"].upper()
reply_info = ""
# format reply info
reply_format = " (to {})" if indented else ", in reply to {}"
if entry["in_reply_to_resolved"] is not None:
reply_info = reply_format.format(entry["in_reply_to_resolved"])
# format entry
for fieldid, fieldtext in entry["fields"].items():
fieldtext = fieldtext.replace("\n", "\\\n#")
if indented:
f.write("{}: # ({})\t{}{}: {}{}\n".format(fieldid, number,
indent, actor, fieldtext, reply_info))
else:
f.write("{}: # ({}{}) {}: {}\n".format(fieldid, number,
reply_info, actor, fieldtext))
def concatFiles():
pass
# define command line arguments
arg_parser = argparse.ArgumentParser(description="Transltool - resource \
management utility for Disco Translator 2")
actiongroup = arg_parser.add_mutually_exclusive_group(required=True)
actiongroup.add_argument("--dump", type=str, metavar="PATH",
help="split a JSON database into a .transl file hierarchy")
actiongroup.add_argument("--concat", type=str, metavar="PATH",
help="concatenate a .transl file hierarchy into a single file")
arg_parser.add_argument("--indented", default=False, action='store_true',
help="use an indented format when dumping dialogues")
arg_parser.add_argument("output", type=str, metavar="OUTPUT_PATH", default=".",
help="output path for the program")
# show help if there are no arguments
if len(sys.argv) < 2:
arg_parser.print_help()
sys.exit(1)
# perform the requested action
args = arg_parser.parse_args()
if args.dump:
dumpDatabase(args.dump, args.output, args.indented)
elif args.concat:
concatFiles(args.concat, args.output)