offset-fixer.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  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="New subtitle filename", 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. if (entryNumber > 0) and (timestamp is not None):
  63. s = SubtitleEntry(entryNumber, text, timestamp.groups()[0], timestamp.groups()[1])
  64. Subtitles.append(s)
  65. text = ""
  66. timestamp = ""
  67. entryNumber = 0
  68. elif re.match(r"^[0-9]+$", line):
  69. entryNumber = int(line.rstrip())
  70. elif m1:
  71. timestamp = m1
  72. else:
  73. text += line
  74. if args.inplace == True:
  75. args.outfile = args.file
  76. args.file = args.file + ".backup"
  77. with open(args.file, 'w') as o:
  78. print("Writing backup to " + args.file)
  79. for entry in Subtitles:
  80. print(entry.formatEntry(), file=o)
  81. print("Updating subtitle file: " + args.outfile)
  82. with open(args.outfile, 'w') as o:
  83. print("Shifting all entries by {} seconds".format(args.seconds))
  84. for entry in Subtitles:
  85. entry.shift(args.seconds)
  86. print(entry.formatEntry(), file=o)
  87. if __name__ == "__main__":
  88. main()