add generic subtitle_id to Subtitle class; skip whacking parts directly after sub storage for now; remove necessity of trigger argument for skipping duplicate views; add generic home button;
This commit is contained in:
@@ -6,11 +6,14 @@ import operator
|
||||
import logger
|
||||
import os
|
||||
import traceback
|
||||
import subliminal
|
||||
import subliminal_patch
|
||||
|
||||
from subliminal_patch.patch_api import list_all_subtitles
|
||||
from subliminal.api import download_subtitles
|
||||
from babelfish import Language
|
||||
from menu_helpers import add_ignore_options, dig_tree, set_refresh_menu_state, \
|
||||
should_display_ignore, enable_channel_wrapper, default_thumb, debounce
|
||||
should_display_ignore, enable_channel_wrapper, default_thumb, debounce, SZObjectContainer
|
||||
from subliminal_patch.patch_subtitle import compute_score
|
||||
from subzero.constants import TITLE, ART, ICON, PREFIX, PLUGIN_IDENTIFIER, DEPENDENCY_MODULE_NAMES
|
||||
from support.background import scheduler
|
||||
@@ -44,8 +47,8 @@ def fatality(randomize=None, force_title=None, header=None, message=None, only_r
|
||||
"""
|
||||
subzero main menu
|
||||
"""
|
||||
title = force_title if force_title is not None else config.full_version
|
||||
oc = ObjectContainer(title1=title, title2=None, header=unicode(header) if header else header, message=message, no_history=no_history,
|
||||
title = config.full_version#force_title if force_title is not None else config.full_version
|
||||
oc = ObjectContainer(title1=title, title2=title, header=unicode(header) if header else title, message=message, no_history=no_history,
|
||||
replace_parent=replace_parent, no_cache=True)
|
||||
|
||||
if not config.permissions_ok and config.missing_permissions:
|
||||
@@ -74,7 +77,7 @@ def fatality(randomize=None, force_title=None, header=None, message=None, only_r
|
||||
summary="Shows the current on deck items and allows you to individually (force-) refresh their metadata/subtitles."
|
||||
))
|
||||
oc.add(DirectoryObject(
|
||||
key=Callback(RecentlyAddedMenu),
|
||||
key=Callback(RecentlyAddedMenu, randomize=timestamp()),
|
||||
title="Items with missing subtitles",
|
||||
summary="Shows the items honoring the configured 'Item age to be considered recent'-setting (%s)"
|
||||
" and allowing you to individually (force-) refresh their metadata/subtitles. " % Prefs["scheduler.item_is_recent_age"]
|
||||
@@ -138,7 +141,8 @@ def OnDeckMenu(message=None):
|
||||
|
||||
|
||||
@route(PREFIX + '/recent')
|
||||
def RecentlyAddedMenu(message=None):
|
||||
@debounce
|
||||
def RecentlyAddedMenu(message=None, randomize=None):
|
||||
"""
|
||||
displays the recently added items with missing subtitles
|
||||
:param message:
|
||||
@@ -148,7 +152,7 @@ def RecentlyAddedMenu(message=None):
|
||||
|
||||
|
||||
def recentItemsMenu(title, base_title=None):
|
||||
oc = ObjectContainer(title2=title, no_cache=True, no_history=True)
|
||||
oc = SZObjectContainer(title2=title, no_cache=True, no_history=True)
|
||||
recent_items = get_recent_items()
|
||||
if recent_items:
|
||||
missing_items = items_get_all_missing_subs(recent_items)
|
||||
@@ -174,7 +178,7 @@ def mergedItemsMenu(title, itemGetter, itemGetterKwArgs=None, base_title=None, *
|
||||
:param kwargs:
|
||||
:return:
|
||||
"""
|
||||
oc = ObjectContainer(title2=title, no_cache=True, no_history=True)
|
||||
oc = SZObjectContainer(title2=title, no_cache=True, no_history=True)
|
||||
items = itemGetter(*args, **kwargs)
|
||||
|
||||
for kind, title, item_id, deeper, item in items:
|
||||
@@ -212,7 +216,7 @@ def IgnoreMenu(kind, rating_key, title=None, sure=False, todo="not_set"):
|
||||
"""
|
||||
is_ignored = rating_key in ignore_list[kind]
|
||||
if not sure:
|
||||
oc = ObjectContainer(no_history=True, replace_parent=True, title1="%s %s %s %s the ignore list" % (
|
||||
oc = SZObjectContainer(no_history=True, replace_parent=True, title1="%s %s %s %s the ignore list" % (
|
||||
"Add" if not is_ignored else "Remove", ignore_list.verbose(kind), title, "to" if not is_ignored else "from"), title2="Are you sure?")
|
||||
oc.add(DirectoryObject(
|
||||
key=Callback(IgnoreMenu, kind=kind, rating_key=rating_key, title=title, sure=True, todo="add" if not is_ignored else "remove"),
|
||||
@@ -257,7 +261,7 @@ def SectionsMenu():
|
||||
"""
|
||||
items = get_all_items("sections")
|
||||
|
||||
return dig_tree(ObjectContainer(title2="Sections", no_cache=True, no_history=True), items, None,
|
||||
return dig_tree(SZObjectContainer(title2="Sections", no_cache=True, no_history=True), items, None,
|
||||
menu_determination_callback=determine_section_display, pass_kwargs={"base_title": "Sections"},
|
||||
fill_args={"title": "section_title"})
|
||||
|
||||
@@ -280,7 +284,7 @@ def SectionMenu(rating_key, title=None, base_title=None, section_title=None, ign
|
||||
|
||||
section_title = title
|
||||
title = base_title + " > " + title
|
||||
oc = ObjectContainer(title2=title, no_cache=True, no_history=True)
|
||||
oc = SZObjectContainer(title2=title, no_cache=True, no_history=True)
|
||||
if ignore_options:
|
||||
add_ignore_options(oc, "sections", title=section_title, rating_key=rating_key, callback_menu=IgnoreMenu)
|
||||
|
||||
@@ -304,7 +308,7 @@ def SectionFirstLetterMenu(rating_key, title=None, base_title=None, section_titl
|
||||
kind, deeper = get_items_info(items)
|
||||
|
||||
title = unicode(title)
|
||||
oc = ObjectContainer(title2=section_title, no_cache=True, no_history=True)
|
||||
oc = SZObjectContainer(title2=section_title, no_cache=True, no_history=True)
|
||||
title = base_title + " > " + title
|
||||
add_ignore_options(oc, "sections", title=section_title, rating_key=rating_key, callback_menu=IgnoreMenu)
|
||||
|
||||
@@ -329,7 +333,7 @@ def FirstLetterMetadataMenu(rating_key, key, title=None, base_title=None, displa
|
||||
:return:
|
||||
"""
|
||||
title = base_title + " > " + unicode(title)
|
||||
oc = ObjectContainer(title2=title, no_cache=True, no_history=True)
|
||||
oc = SZObjectContainer(title2=title, no_cache=True, no_history=True)
|
||||
|
||||
items = get_all_items(key="first_character", value=[rating_key, key], base="library/sections", flat=False)
|
||||
kind, deeper = get_items_info(items)
|
||||
@@ -354,7 +358,7 @@ def MetadataMenu(rating_key, title=None, base_title=None, display_items=False, p
|
||||
title = unicode(title)
|
||||
item_title = title
|
||||
title = base_title + " > " + title
|
||||
oc = ObjectContainer(title2=title, no_cache=True, no_history=True)
|
||||
oc = SZObjectContainer(title2=title, no_cache=True, no_history=True)
|
||||
|
||||
current_kind = get_item_kind_from_rating_key(rating_key)
|
||||
|
||||
@@ -394,7 +398,7 @@ def MetadataMenu(rating_key, title=None, base_title=None, display_items=False, p
|
||||
|
||||
@route(PREFIX + '/ignore_list')
|
||||
def IgnoreListMenu():
|
||||
oc = ObjectContainer(title2="Ignore list", replace_parent=True)
|
||||
oc = SZObjectContainer(title2="Ignore list", replace_parent=True)
|
||||
for key in ignore_list.key_order:
|
||||
values = ignore_list[key]
|
||||
for value in values:
|
||||
@@ -403,6 +407,7 @@ def IgnoreListMenu():
|
||||
|
||||
|
||||
@route(PREFIX + '/item/{rating_key}/actions')
|
||||
@debounce
|
||||
def ItemDetailsMenu(rating_key, title=None, base_title=None, item_title=None, randomize=None):
|
||||
"""
|
||||
displays the item details menu of an item that doesn't contain any deeper tree, such as a movie or an episode
|
||||
@@ -418,7 +423,7 @@ def ItemDetailsMenu(rating_key, title=None, base_title=None, item_title=None, ra
|
||||
|
||||
timeout = 30
|
||||
|
||||
oc = ObjectContainer(title2=title, replace_parent=True)
|
||||
oc = SZObjectContainer(title2=title, replace_parent=True)
|
||||
oc.add(DirectoryObject(
|
||||
key=Callback(RefreshItem, rating_key=rating_key, item_title=item_title, randomize=timestamp(),
|
||||
timeout=timeout*1000),
|
||||
@@ -457,6 +462,7 @@ def ItemDetailsMenu(rating_key, title=None, base_title=None, item_title=None, ra
|
||||
# try getting current subtitle information for that language
|
||||
current_subtitle_key = sub_data_for_lang.get("current", (None, None))
|
||||
current_sub_provider_name, current_sub_id = current_subtitle_key
|
||||
current_sub_link = None
|
||||
|
||||
legacy_storage = False
|
||||
|
||||
@@ -474,6 +480,7 @@ def ItemDetailsMenu(rating_key, title=None, base_title=None, item_title=None, ra
|
||||
summary = u"No current subtitle in storage"
|
||||
if current_sub_provider_name:
|
||||
current_subtitle = sub_part_data[lang_short][current_subtitle_key]
|
||||
current_sub_link = current_subtitle["link"]
|
||||
|
||||
summary = u"Current subtitle%s: %s (added: %s), Language: %s, Score: %i, Storage: %s, From: %s" % \
|
||||
(u" (legacy/inaccurate)" if legacy_storage else "", current_sub_provider_name,
|
||||
@@ -482,8 +489,8 @@ def ItemDetailsMenu(rating_key, title=None, base_title=None, item_title=None, ra
|
||||
|
||||
oc.add(DirectoryObject(
|
||||
key=Callback(TriggerListAvailableSubsForItem, rating_key=rating_key, part_id=part.id, title=title,
|
||||
item_title=item_title, language=lang_short,
|
||||
item_type=plex_item.type, filename=filename),
|
||||
item_title=item_title, language=lang_short, current_link=current_sub_link,
|
||||
item_type=plex_item.type, filename=filename, randomize=timestamp()),
|
||||
title=u"Available subtitles for: %s, %s" % (lang_short, filename),
|
||||
summary=summary
|
||||
))
|
||||
@@ -499,13 +506,16 @@ MANUAL_SUB_SEARCH = {}
|
||||
@route(PREFIX + '/item/search/{rating_key}/{part_id}')
|
||||
@debounce
|
||||
def TriggerListAvailableSubsForItem(rating_key=None, part_id=None, title=None, item_title=None, filename=None,
|
||||
item_type="episode", language=None, force=False, trigger=True):
|
||||
item_type="episode", language=None, force=False, current_link=None,
|
||||
randomize=None):
|
||||
assert rating_key, part_id
|
||||
if not trigger:
|
||||
return
|
||||
|
||||
#config.init_subliminal_patches()
|
||||
plex_item = list(Plex["library"].metadata(rating_key))[0]
|
||||
|
||||
#fixme: woot
|
||||
subliminal.video.Episode.scores["addic7ed_boost"] = int(Prefs['provider.addic7ed.boost_by'])
|
||||
|
||||
# find current part
|
||||
current_part = None
|
||||
for part in plex_item.media.parts:
|
||||
@@ -564,40 +574,52 @@ def TriggerListAvailableSubsForItem(rating_key=None, part_id=None, title=None, i
|
||||
subtitles.append(subtitle)
|
||||
|
||||
print subtitles
|
||||
oc = SZObjectContainer(title2=title, replace_parent=True)
|
||||
oc.add(DirectoryObject(
|
||||
key=Callback(ItemDetailsMenu, rating_key=rating_key, item_title=item_title, randomize=timestamp()),
|
||||
title=u"Back to %s" % title,
|
||||
summary="",
|
||||
thumb=default_thumb
|
||||
))
|
||||
print current_link
|
||||
for subtitle in subtitles:
|
||||
oc.add(DirectoryObject(
|
||||
key=Callback(RefreshItem, rating_key=rating_key, item_title=item_title, randomize=timestamp()),
|
||||
title=u"%s: %s, score: %s; %s" % ("Available" if current_link != subtitle.page_link else "Current",
|
||||
subtitle.provider_name, subtitle.score, subtitle.subtitle_id),
|
||||
summary="Refreshes the item, possibly picking up new subtitles on disk",
|
||||
thumb=default_thumb
|
||||
))
|
||||
|
||||
return ItemDetailsMenu(rating_key, randomize=timestamp(), title=title, item_title=item_title)
|
||||
return oc
|
||||
|
||||
|
||||
@route(PREFIX + '/item/{rating_key}')
|
||||
@debounce
|
||||
def RefreshItem(rating_key=None, item_title=None, force=False, refresh_kind=None,
|
||||
previous_rating_key=None, timeout=8000, randomize=None, trigger=True):
|
||||
previous_rating_key=None, timeout=8000, randomize=None):
|
||||
assert rating_key
|
||||
header = " "
|
||||
if trigger:
|
||||
set_refresh_menu_state(u"Triggering %sRefresh for %s" % ("Force-" if force else "", item_title))
|
||||
Log.Info("Triggering %srefresh of item %s, \"%s\" (timeout: %s)", "" if not force else "force-", rating_key,
|
||||
item_title, timeout)
|
||||
Thread.Create(refresh_item, rating_key=rating_key, force=force, refresh_kind=refresh_kind,
|
||||
parent_rating_key=previous_rating_key, timeout=int(timeout))
|
||||
header = u"%s of item %s triggered" % ("Refresh" if not force else "Forced-refresh", rating_key)
|
||||
set_refresh_menu_state(u"Triggering %sRefresh for %s" % ("Force-" if force else "", item_title))
|
||||
Log.Info("Triggering %srefresh of item %s, \"%s\" (timeout: %s)", "" if not force else "force-", rating_key,
|
||||
item_title, timeout)
|
||||
Thread.Create(refresh_item, rating_key=rating_key, force=force, refresh_kind=refresh_kind,
|
||||
parent_rating_key=previous_rating_key, timeout=int(timeout))
|
||||
header = u"%s of item %s triggered" % ("Refresh" if not force else "Forced-refresh", rating_key)
|
||||
return fatality(randomize=timestamp(), header=header, replace_parent=True)
|
||||
|
||||
|
||||
@route(PREFIX + '/missing/refresh')
|
||||
@debounce
|
||||
def RefreshMissing(randomize=None, trigger=True):
|
||||
header = " "
|
||||
if trigger:
|
||||
Thread.CreateTimer(1.0, lambda: scheduler.run_task("searchAllRecentlyAddedMissing"))
|
||||
header = "Refresh of recently added items with missing subtitles triggered"
|
||||
def RefreshMissing(randomize=None):
|
||||
Thread.CreateTimer(1.0, lambda: scheduler.run_task("searchAllRecentlyAddedMissing"))
|
||||
header = "Refresh of recently added items with missing subtitles triggered"
|
||||
return fatality(header=header, replace_parent=True)
|
||||
|
||||
|
||||
@route(PREFIX + '/advanced')
|
||||
def AdvancedMenu(randomize=None, header=None, message=None):
|
||||
oc = ObjectContainer(header=header or "Internal stuff, pay attention!", message=message, no_cache=True, no_history=True,
|
||||
replace_parent=True, title2="Advanced")
|
||||
oc = SZObjectContainer(header=header or "Internal stuff, pay attention!", message=message, no_cache=True, no_history=True,
|
||||
replace_parent=False, title2="Advanced")
|
||||
|
||||
oc.add(DirectoryObject(
|
||||
key=Callback(TriggerRestart, randomize=timestamp()),
|
||||
@@ -677,10 +699,9 @@ def DispatchRestart():
|
||||
|
||||
@route(PREFIX + '/advanced/restart/trigger')
|
||||
@debounce
|
||||
def TriggerRestart(randomize=None, trigger=True):
|
||||
if trigger:
|
||||
set_refresh_menu_state("Restarting the plugin")
|
||||
DispatchRestart()
|
||||
def TriggerRestart(randomize=None):
|
||||
set_refresh_menu_state("Restarting the plugin")
|
||||
DispatchRestart()
|
||||
return fatality(header="Restart triggered, please wait about 5 seconds", force_title=" ", only_refresh=True, replace_parent=True,
|
||||
no_history=True, randomize=timestamp())
|
||||
|
||||
@@ -693,7 +714,7 @@ def Restart():
|
||||
@route(PREFIX + '/storage/reset', sure=bool)
|
||||
def ResetStorage(key, randomize=None, sure=False):
|
||||
if not sure:
|
||||
oc = ObjectContainer(no_history=True, title1="Reset subtitle storage", title2="Are you sure?")
|
||||
oc = SZObjectContainer(no_history=True, title1="Reset subtitle storage", title2="Are you sure?")
|
||||
oc.add(DirectoryObject(
|
||||
key=Callback(ResetStorage, key=key, sure=True, randomize=timestamp()),
|
||||
title=pad_title("Are you really sure?"),
|
||||
|
||||
@@ -131,8 +131,8 @@ def debounce(func):
|
||||
def wrap(*args, **kwargs):
|
||||
if "randomize" in kwargs:
|
||||
if ([func] + list(args), kwargs) in debouncer:
|
||||
kwargs["trigger"] = False
|
||||
Log.Debug("not triggering %s twice with %s, %s" % (func, args, kwargs))
|
||||
return ObjectContainer()
|
||||
else:
|
||||
debouncer.add([func] + list(args), kwargs)
|
||||
return func(*args, **kwargs)
|
||||
@@ -140,3 +140,16 @@ def debounce(func):
|
||||
return wrap
|
||||
|
||||
|
||||
class SZObjectContainer(ObjectContainer):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(SZObjectContainer, self).__init__(*args, **kwargs)
|
||||
from interface.menu import fatality
|
||||
from support.helpers import pad_title, timestamp
|
||||
self.add(DirectoryObject(
|
||||
key=Callback(fatality, force_title=" ", randomize=timestamp()),
|
||||
title=pad_title("<< Back to home"),
|
||||
summary="Current state: %s; Last state: %s" % (
|
||||
(Dict["current_refresh_state"] or "Idle") if "current_refresh_state" in Dict else "Idle",
|
||||
(Dict["last_refresh_state"] or "None") if "last_refresh_state" in Dict else "None"
|
||||
)
|
||||
))
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import datetime
|
||||
import pprint
|
||||
import copy
|
||||
|
||||
from helpers import get_video_display_title
|
||||
|
||||
@@ -32,10 +33,13 @@ def whack_missing_parts(scanned_video_part_map, existing_parts=None):
|
||||
if video.id not in Dict["subs"]:
|
||||
continue
|
||||
|
||||
for part_id in Dict["subs"][video.id].keys():
|
||||
parts = Dict["subs"][video.id].keys()
|
||||
|
||||
for part_id in parts:
|
||||
if part_id not in existing_parts:
|
||||
Log.Info("Whacking part %s in internal storage of video %s (%s, %s)", part_id, video.id,
|
||||
repr(existing_parts), repr(parts))
|
||||
del Dict["subs"][video.id][part_id]
|
||||
Log.Info("Whacking part %s in internal storage of video %s", part_id, video.id)
|
||||
whacked_parts = True
|
||||
|
||||
if whacked_parts:
|
||||
@@ -49,16 +53,14 @@ def store_subtitle_info(scanned_video_part_map, downloaded_subtitles, storage_ty
|
||||
if "subs" not in Dict:
|
||||
Dict["subs"] = {}
|
||||
|
||||
storage = Dict["subs"]
|
||||
|
||||
existing_parts = []
|
||||
for video, video_subtitles in downloaded_subtitles.items():
|
||||
part = scanned_video_part_map[video]
|
||||
|
||||
if video.id not in storage:
|
||||
storage[video.id] = {}
|
||||
if video.id not in Dict["subs"]:
|
||||
Dict["subs"][video.id] = {}
|
||||
|
||||
video_dict = storage[video.id]
|
||||
video_dict = copy.deepcopy(Dict["subs"][video.id])
|
||||
if part.id not in video_dict:
|
||||
video_dict[part.id] = {}
|
||||
|
||||
@@ -87,8 +89,12 @@ def store_subtitle_info(scanned_video_part_map, downloaded_subtitles, storage_ty
|
||||
date_added=datetime.datetime.now(), title=title)
|
||||
lang_dict["current"] = sub_key
|
||||
|
||||
if existing_parts:
|
||||
whack_missing_parts(scanned_video_part_map, existing_parts=existing_parts)
|
||||
Dict["subs"][video.id] = video_dict
|
||||
|
||||
#Dict.Save()
|
||||
|
||||
#if existing_parts:
|
||||
# whack_missing_parts(scanned_video_part_map, existing_parts=existing_parts)
|
||||
Dict.Save()
|
||||
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ setattr(OpenSubtitlesSubtitle, "__bases__", (PatchedSubtitle,))
|
||||
from .patch_provider_pool import PatchedProviderPool
|
||||
from .patch_video import patched_search_external_subtitles, scan_video
|
||||
from .patch_providers import addic7ed, podnapisi, tvsubtitles, opensubtitles
|
||||
from .patch_api import save_subtitles
|
||||
from .patch_api import save_subtitles, list_all_subtitles
|
||||
|
||||
# patch subliminal's ProviderPool
|
||||
subliminal.api.ProviderPool = PatchedProviderPool
|
||||
@@ -27,6 +27,8 @@ subliminal.api.ProviderPool = PatchedProviderPool
|
||||
# patch subliminal's save_subtitles function
|
||||
subliminal.api.save_subtitles = save_subtitles
|
||||
|
||||
subliminal.api.list_all_subtitles = list_all_subtitles
|
||||
|
||||
# patch subliminal's subtitle classes
|
||||
def subtitleRepr(self):
|
||||
link = self.page_link
|
||||
|
||||
@@ -19,6 +19,7 @@ USE_BOOST = False
|
||||
class PatchedAddic7edSubtitle(Addic7edSubtitle):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(PatchedAddic7edSubtitle, self).__init__(*args, **kwargs)
|
||||
self.subtitle_id = kwargs.get("download_link")
|
||||
|
||||
def get_matches(self, video, hearing_impaired=False):
|
||||
matches = super(PatchedAddic7edSubtitle, self).get_matches(video, hearing_impaired=hearing_impaired)
|
||||
|
||||
@@ -2,12 +2,30 @@
|
||||
|
||||
import logging
|
||||
import io
|
||||
import re
|
||||
try:
|
||||
from lxml import etree
|
||||
except ImportError:
|
||||
try:
|
||||
import xml.etree.cElementTree as etree
|
||||
except ImportError:
|
||||
import xml.etree.ElementTree as etree
|
||||
from babelfish import Language
|
||||
from zipfile import ZipFile
|
||||
from subliminal.providers.podnapisi import PodnapisiProvider, fix_line_ending, ProviderError
|
||||
from subliminal.providers.podnapisi import PodnapisiProvider, PodnapisiSubtitle, fix_line_ending, ProviderError
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PatchedPodnapisiSubtitle(PodnapisiSubtitle):
|
||||
provider_name = 'podnapisi'
|
||||
|
||||
def __init__(self, language, hearing_impaired, page_link, pid, releases, title, season=None, episode=None,
|
||||
year=None):
|
||||
super(PodnapisiSubtitle, self).__init__(language, hearing_impaired, page_link)
|
||||
self.subtitle_id = pid
|
||||
|
||||
|
||||
class PatchedPodnapisiProvider(PodnapisiProvider):
|
||||
def download_subtitle(self, subtitle):
|
||||
# download as a zip
|
||||
@@ -21,3 +39,69 @@ class PatchedPodnapisiProvider(PodnapisiProvider):
|
||||
raise ProviderError('More than one file to unzip')
|
||||
|
||||
subtitle.content = fix_line_ending(zf.read(zf.namelist()[0]))
|
||||
|
||||
|
||||
def query(self, language, keyword, season=None, episode=None, year=None):
|
||||
# set parameters, see http://www.podnapisi.net/forum/viewtopic.php?f=62&t=26164#p212652
|
||||
params = {'sXML': 1, 'sL': str(language), 'sK': keyword}
|
||||
is_episode = False
|
||||
if season and episode:
|
||||
is_episode = True
|
||||
params['sTS'] = season
|
||||
params['sTE'] = episode
|
||||
if year:
|
||||
params['sY'] = year
|
||||
|
||||
# loop over paginated results
|
||||
logger.info('Searching subtitles %r', params)
|
||||
subtitles = []
|
||||
pids = set()
|
||||
while True:
|
||||
# query the server
|
||||
xml = etree.fromstring(self.session.get(self.server_url + 'search/old', params=params, timeout=10).content)
|
||||
|
||||
# exit if no results
|
||||
if not int(xml.find('pagination/results').text):
|
||||
logger.debug('No subtitles found')
|
||||
break
|
||||
|
||||
# loop over subtitles
|
||||
for subtitle_xml in xml.findall('subtitle'):
|
||||
# read xml elements
|
||||
language = Language.fromietf(subtitle_xml.find('language').text)
|
||||
hearing_impaired = 'n' in (subtitle_xml.find('flags').text or '')
|
||||
page_link = subtitle_xml.find('url').text
|
||||
pid = subtitle_xml.find('pid').text
|
||||
releases = []
|
||||
if subtitle_xml.find('release').text:
|
||||
for release in subtitle_xml.find('release').text.split():
|
||||
releases.append(re.sub(r'\.+$', '', release)) # remove trailing dots
|
||||
title = subtitle_xml.find('title').text
|
||||
season = int(subtitle_xml.find('tvSeason').text)
|
||||
episode = int(subtitle_xml.find('tvEpisode').text)
|
||||
year = int(subtitle_xml.find('year').text)
|
||||
|
||||
if is_episode:
|
||||
subtitle = PatchedPodnapisiSubtitle(language, hearing_impaired, page_link, pid, releases, title,
|
||||
season=season, episode=episode, year=year)
|
||||
else:
|
||||
subtitle = PatchedPodnapisiSubtitle(language, hearing_impaired, page_link, pid, releases, title,
|
||||
year=year)
|
||||
|
||||
# ignore duplicates, see http://www.podnapisi.net/forum/viewtopic.php?f=62&t=26164&start=10#p213321
|
||||
if pid in pids:
|
||||
continue
|
||||
|
||||
logger.debug('Found subtitle %r', subtitle)
|
||||
subtitles.append(subtitle)
|
||||
pids.add(pid)
|
||||
|
||||
# stop on last page
|
||||
if int(xml.find('pagination/current').text) >= int(xml.find('pagination/count').text):
|
||||
break
|
||||
|
||||
# increment current page
|
||||
params['page'] = int(xml.find('pagination/current').text) + 1
|
||||
logger.debug('Getting page %d', params['page'])
|
||||
|
||||
return subtitles
|
||||
@@ -68,6 +68,7 @@ def compute_score(matches, video, scores=None):
|
||||
|
||||
class PatchedSubtitle(Subtitle):
|
||||
storage_path = None
|
||||
subtitle_id = None
|
||||
|
||||
def guess_encoding(self):
|
||||
"""Guess encoding using the language, falling back on chardet.
|
||||
|
||||
Reference in New Issue
Block a user