| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- #!/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()
|