Compare commits

...

14 Commits

20 changed files with 351 additions and 74 deletions
+1 -1
View File
@@ -224,7 +224,7 @@ class SubZeroAgent(object):
whack_missing_parts(scanned_video_part_map)
if downloaded_subtitles:
save_subtitles(scanned_video_part_map, downloaded_subtitles)
save_subtitles(scanned_video_part_map, downloaded_subtitles, mods=config.default_mods)
track_usage("Subtitle", "refreshed", "download", 1)
for video, video_subtitles in downloaded_subtitles.items():
+1 -1
View File
@@ -15,7 +15,7 @@ from support.helpers import timestamp, pad_title
from support.config import config
from support.lib import Plex
from support.storage import reset_storage, log_storage
from support.background import scheduler
from support.scheduler import scheduler
@route(PREFIX + '/advanced')
+109 -7
View File
@@ -1,17 +1,23 @@
# coding=utf-8
import os
import traceback
from babelfish import Language
from subzero.constants import PREFIX
from menu_helpers import debounce, SubFolderObjectContainer, default_thumb, add_ignore_options, get_item_task_data, \
set_refresh_menu_state
from refresh_item import RefreshItem
from support.helpers import timestamp, cast_bool, df, get_language
from support.items import get_item_kind_from_rating_key, get_item
from support.items import get_item_kind_from_rating_key, get_item, get_current_sub
from support.plex_media import get_plex_metadata, scan_videos
from support.lib import Plex
from support.storage import get_subtitle_storage
from support.storage import get_subtitle_storage, save_subtitles
from support.config import config
from support.background import scheduler
from support.scheduler import scheduler
from subliminal_patch import PatchedSubtitle as Subtitle
from subzero.modification import registry as mod_registry
@route(PREFIX + '/item/{rating_key}/actions')
@@ -89,12 +95,12 @@ def ItemDetailsMenu(rating_key, title=None, base_title=None, item_title=None, ra
current_sub.score, current_sub.storage_type)
oc.add(DirectoryObject(
key=Callback(ListAvailableSubsForItemMenu, rating_key=rating_key, part_id=part_id, title=title,
item_title=item_title, language=lang, current_id=current_sub_id,
key=Callback(SubtitleOptionsMenu, rating_key=rating_key, part_id=part_id, title=title,
item_title=item_title, language=lang, language_name=lang.name, current_id=current_sub_id,
item_type=plex_item.type, filename=filename, current_data=summary,
randomize=timestamp(), current_provider=current_sub_provider_name,
current_score=current_score),
title=u"List %s subtitles" % lang.name,
title=u"Actions for %s subtitle" % lang.name,
summary=summary
))
@@ -103,10 +109,106 @@ def ItemDetailsMenu(rating_key, title=None, base_title=None, item_title=None, ra
return oc
@route(PREFIX + '/item/current_sub/{rating_key}/{part_id}', force=bool)
@debounce
def SubtitleOptionsMenu(**kwargs):
oc = SubFolderObjectContainer(title2=kwargs["title"], replace_parent=True)
rating_key = kwargs["rating_key"]
part_id = kwargs["part_id"]
language = kwargs["language"]
current_sub, stored_subs, storage = get_current_sub(rating_key, part_id, language)
kwargs.pop("randomize")
oc.add(DirectoryObject(
key=Callback(ItemDetailsMenu, rating_key=kwargs["rating_key"], item_title=kwargs["item_title"],
title=kwargs["title"], randomize=timestamp()),
title=u"Back to: %s" % kwargs["title"],
summary=kwargs["current_data"],
thumb=default_thumb
))
oc.add(DirectoryObject(
key=Callback(ListAvailableSubsForItemMenu, randomize=timestamp(), **kwargs),
title=u"List %s subtitles" % kwargs["language_name"],
summary=kwargs["current_data"]
))
if current_sub:
oc.add(DirectoryObject(
key=Callback(SubtitleModificationsMenu, randomize=timestamp(), **kwargs),
title=u"Modify %s subtitle" % kwargs["language_name"],
summary=u"Currently applied mods: %s" % (", ".join(current_sub.mods) if current_sub.mods else "none")
))
return oc
@route(PREFIX + '/item/sub_mods/{rating_key}/{part_id}', force=bool)
@debounce
def SubtitleModificationsMenu(**kwargs):
rating_key = kwargs["rating_key"]
part_id = kwargs["part_id"]
language = kwargs["language"]
current_sub, stored_subs, storage = get_current_sub(rating_key, part_id, language)
kwargs.pop("randomize")
oc = SubFolderObjectContainer(title2=kwargs["title"], replace_parent=True)
for identifier, mod in mod_registry.mods.iteritems():
oc.add(DirectoryObject(
key=Callback(SubtitleApplyMod, mod_identifier=identifier, randomize=timestamp(), **kwargs),
title=mod.description
))
oc.add(DirectoryObject(
key=Callback(SubtitleApplyMod, mod_identifier=None, randomize=timestamp(), **kwargs),
title="Restore original version",
summary=u"Currently applied mods: %s" % (", ".join(current_sub.mods) if current_sub.mods else "none")
))
return oc
@route(PREFIX + '/item/sub_add_mod/{rating_key}/{part_id}/{mod_identifier}', force=bool)
@debounce
def SubtitleApplyMod(mod_identifier=None, **kwargs):
if mod_identifier is not None and mod_identifier not in mod_registry.mods:
raise NotImplementedError
rating_key = kwargs["rating_key"]
part_id = kwargs["part_id"]
lang_a2 = kwargs["language"]
item_type = kwargs["item_type"]
language = Language.fromietf(lang_a2)
current_sub, stored_subs, storage = get_current_sub(rating_key, part_id, language)
current_sub.add_mod(mod_identifier)
storage.save(stored_subs)
metadata = get_plex_metadata(rating_key, part_id, item_type)
scanned_parts = scan_videos([metadata], kind="series" if item_type == "episode" else "movie", ignore_all=True)
video, plex_part = scanned_parts.items()[0]
subtitle = Subtitle(language, mods=current_sub.mods)
subtitle.content = current_sub.content
subtitle.plex_media_fps = plex_part.fps
subtitle.page_link = "modify subtitles with: %s" % (", ".join(current_sub.mods) if current_sub.mods else "none")
subtitle.language = language
try:
save_subtitles(scanned_parts, {video: [subtitle]}, mode="m", bare_save=True)
Log.Debug("Modified %s subtitle for: %s:%s with: %s", language.name, rating_key, part_id,
", ".join(current_sub.mods) if current_sub.mods else "none")
except:
Log.Error("Something went wrong when modifying subtitle: %s", traceback.format_exc())
kwargs.pop("randomize")
return SubtitleModificationsMenu(randomize=timestamp(), **kwargs)
@route(PREFIX + '/item/search/{rating_key}/{part_id}', force=bool)
@debounce
def ListAvailableSubsForItemMenu(rating_key=None, part_id=None, title=None, item_title=None, filename=None,
item_type="episode", language=None, force=False, current_id=None, current_data=None,
item_type="episode", language=None, language_name=None, force=False, current_id=None,
current_data=None,
current_provider=None, current_score=None, randomize=None):
assert rating_key, part_id
+1 -1
View File
@@ -3,7 +3,7 @@
from subzero.constants import PREFIX, TITLE, ART
from support.config import config
from support.helpers import pad_title, timestamp, df
from support.background import scheduler
from support.scheduler import scheduler
from support.ignore import ignore_list
from support.items import get_item_thumb, get_on_deck_items, get_all_items, get_items_info
from menu_helpers import main_icon, debounce, SubFolderObjectContainer, default_thumb, dig_tree, add_ignore_options
+1 -1
View File
@@ -9,7 +9,7 @@ from menu_helpers import add_ignore_options, dig_tree, set_refresh_menu_state, \
from main import fatality, IgnoreMenu
from advanced import DispatchRestart
from subzero.constants import ART, PREFIX, DEPENDENCY_MODULE_NAMES
from support.background import scheduler
from support.scheduler import scheduler
from support.config import config
from support.helpers import timestamp, df
from support.ignore import ignore_list
+1 -1
View File
@@ -8,7 +8,7 @@ from support.ignore import ignore_list
from support.lib import get_intent
from support.config import config
from subzero.constants import ICON_SUB, ICON
from support.background import scheduler
from support.scheduler import scheduler
default_thumb = R(ICON_SUB)
main_icon = ICON if not config.is_development else "icon-dev.jpg"
+2 -2
View File
@@ -32,9 +32,9 @@ import missing_subtitles
sys.modules["support.missing_subtitles"] = missing_subtitles
import background
import scheduler
sys.modules["support.background"] = background
sys.modules["support.scheduler"] = scheduler
import tasks
+11
View File
@@ -67,12 +67,14 @@ class Config(object):
notify_executable = None
sections = None
enabled_sections = None
remove_hi = False
enforce_encoding = False
chmod = None
forced_only = False
exotic_ext = False
treat_und_as_first = False
ext_match_strictness = False
default_mods = None
use_activities = False
activity_mode = None
@@ -106,12 +108,14 @@ class Config(object):
self.enabled_sections = self.check_enabled_sections()
self.permissions_ok = self.check_permissions()
self.notify_executable = self.check_notify_executable()
self.remove_hi = cast_bool(Prefs['subtitles.remove_hi'])
self.enforce_encoding = cast_bool(Prefs['subtitles.enforce_encoding'])
self.chmod = self.check_chmod()
self.forced_only = cast_bool(Prefs["subtitles.only_foreign"])
self.exotic_ext = cast_bool(Prefs["subtitles.scan.exotic_ext"])
self.treat_und_as_first = cast_bool(Prefs["subtitles.language.treat_und_as_first"])
self.ext_match_strictness = self.determine_ext_sub_strictness()
self.default_mods = self.get_default_mods()
self.initialized = True
def set_log_paths(self):
@@ -404,6 +408,13 @@ class Config(object):
return "loose"
return "strict"
def get_default_mods(self):
mods = []
if self.remove_hi:
mods.append("remove_HI")
return mods
def set_activity_modes(self):
val = Prefs["activity.on_playback"]
if val == "never":
+10
View File
@@ -283,3 +283,13 @@ def refresh_item(rating_key, force=False, timeout=8000, refresh_kind=None, paren
for key in refresh:
Log.Info("%s item %s", "Refreshing" if not force else "Forced-refreshing", key)
Plex["library/metadata"].refresh(key)
def get_current_sub(rating_key, part_id, language):
from support.storage import get_subtitle_storage
item = get_item(rating_key)
subtitle_storage = get_subtitle_storage()
stored_subs = subtitle_storage.load_or_new(item)
current_sub = stored_subs.get_any(part_id, language)
return current_sub, stored_subs, subtitle_storage
+27 -5
View File
@@ -6,16 +6,17 @@ import pprint
import copy
import subliminal
from items import get_item
from subzero.subtitle_storage import StoredSubtitlesManager
from subtitlehelpers import force_utf8
from config import config
from helpers import notify_executable, get_title_for_video_metadata, cast_bool, force_unicode
from plex_media import PMSMediaProxy
from support.items import get_item
get_subtitle_storage = lambda: StoredSubtitlesManager(Data, get_item)
def get_subtitle_storage():
return StoredSubtitlesManager(Data, get_item)
def whack_missing_parts(scanned_video_part_map, existing_parts=None):
@@ -156,9 +157,29 @@ def save_subtitles_to_metadata(videos, subtitles):
return True
def save_subtitles(scanned_video_part_map, downloaded_subtitles, mode="a"):
def save_subtitles(scanned_video_part_map, downloaded_subtitles, mode="a", bare_save=False, mods=None):
"""
:param scanned_video_part_map:
:param downloaded_subtitles:
:param mode:
:param bare_save: don't trigger anything; don't store information
:param mods: enabled mods
:return:
"""
meta_fallback = False
save_successful = False
if mods:
for video, video_subtitles in downloaded_subtitles.items():
if not video_subtitles:
continue
for subtitle in video_subtitles:
Log.Info("Applying mods: %s to %s", mods, subtitle)
subtitle.mods = mods
subtitle.plex_media_fps = video.fps
storage = "metadata"
if Prefs['subtitles.save.filesystem']:
storage = "filesystem"
@@ -180,8 +201,9 @@ def save_subtitles(scanned_video_part_map, downloaded_subtitles, mode="a"):
Log.Debug("Using metadata as subtitle storage")
save_successful = save_subtitles_to_metadata(scanned_video_part_map, downloaded_subtitles)
if save_successful and config.notify_executable:
if not bare_save and save_successful and config.notify_executable:
notify_executable(config.notify_executable, scanned_video_part_map, downloaded_subtitles, storage)
store_subtitle_info(scanned_video_part_map, downloaded_subtitles, storage, mode=mode)
if not bare_save:
store_subtitle_info(scanned_video_part_map, downloaded_subtitles, storage, mode=mode)
+1 -1
View File
@@ -11,7 +11,7 @@ from subliminal import list_subtitles as list_all_subtitles
from babelfish import Language
from missing_subtitles import items_get_all_missing_subs, refresh_item
from background import scheduler
from scheduler import scheduler
from storage import save_subtitles, whack_missing_parts, get_subtitle_storage
from support.config import config
from support.items import get_recent_items, is_ignored, get_item
+6
View File
@@ -395,6 +395,12 @@
],
"default": "don't prefer"
},
{
"id": "subtitles.remove_hi",
"label": "Remove Hearing Impaired tags from downloaded subtitles",
"type": "bool",
"default": "true"
},
{
"id": "subtitles.enforce_encoding",
"label": "Normalize subtitle encoding to UTF-8",
+2 -2
View File
@@ -13,7 +13,7 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>2.0.0.9</string>
<string>2.0.0.10</string>
<key>PlexFrameworkVersion</key>
<string>2</string>
<key>PlexPluginClass</key>
@@ -32,7 +32,7 @@
&lt;h1&gt;Sub-Zero for Plex&lt;/h1&gt;&lt;i&gt;Subtitles done right&lt;/i&gt;
Version 2.0.0.9 DEV
Version 2.0.0.10 DEV
Originally based on @bramwalet's awesome &lt;a href=&quot;https://github.com/bramwalet/Subliminal.bundle&quot;&gt;Subliminal.bundle&lt;/a&gt;
@@ -515,7 +515,7 @@ def save_subtitles(video, subtitles, single=False, directory=None, encoding=None
# save normalized subtitle if encoder or no encoding is given
if has_encoder or encoding is None:
content = encode_with(subtitle.text) if has_encoder else subtitle.content
content = encode_with(subtitle.get_modified_text()) if has_encoder else subtitle.get_modified_content()
with io.open(subtitle_path, 'wb') as f:
f.write(content)
@@ -530,7 +530,7 @@ def save_subtitles(video, subtitles, single=False, directory=None, encoding=None
# save subtitle if encoding given
if encoding is not None:
with io.open(subtitle_path, 'w', encoding=encoding) as f:
f.write(subtitle.text)
f.write(subtitle.get_modified_text())
# change chmod if requested
if chmod:
@@ -74,7 +74,7 @@ class OpenSubtitlesProvider(ProviderRetryMixin, _OpenSubtitlesProvider):
logger.info("Only searching for foreign/forced subtitles")
super(OpenSubtitlesProvider, self).__init__()
self.server = ServerProxy('https://api.opensubtitles.org/xml-rpc', TimeoutSafeTransport(10))
self.server = ServerProxy('https://api.opensubtitles.org/xml-rpc', TimeoutSafeTransport(4))
def initialize(self):
logger.info('Logging in')
@@ -8,6 +8,7 @@ import pysrt
import pysubs2
from bs4 import UnicodeDammit
from subliminal import Subtitle
from subzero.modification import SubtitleModifications
logger = logging.getLogger(__name__)
@@ -17,6 +18,13 @@ class PatchedSubtitle(Subtitle):
release_info = None
matches = None
hash_verifiable = False
mods = None
plex_media_fps = None
def __init__(self, language, hearing_impaired=False, page_link=None, encoding=None, mods=None):
super(PatchedSubtitle, self).__init__(language, hearing_impaired=hearing_impaired, page_link=page_link,
encoding=encoding)
self.mods = mods
def __repr__(self):
return '<%s %r [%s]>' % (
@@ -126,4 +134,30 @@ class PatchedSubtitle(Subtitle):
logger.exception("Couldn't convert subtitle %s to .srt format", self)
return False
return True
return True
def get_modified_content(self):
"""
:param language:
:param fps:
:return: string
"""
if not self.mods:
return self.content
encoding = self.guess_encoding()
submods = SubtitleModifications()
submods.load(content=self.text, fps=self.plex_media_fps)
submods.modify(*self.mods)
return submods.to_string("srt", encoding=encoding).encode(encoding=encoding)
def get_modified_text(self):
"""
:param language:
:param fps:
:return: unicode
"""
content = self.get_modified_content()
encoding = self.guess_encoding()
return content.decode(encoding=encoding)
+16 -4
View File
@@ -1,8 +1,20 @@
# coding=utf-8
from subzero.modification import SubMod, HearingImpaired
import sys
import logging
submod = SubMod("test.srt")
submod.modify(HearingImpaired)
logger = logging.getLogger(__name__)
print submod.f.to_string("srt")
from subzero.modification import SubMod
fn = sys.argv[1]
debug = "--debug" in sys.argv
if debug:
logging.basicConfig(level=logging.DEBUG)
submod = SubMod(debug=debug)
submod.load(fn)
submod.modify("remove_HI")
#print submod.f.to_string("srt")
+112 -33
View File
@@ -2,6 +2,7 @@
import re
import traceback
from collections import OrderedDict
import pysubs2
import logging
@@ -10,7 +11,19 @@ logger = logging.getLogger(__name__)
class SubtitleModifications(object):
def __init__(self, fn=None, content=None, fps=None):
debug = False
def __init__(self, debug=False):
self.debug = debug
def load(self, fn=None, content=None, fps=None):
"""
:param fn: filename
:param content: unicode
:param fps:
:return:
"""
try:
if fn:
self.f = pysubs2.load(fn, fps=fps)
@@ -29,19 +42,29 @@ class SubtitleModifications(object):
def modify(self, *mods):
new_f = []
for line in self.f:
for mod in mods:
new_content = mod.modify(line.text)
if not new_content:
logger.debug("deleting %s", line)
continue
applied_mods = []
for identifier in mods:
if identifier in registry.mods:
mod = registry.mods[identifier]
line.text = new_content
new_f.append(line)
# don't bother reapplying exclusive mods multiple times
if mod.exclusive and identifier in applied_mods:
continue
new_content = mod.modify(line.text, debug=self.debug)
if not new_content:
if self.debug:
logger.debug("%s: deleting %s", identifier, line)
continue
line.text = new_content
new_f.append(line)
applied_mods.append(identifier)
self.f.events = new_f
def to_string(self, format="srt"):
return self.f.to_string(format)
def to_string(self, format="srt", encoding="utf-8"):
return self.f.to_string(format, encoding=encoding)
def save(self, fn):
self.f.save(fn)
@@ -50,21 +73,54 @@ class SubtitleModifications(object):
SubMod = SubtitleModifications
class SubtitleModRegistry(object):
mods = None
mods_available = None
def __init__(self):
self.mods = OrderedDict()
self.mods_available = []
def register(self, mod):
self.mods[mod.identifier] = mod
self.mods_available.append(mod.identifier)
registry = SubtitleModRegistry()
class Processor(object):
"""
Processor base class
"""
name = None
def __init__(self, name=None):
self.name = name
@property
def info(self):
return self.name
def process(self, content):
return content
def __repr__(self):
return "Processor <%s %s>" % (self.__class__.__name__, self.info)
def __str__(self):
return repr(self)
def __unicode__(self):
return unicode(repr(self))
class StringProcessor(Processor):
"""
String replacement processor base
"""
def __init__(self, search, replace):
def __init__(self, search, replace, name=None):
super(StringProcessor, self).__init__(name=name)
self.search = search
self.replace = replace
@@ -79,11 +135,12 @@ class ReProcessor(Processor):
pattern = None
replace_with = None
def __init__(self, pattern, replace_with):
def __init__(self, pattern, replace_with, name=None):
super(ReProcessor, self).__init__(name=name)
self.pattern = pattern
self.replace_with = replace_with
def process(self, content):
def process(self, content, debug=False):
return self.pattern.sub(self.replace_with, content)
@@ -92,10 +149,10 @@ class NReProcessor(ReProcessor):
Single line regex processor
"""
def process(self, content):
def process(self, content, debug=False):
lines = []
for line in content.split(r"\N"):
a = super(NReProcessor, self).process(line)
a = super(NReProcessor, self).process(line, debug=debug)
if not a:
continue
lines.append(a)
@@ -103,37 +160,49 @@ class NReProcessor(ReProcessor):
class SubtitleModification(object):
identifier = None
description = None
exclusive = False
pre_processors = []
processors = []
post_processors = []
@classmethod
def _process(cls, content, processors):
def _process(cls, content, processors, debug=False):
if not content:
return
new_content = content
for processor in processors:
new_content = processor.process(new_content)
old_content = new_content
new_content = processor.process(new_content, debug=debug)
if not new_content:
if debug:
logger.debug("Processor returned empty line: %s", processor)
break
if debug:
if old_content == new_content:
continue
logger.debug("%s: %s -> %s", processor, old_content, new_content)
return new_content
@classmethod
def pre_process(cls, content):
return cls._process(content, cls.pre_processors)
def pre_process(cls, content, debug=False):
return cls._process(content, cls.pre_processors, debug=debug)
@classmethod
def process(cls, content):
return cls._process(content, cls.processors)
def process(cls, content, debug=False):
return cls._process(content, cls.processors, debug=debug)
@classmethod
def post_process(cls, content):
return cls._process(content, cls.post_processors)
def post_process(cls, content, debug=False):
return cls._process(content, cls.post_processors, debug=debug)
@classmethod
def modify(cls, content):
def modify(cls, content, debug=False):
new_content = content
for method in ("pre_process", "process", "post_process"):
new_content = getattr(cls, method)(new_content)
new_content = getattr(cls, method)(new_content, debug=debug)
return new_content
@@ -141,27 +210,37 @@ class SubtitleModification(object):
class SubtitleTextModification(SubtitleModification):
post_processors = [
# empty tag
ReProcessor(re.compile(r'(<[A-z]+[^>]*>)[\s.,-_!?]+(</[A-z]>)'), ""),
ReProcessor(re.compile(r'({\\\w+1})[\s.,-_!?]+({\\\w+0})'), "", name="empty_tag"),
# empty line (needed?)
ReProcessor(re.compile(r'(?m)^\s+$'), ""),
NReProcessor(re.compile(r'^\s+$'), "", name="empty_line"),
# empty dash line (needed?)
ReProcessor(re.compile(r'(?m)(^[\s]*[\-]+[\s]*)$'), ""),
NReProcessor(re.compile(r'(^[\s]*[\-]+[\s]*)$'), "", name="empty_dash_line"),
# clean whitespace at start and end
ReProcessor(re.compile(r'^\s*([^\s]+)\s*$'), r"\1"),
ReProcessor(re.compile(r'^\s*([^\s]+)\s*$'), r"\1", name="surrounding_whitespace"),
]
class HearingImpaired(SubtitleTextModification):
identifier = "remove_HI"
description = "Remove Hearing Impaired tags"
exclusive = True
processors = [
# brackets
ReProcessor(re.compile(r'(?sux)[([{].+[)\]}]'), ""),
NReProcessor(re.compile(r'(?sux)[([].+[)\]]'), "", name="HI_brackets"),
# text before colon (and possible dash in front)
ReProcessor(re.compile(r'(?mu)(^[A-z\-]+[\w\s]*:[^0-9{2}][\s]*)'), ""),
NReProcessor(re.compile(r'(?u)(^[A-z\-]+[\w\s]*:[^0-9{2}][\s]*)'), "", name="HI_before_colon"),
# all caps line (at least 3 chars
NReProcessor(re.compile(r'(?mu)(^[A-Z\.\-_]{3,}$)'), ""),
# all caps line (at least 3 chars)
NReProcessor(re.compile(r'(?u)(^[A-Z]{3,}$)'), "", name="HI_all_caps"),
# dash in front
NReProcessor(re.compile(r'(?u)^\s*-\s*'), "", name="HI_starting_dash"),
]
registry.register(HearingImpaired)
@@ -6,7 +6,6 @@ import logging
import traceback
from constants import mode_map
from modification import SubtitleModifications
logger = logging.getLogger(__name__)
@@ -22,7 +21,8 @@ class StoredSubtitle(object):
content = None
mods = None
def __init__(self, score, storage_type, hash, provider_name, id, date_added=None, mode="a", content=None):
def __init__(self, score, storage_type, hash, provider_name, id, date_added=None, mode="a", content=None,
mods=None):
self.score = int(score)
self.storage_type = storage_type
self.hash = hash
@@ -31,19 +31,20 @@ class StoredSubtitle(object):
self.date_added = date_added or datetime.datetime.now()
self.mode = mode
self.content = content
self.mods = []
self.mods = mods or []
def add_mod(self, identifier):
self.mods = self.mods or []
if identifier is None:
self.mods = []
return
self.mods.append(identifier)
@property
def mode_verbose(self):
return mode_map.get(self.mode, "Unknown")
def get_modified_content(self, fps=None):
if not self.mods:
return self.content
submods = SubtitleModifications(content=self.content, fps=fps)
submods.modify(*self.mods)
return submods.to_string("srt")
class StoredVideoSubtitles(object):
"""
@@ -80,7 +81,7 @@ class StoredVideoSubtitles(object):
sub_key = self.get_sub_key(subtitle.provider_name, subtitle.id)
subs[sub_key] = StoredSubtitle(subtitle.score, storage_type, hashlib.md5(subtitle.content).hexdigest(),
subtitle.provider_name, subtitle.id, date_added=date_added, mode=mode,
content=subtitle.content)
content=subtitle.content, mods=subtitle.mods)
subs["current"] = sub_key
return True