Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 13 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
##**SubFixer**
# SubFixer
SubFixer does a bit of string manipulation and datetime math to shift your subtitles to match your film and decode string to unicode and fix problems with Persian.
SubFixer is based on [Ali Vakilzade](https://github.com/aliva/) SubtitleFixer and [delwin](https://github.com/enceladus/) subtitle-shifter.

###Install SubFixer
## Install SubFixer
```
$ pip install subfixer
```

###Fix persian subtitles
```
$ subfixer input_file_name.srt --fix_persian
```
## Usage

###Shift time
```
$ subfixer input_file_name.srt --shif 10 #shift 10 secound
Simple fix subtitles:

```shell
$ subfixer input.srt
```

###More help and options
Shifting some second times:
```shell
$ subfixer input.srt --shif 10 # Shift 10 secound
```

for more help and options:
```shell
$ subfixer --help
```

154 changes: 79 additions & 75 deletions subfixer.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# -*- coding: utf-8 -*-

__author__ = 'itmard'
__author__ = "itmard"

import codecs
import sys
import re
import datetime
Expand All @@ -12,85 +13,88 @@

class SubtitleFixer:
def __init__(self):
self.time = '\d\d:\d\d:\d\d,\d\d\d'
self.number = u'۰۱۲۳۴۵۶۷۸۹'
self.time = r"\d\d:\d\d:\d\d,\d\d\d"
self.number = u"۰۱۲۳۴۵۶۷۸۹"

self.string = ''
self.string = ""

def fix_encoding(self):
assert isinstance(self.string, str), repr(self.string)
assert isinstance(self.string, bytes), repr(self.string)

try:
self.string.decode('utf8', 'strict')
self.string = self.string.decode('utf8')
return 'utf8'
self.string.decode("utf8", "strict")
self.string = self.string.decode("utf8")
return "utf8"
except UnicodeError:
pass

try:
self.string.decode('utf16', 'strict')
self.string = self.string.decode('utf16')
return 'utf16'
self.string.decode("utf16", "strict")
self.string = self.string.decode("utf16")
return "utf16"
except UnicodeError:
pass

self.string = self.string.decode('windows-1256')
return 'windows-1256'
self.string = self.string.decode("windows-1256")
return "windows-1256"

def fix_italic(self):
self.string = self.string.replace('<i>', '')
self.string = self.string.replace('</i>', '')
self.string = self.string.replace("<i>", "")
self.string = self.string.replace("</i>", "")

def fix_arabic(self):
self.string = self.string.replace(u'ي', u'ی')
self.string = self.string.replace(u'ك', u'ک')
self.string = self.string.replace(u"ي", u"ی")
self.string = self.string.replace(u"ك", u"ک")

def fix_question_mark(self):
# quistion mark in persina is ؟ not ?
self.string = self.string.replace('?', u'؟')
self.string = self.string.replace("?", u"؟")

def fix_other(self):
self.string = self.string.replace(u'\u202B', u'')
self.string = self.string.replace(u"\u202B", u"")

lines = self.string.split('\n')
string = ''
lines = self.string.split("\n")
string = ""

for line in lines:
if re.match('^%s\s-->\s%s$' % (self.time, self.time), line):
if re.match(r"^%s\s-->\s%s$" % (self.time, self.time), line):
string += line
elif re.match('^%s\s-->\s%s$' % (self.time, self.time), line[:-1]):
elif re.match(r"^%s\s-->\s%s$" % (self.time, self.time), line[:-1]):
string += line
elif line.strip() == '':
elif line.strip() == "":
string += line
elif re.match('^\d+$', line):
elif re.match(r"^\d+$", line):
string += line
elif re.match('^\d+$', line[:-1]):
elif re.match(r"^\d+$", line[:-1]):
string += line
elif re.match(r"<.*>.*<\/.*>", line):
string += line
else:
# this should be subtitle
s = re.match('^([\.!?]*)', line)
s = re.match(r"^([\.!?]*)", line)

try:
line = re.sub('^%s' % s.group(), '', line)
line = re.sub(r"^%s" % s.group(), "", line)
except:
pass

# use persian numbers
for i in range(0, 10):
re.sub("\d", self.number[i], line)
line = line.replace(str(i), self.number[i])

# for ltr problems some peoples put '-' on EOL
# for ltr problems some peoples put "-" on EOL
# it should be in start
if len(line) != 0 and line[-1] == '-':
line = '- %s' % line[:-1]
if len(line) != 0 and line[-1] == "-":
line = "- %s" % line[:-1]
line += s.group()

# put rtl char in start of line
# it forces some player to show that line rtl
string += u'\u202B' + unicode(line)
string += u"\u202B" + str(line)

# noting to see here
string += '\n'
string += "\n"

self.string = string

Expand Down Expand Up @@ -122,10 +126,10 @@ def change_time(hour, minute, second, time_diff):
try:
return current_time + difference
except OverflowError:
print 'ERROR: Date value out of range.'
click.echo("ERROR: Date value out of range.")
sys.exit()
except:
print 'ERROR: Error changing time.'
click.echo("ERROR: Error changing time.")
return None


Expand All @@ -138,10 +142,10 @@ def process_time_string(s, time_diff):
"""

# Ignore milliseconds
s = s.split(',')
s = s.split(",")

# Convert to time object
dt = time.strptime(s[0], '%H:%M:%S')
dt = time.strptime(s[0], "%H:%M:%S")

# Apply time difference
dt = change_time(dt.tm_hour, dt.tm_min, dt.tm_sec, time_diff)
Expand All @@ -150,80 +154,80 @@ def process_time_string(s, time_diff):
minutes = str(dt.minute)
seconds = str(dt.second)
if len(minutes) == 1:
minutes = '0%s' % (minutes,)
minutes = "0%s" % (minutes,)
if len(seconds) == 1:
seconds = '0%s' % (seconds,)
seconds = "0%s" % (seconds,)

new_time_string = '0%s:%s:%s,%s' % (str(dt.hour), minutes, seconds, s[1])
new_time_string = "0%s:%s:%s,%s" % (str(dt.hour), minutes, seconds, s[1])
return new_time_string


def is_time_string(s):
""" Determines if a string 's' is an SRT file time string
""" Determines if a string "s" is an SRT file time string
Format: HH:MM:SS,MMS --> HH:MM:SS,MMS
"""
if re.match(r'^\d{2}:\d{2}:\d{2},\d{3} --> \d{2}:\d{2}:\d{2},\d{3}$', s):
if re.match(r"^\d{2}:\d{2}:\d{2},\d{3} --> \d{2}:\d{2}:\d{2},\d{3}$", s):
return True
return False


@click.command()
@click.argument('input', type=click.Path(exists=True))
@click.argument('output', type=click.Path(), required=False)
@click.option('--fix_persian', is_flag=True, help='Decode Unicode and fix issues with Persian')
@click.option('--shift', type=int, help='The change in seconds to shift the subtitles, e.g. --shift 2 or --shift -5')
def cli(input, output, fix_persian, shift):
'''
@click.argument("input", type=click.Path(exists=True))
@click.argument("output", type=click.Path(), required=False)
@click.option("--shift", type=int, help="The change in seconds to shift the subtitles, e.g. --shift 2 or --shift -5")
def cli(input, output, shift):
"""
SubFixer does a bit of string manipulation and datetime math
to shift your subtitles to match your film and decode string to
unicode and fix problems with Persian.

'''
if input[-4:] not in ('.srt', '.SRT'):
click.echo('%s is not a srt file.' % click.format_filename(input))
"""
if input[-4:] not in (".srt", ".SRT"):
click.echo("%s is not a srt file." % click.format_filename(input))
exit()
if not fix_persian and not shift:
raise click.BadParameter('''Enter an option --fix_persian or --shift \
\nUse subfixer --help for more info''')

if fix_persian:
with open(input, 'r') as f:
lines = f.read()
with open(input, "rb") as f:
lines = f.read()

sub_title_fixer = SubtitleFixer()
sub_title_fixer = SubtitleFixer()

lines = sub_title_fixer.decode_string(lines)
lines = sub_title_fixer.decode_string(lines)

write_file_name = input[:-4] + '_fixed.srt'
write_file_name = input[:-4] + "_fixed.srt"

if output:
write_file_name = output
with open(write_file_name, 'w') as f:
f.write(lines.encode('utf-8'))
if output:
write_file_name = output
with open(write_file_name, "wb") as f:
f.write(lines.encode("utf-8"))

click.echo("%s Persian fixed" % input)
click.echo("New subtitle is on : %s" % write_file_name)

click.echo('%s Persian fixed' % input)
click.echo('New subtitle is on : %s' % write_file_name)

if shift:
new_lines = []
with open(input, 'r') as f:
with open(input, "r") as f:
for line in f.readlines():
line = line[:-2] # removes '\r\n' from line
line = line[:-2] # removes "\r\n" from line
if is_time_string(line):
times = line.split(' --> ') # split up the two times
times = line.split(" --> ") # split up the two times
new_times = []
for t in times:
new_times.append(process_time_string(t, shift))
line = new_times[0] + ' --> ' + new_times[1]
new_lines.append(line + '\r\n') # adds back in '\r\n'
line = new_times[0] + " --> " + new_times[1]
new_lines.append(line + "\r\n") # adds back in "\r\n"

write_file_name = input[:-4] + '_fixed.srt'
write_file_name = input[:-4] + "_fixed.srt"

if output:
write_file_name = output
with open(write_file_name, 'w') as f:
with open(write_file_name, "w") as f:
for line in new_lines:
f.write(line)

click.echo('%s Time shift done for ' % input)
click.echo('New subtitle is on : %s' % write_file_name)
click.echo("%s Time shift done for " % input)
click.echo("New subtitle is on : %s" % write_file_name)


if __name__ == "__main__":
cli()