class Slide(object): def __init__(self): self.index = None self.begin = Timestamp(Timestamp.SRT) self.end = Timestamp(Timestamp.SRT) self.content = [] @classmethod def from_node(cls, node): slide = cls() slide.index = node['index'] slide.begin.millisecond = node['begin'] slide.end.millisecond = node['end'] slide.content = node['content'] return slide @property def valid(self): return self.begin.millisecond > 0 and self.end.millisecond > 0 and \ self.begin.millisecond < self.end.millisecond and self.content @property def node(self): return { 'index':self.index, 'begin':self.begin.millisecond, 'end':self.end.millisecond, 'content':self.content, } @property def duration(self): return self.end.millisecond - self.begin.millisecond def clear(self): self.content = [] def add(self, line): if line: line = line.strip() if line: self.content.append(line) def shift(self, offset): self.begin.shift(offset) self.end.shift(offset) def scale(self, factor): self.begin.scale(factor) self.end.scale(factor) def encode(self, content): content.append(unicode(self.index)) content.append(u'{0} --> {1}'.format(self.begin.timecode, self.end.timecode)) for line in self.content: content.append(line) content.append(u'')
class Chapter(object): def __init__(self): self.index = None self.time = Timestamp(Timestamp.CHAPTER) self._name = None self.language = None @classmethod def from_raw(cls, timecode, name, format): o = cls() codec = Chapter.format[format] if timecode and name: # Decode timecode match = codec["timecode decode"].search(timecode) if match: frag = match.groupdict() o.time.timecode = o.time.codec["encode"].format( int(frag["hour"]), int(frag["minute"]), int(frag["second"]), int(frag["millisecond"]) ) # Decode name if codec["name decode"]: match = codec["name decode"].search(name) if match: frag = match.groupdict() o.name = frag["name"].replace(""", '"') # if 'lang' in frag and frag['lang']: # lang = self.env.enumeration['language'].parse(frag['lang']) # if lang: self.language = lang else: o.name = name return o @classmethod def from_node(cls, node): o = cls() o.index = node["index"] o.time.millisecond = node["time"] o.name = node["name"] return o @property def valid(self): return self.time is not None and self.time.millisecond > 0 @property def name(self): if self._name is None: self._name = Chapter.default_name_format.format(self.index) return self._name @property def node(self): return {"index": self.index, "time": self.time.millisecond, "name": self.name} @name.setter def name(self, value): match = Chapter.junk_name.search(value) if match is None: self._name = value.strip('"').strip("'").strip() else: self._name = None def shift(self, offset): self.time.shift(offset) def scale(self, factor): self.time.scale(factor) def encode(self, content, format): codec = Chapter.format[format] content.append(codec["timecode encode"].format(self.index, self.time.timecode)) content.append(codec["name encode"].format(self.index, self.name)) def __unicode__(self): return u"{}. {}:{}".format(self.index, self.time.timecode, self.name) default_name_format = u"Chapter {0}" junk_name = re.compile(ur"^(?:[0-9]{,2}:[0-9]{,2}:[0-9]{,2}[\.,][0-9]+|[0-9]+|chapter[\s0-9]+)$", re.UNICODE) OGG = 1 MEDIAINFO = 2 format = { 1: { "timecode encode": u"CHAPTER{0:02d}={1}", "timecode decode": re.compile( ur"CHAPTER(?P<index>[0-9]{,2})=(?P<hour>[0-9]{,2}):(?P<minute>[0-9]{,2}):(?P<second>[0-9]{,2})\.(?P<millisecond>[0-9]+)", re.UNICODE, ), "name encode": u"CHAPTER{0:02d}NAME={1}", "name decode": re.compile(ur"CHAPTER(?P<index>[0-9]{,2})NAME=(?P<name>.*)", re.UNICODE), }, 2: { "timecode encode": None, "timecode decode": re.compile( ur"_(?P<hour>[0-9]{,2})_(?P<minute>[0-9]{,2})_(?P<second>[0-9]{2})(?P<millisecond>[0-9]{3})", re.UNICODE ), "name encode": None, "name decode": re.compile(ur"(?:(?P<lang>[a-z]{2}):)?(?P<name>.*)", re.UNICODE), }, }