#!/usr/bin/python
# -*- coding: UTF-8 -*-

"""lengthen.py

Usage: lengthen.py [-n <seconds>] [--input <infile>] [--output <outfile>]

Reads a subtitle file from <infile> (or stdin if not specified), and
outputs a new subtitle file to <outfile> (or stdout if not specified).
All subtitles in the new file will be displayed <seconds> longer than
in the original file, but they won't be overlapping.

<seconds> can be either an integer or a floating point number.

The subtitle files should be in SRT format. You can use mplayer to
convert different subtitle formats.
"""

__author__ = "Sybren Stüvel"
__copyright__ = "GPL"
__url__ = "http://www.unrealtower.org/lengthen"

import sys
import datetime
import getopt

class SubtitleEntry(dict):
	def __repr__(self):
		return """%(num)i
			%(start)s --> %(end)s
			%(lines)s
			""".replace('\t', '') % self

class ShorterTimeDelta(datetime.timedelta):
	def __new__(self, *args, **kwargs):
		if 'copy' in kwargs:
			return datetime.timedelta.__new__(
					self,
					days = kwargs['copy'].days,
					seconds = kwargs['copy'].seconds,
					microseconds = kwargs['copy'].microseconds)
		return datetime.timedelta.__new__(self, *args, **kwargs)

	def __str__(self):
		sec = self.seconds
		(hours, sec) = divmod(sec, 3600)
		(mins , sec) = divmod(sec, 60)

		return "%02i:%02i:%02i,%03i" % (hours, mins, sec, self.microseconds / 1000)

	__repr__ = __str__
	__unicode__ = __str__

def str2time(string):
	"""Converts a string in the format HH:MM:SS,mmm to a
	datetime.timedelta object"""

	(hhmmss, mmm) = string.split(',')
	(hh, mm, ss) = hhmmss.split(':')

	return ShorterTimeDelta(
			hours=int(hh),
			minutes=int(mm),
			seconds=int(ss),
			milliseconds=int(mmm)
			)

def parse(entry):
	"""Parses an entry, returning a dict
		'num': number (int),
		'start': start code (time),
		'end': end code (time),
		'lines': the lines of text, including a space in front
	"""

	if not entry:
		return

	parts = entry.split('\n')
	time  = parts[1].split(' --> ')

	start  = str2time(time[0])
	end    = str2time(time[1])

	r = SubtitleEntry({
		'num': int(parts[0]),
		'start': start,
		'end': end,
		'lines': '\n'.join(parts[2:])
	})

	return r

def main():
	# Parse options
	try:
		optlist, args = getopt.gnu_getopt(sys.argv, 'i:o:n:', ['input=', 'output='])
	except getopt.GetoptError:
		import lengthen
		help(lengthen)
		raise SystemExit()

	infile  = sys.stdin
	outfile = sys.stdout
	maxskip = ShorterTimeDelta(seconds = 2)

	for (key, value) in optlist:
		if key in ['-i', '--input']:
			infile = file(value)
		if key in ['-o', '--output']:
			outfile = file(value, 'w')
		if key in ['-n']:
			maxskip = ShorterTimeDelta(seconds = float(value))


	# Read & parse file
	input  = infile.read().strip()
	parsed = [parse(entry) for entry in input.split('\n\n')]

	milli   = ShorterTimeDelta(milliseconds = 1)

	for number, cur in enumerate(parsed):
		try:
			next = parsed[number+1]
			margin = (next['start'] - cur['end'] - milli)
		except IndexError:
			margin = ShorterTimeDelta(days = 10)

		skip = min(margin, maxskip)
		cur['end'] = ShorterTimeDelta(copy = (cur['end'] + skip))

		print >>outfile, cur

if __name__ == '__main__':
	main()

