Skip to content

Instantly share code, notes, and snippets.

@WorldMaker
Created March 31, 2010 23:27
Show Gist options
  • Save WorldMaker/351086 to your computer and use it in GitHub Desktop.
Save WorldMaker/351086 to your computer and use it in GitHub Desktop.
Celtx to Ren'Py Script
#!/usr/bin/python
# Celtx HTML Film Script to Ren'Py Script Tool (Based on KeyLimePie tools)
# Copyright 2010 Max Battcher. Some Rights Reserved.
# Licensed for use under the Ms-PL.
from BeautifulSoup import BeautifulSoup, Tag
import logging
def tagtext(contents):
def txt(thing):
if isinstance(thing, Tag):
return thing.string or ''
else:
return unicode(thing) or ''
return ''.join(txt(thing) for thing in contents).strip()
class ScriptConverter(object):
def __init__(self, tab=' '):
self.tab = tab
self.indentlvl = 0
self.outf = None
self.curchar = None
self.curcond = None
self.inmenu = False
self.curchoice = None
def writeln(self, text, offset=0):
for line in text.split('\n'):
self.outf.write("%s%s\n" % (self.tab * (self.indentlvl + offset),
line.strip(),
))
def default_p(self, cls, text):
logging.warn("Unrecognized class '%s'" % cls)
def convert(self, script, output):
self.__init__()
self.outf = output
soup = BeautifulSoup(script, convertEntities='html')
for p in soup('p'):
text = tagtext(p.contents)
handler = getattr(self, p['class'], self.default_p)
if self.inmenu and self.curchoice is not None \
and p['class'] != 'parenthetical':
self.writeln('"%s":' % self.curchoice)
self.curchoice = None
self.indentlvl += 1
handler(p['class'], text)
def sceneheading(self, cls, text):
logging.info("Node started: %s" % text)
pieces = [t.strip().lower() for t in text.split('--')]
self.curcond = None
self.curchar = None
self.inmenu = False
self.indentlvl = 0
self.writeln('# %s' % text.replace('\n', ' ').replace('\r', ''))
self.writeln('label %s:' % pieces[0])
self.indentlvl += 1
def shot(self, cls, text):
text = text.strip().rstrip(':').title()
self.curchar = None
if not self.inmenu:
logging.info("Menu started")
self.writeln('menu:')
self.indentlvl += 1
self.curchoice = text
self.inmenu = True
else:
self.indentlvl -= 1
self.curchoice = text
def transition(self, cls, text):
self.writeln(text.strip().lower())
def parenthetical(self, cls, text):
if self.inmenu and self.curchoice is not None and text[0] != '[':
self.writeln('"%s":' % self.curchoice)
self.curchoice = None
self.indentlvl += 1
if text[0] == '[':
if text[-1] != ']':
logging.warn("Mismatched parenthetical: expect ], got %s" % (
text[-1],
))
text = text[1:-1]
if self.inmenu and self.curchoice is not None:
self.writeln('"%s" if %s:' % (self.curchoice, text))
self.curchoice = None
self.indentlvl += 1
elif self.curchar:
self.curcond = text
elif text[0] == '{':
if text[-1] != '}':
logging.warn("Mismatched parenthetical: expect }, got %s" % (
text[-1],
))
text = text[1:-1]
self.writeln('python:')
self.writeln(text, offset=1)
else:
self.writeln('# %s' % text.replace('\n', ' ').replace('\r', ''))
def character(self, cls, text):
self.curcond = None
self.curchar = text.lower()
def dialog(self, cls, text):
if not self.curchar:
logging.warn("Unattributed dialog: %s" % text)
return
offset = 0
if self.curcond:
self.writeln('if %s:' % self.curcond)
offset = 1
text = text.replace('"', '\\"')
if self.curchar == 'narrator':
self.writeln('"%s"' % text, offset=offset)
else:
self.writeln('%s "%s"' % (self.curchar, text), offset=offset)
def action(self, cls, text):
self.writeln('"%s"' % text)
def text(self, cls, text):
self.writeln('%s' % text)
def main():
import argparse
import sys
parser = argparse.ArgumentParser()
parser.add_argument('script', type=argparse.FileType('r'))
parser.add_argument('-o', '--output', type=argparse.FileType('w'),
default=sys.stdout)
args = parser.parse_args()
conv = ScriptConverter()
conv.convert(args.script, args.output)
args.script.close()
args.output.close()
if __name__ == '__main__':
main()
# vim: ai et ts=4 sts=4 sw=4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment