Advertisement
mbpaster

subslider.py

May 2nd, 2012
828
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.60 KB | None | 0 0
  1.  
  2. #!/usr/bin/env python
  3. # -*- coding: utf-8 -*-
  4. #
  5. # SubSlider - a simple script to apply offsets to subtitles
  6. #
  7. # Copyright May 2nd 2012 - MB <http://somethingididnotknow.wordpress.com>
  8. #
  9. # This program is free software: you can redistribute it and/or modify
  10. # it under the terms of the GNU General Public License as published by
  11. # the Free Software Foundation, either version 3 of the License, or
  12. # (at your option) any later version.
  13. #
  14. # This program is distributed in the hope that it will be useful,
  15. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17. # GNU General Public License for more details.
  18. #
  19. # You should have received a copy of the GNU General Public License
  20. # along with this program.  If not, see <http://www.gnu.org/licenses/>
  21. from __future__ import print_function
  22. from datetime import timedelta, datetime
  23. import os
  24. import re
  25. import sys
  26.  
  27. class SubSlider:
  28.     """A simple script to apply offsets to subtitles.
  29.  
  30.    Subtitles can be delayed by specifying a positive offset (e.g. +12 or simply 12), or video can be delayed by specifying a negative offset (e.g. -12)"""
  31.  
  32.     def __init__(self, argv):
  33.         if len(argv) < 2:
  34.             self.usage()
  35.         else:
  36.             self.first_valid = 0
  37.             self.parse_args(argv)
  38.             self.parse_subs()
  39.             self.fix_file()
  40.             os.remove(self.output_temp)
  41.             print('Success! Offset subs have been written to %s' % os.path.abspath(self.output_subs))
  42.  
  43.     def usage(self):
  44.         print("""usage: subslider.py [-h] subs_file offset
  45.  
  46. Applies an offset to a subtitles file
  47.  
  48. positional arguments:
  49.  subs_file             The input subtitles file, the one to which the offset
  50.                        is to be applied
  51.  offset                The offset to be applied to the input subtitles file.
  52.                        Format is [+/-][MM:]SS[,sss] like +1:23,456 (new subs
  53.                        will be displayed with a delay of 1 minute, 23 seconds,
  54.                        456 milliseconds) or -100 (subs 100
  55.                        seconds earlier) or +12,43 (subs delayed of 12 seconds
  56.                        43 milliseconds)""")
  57.         sys.exit(1)
  58.  
  59.  
  60.     def parse_args(self, args):
  61.         error = None
  62.         if not os.path.isfile(args[0]):
  63.             print('%s does not exist' % args[0])
  64.             error = True
  65.         else:
  66.             self.input_subs = args[0]
  67.             self.output_subs = '%s_offset.srt' % os.path.splitext(self.input_subs)[0]
  68.             self.output_temp = '%s_temp.srt' % os.path.splitext(self.input_subs)[0]
  69.         offset_ok = re.match('[\+\-]?(\d{1,2}\:)?\d+(\,\d{1,3})?$', args[1])
  70.         if not offset_ok:
  71.             print('%s is not a valid offset, format is [+/-][MM:]SS[,sss], see help dialog for some examples' % args[1])
  72.             error = True
  73.         else:
  74.             offset = re.search('([\+\-])?((\d{1,2})\:)?(\d+)(\,(\d{1,3}))?', args[1])
  75.             self.direction, self.minutes, self.seconds, self.millis = (offset.group(1), offset.group(3), offset.group(4), offset.group(6))
  76.         if error:
  77.             self.usage()
  78.  
  79.     def parse_subs(self):
  80.         with open(self.input_subs, 'r') as input:
  81.             with open(self.output_temp, 'w') as output:
  82.                 nsafe = lambda s: int(s) if s else 0
  83.                 block = 0
  84.                 date_zero = datetime.strptime('00/1/1','%y/%m/%d')
  85.                 for line in input:
  86.                     parsed = re.search('(\d{2}:\d{2}:\d{2},\d{3}) \-\-> (\d{2}:\d{2}:\d{2},\d{3})', line)
  87.                     if parsed:
  88.                         block += 1
  89.                         start, end = (self.parse_time(parsed.group(1)), self.parse_time(parsed.group(2)))
  90.                         offset = timedelta(minutes=nsafe(self.minutes), seconds=nsafe(self.seconds), microseconds=nsafe(self.millis) * 1000)
  91.                         if '-' == self.direction:
  92.                             start -= offset
  93.                             end -= offset
  94.                         else:
  95.                             start += offset
  96.                             end += offset
  97.                         offset_start, offset_end = (self.format_time(start), self.format_time(end))
  98.                         if not self.first_valid:
  99.                             if end > date_zero:
  100.                                 self.first_valid = block
  101.                                 if start < date_zero:
  102.                                     offset_start = '00:00:00,000'
  103.                         output.write('%s --> %s\n' % (offset_start, offset_end))
  104.                     else:
  105.                         output.write(line)
  106.  
  107.     def fix_file(self):
  108.         with open(self.output_temp, 'r') as input:
  109.             with open(self.output_subs, 'w') as output:
  110.                 start_output = False
  111.                 for line in input:
  112.                     if re.match('\d+$', line.strip()):
  113.                         block_num = int(line.strip())
  114.                         if block_num >= self.first_valid:
  115.                             if not start_output:
  116.                                 start_output = True
  117.                             output.write('%d\r\n' % (block_num - self.first_valid + 1))
  118.                     elif start_output:
  119.                         output.write(line)
  120.  
  121.     def format_time(self, value):
  122.         formatted = datetime.strftime(value, '%H:%M:%S,%f')
  123.         return formatted[:-3]
  124.  
  125.     def parse_time(self, time):
  126.         parsed = datetime.strptime(time, '%H:%M:%S,%f')
  127.         return parsed.replace(year=2000)
  128.  
  129. if __name__ == '__main__':
  130.     SubSlider(sys.argv[1:])
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement