summaryrefslogtreecommitdiff
path: root/pykfx/__init__.py
diff options
context:
space:
mode:
authorJon Bergli Heier <jonheier@start.no>2007-10-01 00:04:47 +0200
committerJon Bergli Heier <jonheier@start.no>2007-10-01 00:04:47 +0200
commitc062ac07e6241cf32a4a5655775aa037bdb1e76e (patch)
treea3b41bfc3ea1b57af6b95e4072ce7fcbbdaa4afb /pykfx/__init__.py
parent2b47e8d3c263bdaff9d48f3a1a480631b22ee145 (diff)
Moved pykfx.py to pykfx/__init__.py
Added self.names in Styles along with int support in __getitem__. Added setup.py. Added fscalc, an extension that calculates text sizes for a given font. Using boost.python-wrapper for fscalc.
Diffstat (limited to 'pykfx/__init__.py')
-rw-r--r--pykfx/__init__.py232
1 files changed, 232 insertions, 0 deletions
diff --git a/pykfx/__init__.py b/pykfx/__init__.py
new file mode 100644
index 0000000..4ef55f1
--- /dev/null
+++ b/pykfx/__init__.py
@@ -0,0 +1,232 @@
+import re
+
+class StyleException(Exception): pass
+class EventException(Exception): pass
+class ScriptException(Exception): pass
+
+class ScriptInfo:
+ def __init__(self, f = None):
+ # original case keys used for writing
+ self.ock = {}
+ self.info = {}
+ if f:
+ self.read(f)
+
+ def __getitem__(self, key):
+ try:
+ return self.info[key.lower()]
+ except ValueError:
+ raise KeyError
+
+ def read(self, f):
+ s = f.readline().strip()
+ while s:
+ if not s.startswith(';'):
+ k, v = s.split(': ', 1)
+ self.ock[k.lower()] = k
+ self.info[k.lower()] = v
+ s = f.readline().strip()
+
+ def write(self, f):
+ f.write('[Script Info]\n')
+ f.writelines(['%s: %s\n' % (self.ock[k], self.info[k]) for k in self.info.keys()])
+
+class Style:
+ def __init__(self, format, s = None):
+ self.format = format
+ if s:
+ self.parse(s)
+
+ def __str__(self):
+ return 'Style: %s' % ','.join([getattr(self, x.lower()) for x in self.format])
+
+ def parse(self, s):
+ s = s.split(': ', 1)
+ if s[0] != 'Style':
+ raise StyleException('invalid style line')
+ s = s[1].split(',')
+ for k, v in zip(self.format, s):
+ setattr(self, k.lower(), v)
+
+class Styles:
+ def __init__(self, f = None):
+ self.format, self.styles, self.names = [], {}, []
+ if f:
+ self.read(f)
+
+ def __getitem__(self, key):
+ if type(key) == int:
+ return self.styles[self.names[key]]
+ elif self.styles.has_key(key.lower()):
+ return self.styles[key.lower()]
+ else:
+ raise KeyError('style "%s" not found' % key)
+
+ def read(self, f):
+ s = f.readline().strip()
+ s = s.split(': ', 1)
+ if s[0] != 'Format':
+ raise StyleException('format line not found')
+ self.format = s[1].split(', ')
+
+ s = f.readline().strip()
+ while s:
+ s = Style(self.format, s)
+ self.styles[s.name.lower()] = s
+ self.names.append(s.name.lower())
+ s = f.readline().split()
+
+ def write(self, f):
+ f.write('[V4+ Styles]\n')
+ f.write('Format: %s\n' % ', '.join(self.format))
+ f.writelines(['%s\n' % str(s) for s in self.styles.values()])
+
+class Syllable:
+ def __init__(self, start, end, text):
+ self.start, self.end, self.dur, self.text = start, end, end - start, text
+
+ def __str__(self):
+ return '{\\k%d}%s' % (self.dur / 10, self.text)
+
+class Event:
+ def __init__(self, format, s = None):
+ self.karaoke = []
+ self.format = format
+ if s:
+ self.parse(s)
+
+ def __getitem__(self, key):
+ if type(key) is int:
+ return self.karaoke[key]
+ else:
+ raise TypeError('key must be int')
+
+ def __str__(self):
+ return '%s: %s' % (self.kind.capitalize(), ','.join([getattr(self, x.lower()) for x in self.format]))
+
+ def parse(self, s):
+ s = s.split(': ', 1)
+ self.kind = s[0].lower()
+ s = s[1].split(',')
+ for k, v in zip(self.format, s):
+ setattr(self, k.lower(), v)
+ if self.kind == 'dialogue' and self.text.find('\\k') > -1:
+ self.parse_karaoke()
+
+ def parse_karaoke(self):
+ s = self.text
+ i = 0
+ tot = 0
+ while i < len(s):
+ i = s.find('\\k', i)
+ # break if no more \k's (end-of-line-text is added at the end of the loop)
+ if i == -1:
+ break
+ i += 2
+ ms = ''
+ while s[i].isdigit():
+ ms += s[i]
+ i += 1
+ ms = int(ms) * 10
+ tot += ms
+ # unless next is another override, skip one char (past '}')
+ if s[i] != '\\':
+ i += 1
+ n = s.find('\\k', i)
+ if n > -1:
+ part = s[i:n-1] # get text up to next \k
+ else:
+ part = s[i:] # end of line
+
+ # go to next if part is empty
+ if not part.strip():
+ continue
+
+ self.karaoke.append(Syllable(tot - ms, tot, part))
+
+ def add_lead_in(self, s):
+ t = self.start.split(':')
+ ts = float(t[-1]) + 60 * int(t[-2]) + 3600 * int(t[-3]) - s
+ th, ts = int(ts / 3600), ts % 3600
+ tm, ts = int(ts / 60), ts % 60
+ self.start = '%01d:%02d:%05.2f' % (th, tm, ts)
+
+ def add_lead_out(self, s):
+ t = self.snd.split(':')
+ ts = float(t[-1]) + 60 * int(t[-2]) + 3600 * int(t[-3]) + s
+ th, ts = int(ts / 3600), ts % 3600
+ tm, ts = int(ts / 60), ts % 60
+ self.end = '%01d:%02d:%05.2f' % (th, tm, ts)
+
+class Events:
+ def __init__(self, f = None):
+ self.format, self.events = [], []
+ if f:
+ self.read(f)
+
+ def __getitem__(self, key):
+ if type(key) is int:
+ return self.events[key]
+ else:
+ raise TypeError('key must be int')
+
+ def add(self, s = None, e = None):
+ if not e and s:
+ e = Event(self.format, s)
+ if e:
+ self.events.append(e)
+ return e
+
+ def read(self, f):
+ s = f.readline().strip()
+ s = s.split(': ', 1)
+ if s[0] != 'Format':
+ raise EventException('format line not found')
+ self.format = s[1].split(', ')
+
+ s = f.readline().strip()
+ while s:
+ self.add(s)
+ s = f.readline().strip()
+
+ def write(self, f):
+ f.write('[Events]\n')
+ f.write('Format: %s\n' % ', '.join(self.format))
+ f.writelines(['%s\n' % str(e) for e in self.events])
+
+class Script:
+ def __init__(self, f = None):
+ if f:
+ self.read(f)
+
+ def read(self, f):
+ f = open(f, 'r')
+
+ s = f.readline().strip()
+ if s.startswith('\xef\xbb\xbf'):
+ s = s[3:]
+ if s == '[Script Info]':
+ self.info = ScriptInfo(f)
+ else:
+ raise ScriptException('script info not found')
+
+ s = f.readline().strip()
+ if re.match('\[V4\+? Styles\]', s):
+ self.styles = Styles(f)
+ else:
+ raise ScriptException('script styles not found')
+
+ s = f.readline().strip()
+ if s == '[Events]':
+ self.events = Events(f)
+ else:
+ raise ScriptException('script events not found')
+
+ def write(self, f):
+ f = open(f, 'w')
+ self.info.write(f)
+ f.write('\n')
+ self.styles.write(f)
+ f.write('\n')
+ self.events.write(f)
+ f.write('\n')