offset-fixer.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. #!/usr/bin/env python
  2. import re
  3. from datetime import timedelta
  4. import argparse
  5. import locale
  6. import math
  7. class SubtitleEntry:
  8. def __init__(self, entryNumber, text, startTime, endTime):
  9. # dd:dd:dd,ddd --> dd:dd:dd,ddd
  10. self.entryNumber = entryNumber
  11. self.text = text
  12. sH, sM, sS = startTime.replace(',', '.').split(':')
  13. self.startTime = int(sH) * 3600 + int(sM) * 60 + float(sS)
  14. sH, sM, sS = endTime.replace(',', '.').split(':')
  15. self.endTime = int(sH) * 3600 + int(sM) * 60 + float(sS)
  16. def formatEntry(self):
  17. entry = ""
  18. entry += "{}\n".format(self.entryNumber)
  19. entry += self.formatTimeString() + "\n"
  20. entry += "{}".format(self.text)
  21. return entry
  22. def formatTimeString(self):
  23. s = self.startTime
  24. startHours = s // 3600
  25. s = s - (startHours * 3600)
  26. startMinutes = s // 60
  27. s = s - (startMinutes * 60)
  28. startSeconds = s
  29. e = self.endTime
  30. endHours = e // 3600
  31. e = e - (endHours * 3600)
  32. endMinutes = e // 60
  33. e = e - (endMinutes * 60)
  34. endSeconds = e
  35. 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 )
  36. def shift(self, seconds):
  37. self.startTime = self.startTime + seconds
  38. self.endTime = self.endTime + seconds
  39. def main():
  40. Subtitles = []
  41. parser = argparse.ArgumentParser()
  42. parser.add_argument("--seconds", help="Decimal formatted seconds to adjust offsets by", type=float, required=True)
  43. parser.add_argument("--file", help="Subtitle file to shift", type=str, required=True)
  44. parser.add_argument("--inplace", required=False, help="Shift file in place, creating a backup", action='store_true')
  45. parser.add_argument("--outfile", required=False, help="Subtitle file to shift", type=str)
  46. args = parser.parse_args()
  47. if args.inplace is True:
  48. if args.outfile == None:
  49. args.outfile = str(args.file + ".backup")
  50. else:
  51. sys.exit(1)
  52. if args.outfile == None:
  53. args.outfile = str(args.file + ".new")
  54. print("Opening subtitle file: {}".format(args.file))
  55. with open(args.file, "r+") as file:
  56. entryNumber = 0
  57. text = ""
  58. timestamp = ""
  59. for line in file:
  60. 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)
  61. if line == "\n":
  62. #print("blank line")
  63. if (entryNumber > 0) and (timestamp is not None):
  64. #print("new entry")
  65. s = SubtitleEntry(entryNumber, text, timestamp.groups()[0], timestamp.groups()[1])
  66. Subtitles.append(s)
  67. #print(s.entryNumber, s.startTime, s.endTime, s.text)
  68. text = ""
  69. timestamp = ""
  70. entryNumber = 0
  71. elif re.match(r"^[0-9]+$", line):
  72. #print("Added entryNumber")
  73. entryNumber = int(line.rstrip())
  74. #print(entryNumber)
  75. elif m1:
  76. #print("Added timestamp")
  77. timestamp = m1
  78. #print(m1.groups()[0])
  79. #print(m1.groups()[1])
  80. else:
  81. #print("Added text:" + line)
  82. text += line
  83. if args.inplace == True:
  84. args.outfile = args.file
  85. args.file = args.file + ".backup"
  86. with open(args.file, 'w') as o:
  87. print("Writing backup to " + args.file)
  88. for entry in Subtitles:
  89. print(entry.formatEntry(), file=o)
  90. print("Updating subtitle file: " + args.outfile)
  91. with open(args.outfile, 'w') as o:
  92. print("Shifting all entries by {} seconds".format(args.seconds))
  93. for entry in Subtitles:
  94. #print("\n\n\n\n")
  95. #print(entry.entryNumber)
  96. entry.shift(args.seconds)
  97. #print(entry.formatEntry())
  98. print(entry.formatEntry(), file=o)
  99. if __name__ == "__main__":
  100. main()