|
@@ -0,0 +1,120 @@
|
|
|
|
|
+#!/usr/bin/env python
|
|
|
|
|
+
|
|
|
|
|
+import re
|
|
|
|
|
+from datetime import timedelta
|
|
|
|
|
+import argparse
|
|
|
|
|
+import locale
|
|
|
|
|
+
|
|
|
|
|
+import math
|
|
|
|
|
+
|
|
|
|
|
+class SubtitleEntry:
|
|
|
|
|
+ def __init__(self, entryNumber, text, startTime, endTime):
|
|
|
|
|
+ # dd:dd:dd,ddd --> dd:dd:dd,ddd
|
|
|
|
|
+ self.entryNumber = entryNumber
|
|
|
|
|
+ self.text = text
|
|
|
|
|
+ sH, sM, sS = startTime.replace(',', '.').split(':')
|
|
|
|
|
+ self.startTime = int(sH) * 3600 + int(sM) * 60 + float(sS)
|
|
|
|
|
+ sH, sM, sS = endTime.replace(',', '.').split(':')
|
|
|
|
|
+ self.endTime = int(sH) * 3600 + int(sM) * 60 + float(sS)
|
|
|
|
|
+
|
|
|
|
|
+ def formatEntry(self):
|
|
|
|
|
+ entry = ""
|
|
|
|
|
+ entry += "{}\n".format(self.entryNumber)
|
|
|
|
|
+ entry += self.formatTimeString() + "\n"
|
|
|
|
|
+ entry += "{}".format(self.text)
|
|
|
|
|
+ return entry
|
|
|
|
|
+
|
|
|
|
|
+ def formatTimeString(self):
|
|
|
|
|
+ s = self.startTime
|
|
|
|
|
+ startHours = s // 3600
|
|
|
|
|
+ s = s - (startHours * 3600)
|
|
|
|
|
+ startMinutes = s // 60
|
|
|
|
|
+ s = s - (startMinutes * 60)
|
|
|
|
|
+ startSeconds = s
|
|
|
|
|
+
|
|
|
|
|
+ e = self.endTime
|
|
|
|
|
+ endHours = e // 3600
|
|
|
|
|
+ e = e - (endHours * 3600)
|
|
|
|
|
+ endMinutes = e // 60
|
|
|
|
|
+ e = e - (endMinutes * 60)
|
|
|
|
|
+ endSeconds = e
|
|
|
|
|
+
|
|
|
|
|
+ return '{:02.0f}:{:02.0f}:{:02.0f},{:03.0f} --> {:02.0f}:{:02.0f}:{:02.0f},{:03.0f}'.format(startHours, startMinutes, math.floor(startSeconds), (startSeconds % 1) * 1000 , endHours, endMinutes, math.floor(endSeconds), (endSeconds % 1) * 1000 )
|
|
|
|
|
+
|
|
|
|
|
+ def shift(self, seconds):
|
|
|
|
|
+ self.startTime = self.startTime + seconds
|
|
|
|
|
+ self.endTime = self.endTime + seconds
|
|
|
|
|
+
|
|
|
|
|
+def main():
|
|
|
|
|
+ Subtitles = []
|
|
|
|
|
+
|
|
|
|
|
+ parser = argparse.ArgumentParser()
|
|
|
|
|
+
|
|
|
|
|
+ parser.add_argument("--seconds", help="Decimal formatted seconds to adjust offsets by", type=float, required=True)
|
|
|
|
|
+ parser.add_argument("--file", help="Subtitle file to shift", type=str, required=True)
|
|
|
|
|
+ parser.add_argument("--inplace", required=False, help="Shift file in place, creating a backup", action='store_true')
|
|
|
|
|
+ parser.add_argument("--outfile", required=False, help="New subtitle filename", type=str)
|
|
|
|
|
+ parser.add_argument("--strip-first", required=False, help="Clear first subtitle entry", action='store_true')
|
|
|
|
|
+ parser.add_argument("--strip-last", required=False, help="Clear last subtitle entry", action='store_true')
|
|
|
|
|
+
|
|
|
|
|
+ args = parser.parse_args()
|
|
|
|
|
+
|
|
|
|
|
+ if args.inplace is True:
|
|
|
|
|
+ if args.outfile == None:
|
|
|
|
|
+ args.outfile = str(args.file + ".backup")
|
|
|
|
|
+ else:
|
|
|
|
|
+ sys.exit(1)
|
|
|
|
|
+
|
|
|
|
|
+ if args.outfile == None:
|
|
|
|
|
+ args.outfile = str(args.file + ".new")
|
|
|
|
|
+
|
|
|
|
|
+ print("Opening subtitle file: {}".format(args.file))
|
|
|
|
|
+
|
|
|
|
|
+ with open(args.file, "r+") as file:
|
|
|
|
|
+ entryNumber = 0
|
|
|
|
|
+ text = ""
|
|
|
|
|
+ timestamp = ""
|
|
|
|
|
+ for line in file:
|
|
|
|
|
+ m1 = re.match(r"^([0-9]{2}:[0-9]{2}:[0-9]{2},[0-9]{3}) --> ([0-9]{2}:[0-9]{2}:[0-9]{2},[0-9]{3})", line)
|
|
|
|
|
+ if line == "\n":
|
|
|
|
|
+ if (entryNumber > 0) and (timestamp is not None):
|
|
|
|
|
+ s = SubtitleEntry(entryNumber, text, timestamp.groups()[0], timestamp.groups()[1])
|
|
|
|
|
+ Subtitles.append(s)
|
|
|
|
|
+ text = ""
|
|
|
|
|
+ timestamp = ""
|
|
|
|
|
+ entryNumber = 0
|
|
|
|
|
+ elif re.match(r"^[0-9]+$", line):
|
|
|
|
|
+ entryNumber = int(line.rstrip())
|
|
|
|
|
+ elif m1:
|
|
|
|
|
+ timestamp = m1
|
|
|
|
|
+ else:
|
|
|
|
|
+ text += line
|
|
|
|
|
+
|
|
|
|
|
+ if args.inplace == True:
|
|
|
|
|
+ args.outfile = args.file
|
|
|
|
|
+ args.file = args.file + ".backup"
|
|
|
|
|
+ with open(args.file, 'w') as o:
|
|
|
|
|
+ print("Writing backup to " + args.file)
|
|
|
|
|
+ for entry in Subtitles:
|
|
|
|
|
+ print(entry.formatEntry(), file=o)
|
|
|
|
|
+
|
|
|
|
|
+ print("Updating subtitle file: " + args.outfile)
|
|
|
|
|
+ lastEntryNumber = Subtitles[-1].entryNumber
|
|
|
|
|
+ with open(args.outfile, 'w') as o:
|
|
|
|
|
+ print("Shifting all entries by {} seconds".format(args.seconds))
|
|
|
|
|
+ for idx, entry in enumerate(Subtitles):
|
|
|
|
|
+ if idx == 0:
|
|
|
|
|
+ print("First subtitle line: {}".format(entry.text))
|
|
|
|
|
+ if args.strip_first and entry.text != "":
|
|
|
|
|
+ print("Stripping first line - {}".format(entry.text))
|
|
|
|
|
+ entry.text = ""
|
|
|
|
|
+ if idx == lastEntryNumber - 1:
|
|
|
|
|
+ print("Last subtitle line: {}".format(entry.text))
|
|
|
|
|
+ if args.strip_last and entry.text != "":
|
|
|
|
|
+ print("Stripping last line - {}".format(entry.text))
|
|
|
|
|
+ entry.text = ""
|
|
|
|
|
+ entry.shift(args.seconds)
|
|
|
|
|
+ print(entry.formatEntry(), file=o)
|
|
|
|
|
+
|
|
|
|
|
+if __name__ == "__main__":
|
|
|
|
|
+ main()
|