Compare commits

...

26 Commits

Author SHA1 Message Date
panni 775e2cca47 Merge remote-tracking branch 'origin/master' 2019-08-09 03:13:46 +02:00
panni 7cb2486d3e release 2.6.5.3124 2019-08-09 03:13:34 +02:00
panni 02a3ecc9fe prepare for release 2019-08-09 03:11:55 +02:00
panni 54435398af bump dev 2019-08-08 15:09:04 +02:00
panni ffc42883de core: extract embedded/menu: fix detection of unknown streams; don't use unknown streams if a known language was previously found 2019-08-08 14:30:29 +02:00
panni 0cf0371a43 core: language: use replacement map from bazarr 2019-08-06 18:04:34 +02:00
panni f5156bcea7 providers: titlovi: fix matching 2019-07-27 03:10:08 +02:00
panni efdf3b2c9d core: http: fallback to default DNS when normal resolving fails; fixes #657 2019-07-27 02:57:35 +02:00
panni c3d3163392 providers: subscene: fix unknown language code error when "empty" result is returned 2019-07-05 13:56:21 +02:00
panni c91d5ca483 providers: subscene: add support for pt-BR (based on https://github.com/Diaoul/subliminal/pull/740/commits/b22cf08a5d0e7082b0dc6c0de8cc764f01233625) 2019-07-05 13:55:52 +02:00
panni 5f0982970d docker/bazarr compat 2019-07-05 03:22:06 +02:00
panni ee05da70f4 providers: subscene: explicitly set account filters for languages 2019-06-23 15:26:41 +02:00
panni 04c283c48d providers: subscene: limit alternative searches to 3; set throttle to 8 2019-06-23 04:24:18 +02:00
panni 836945c95c providers: subscene: move login/cookies to initialization sequence 2019-06-22 16:45:31 +02:00
panni bd4c180c07 submod: generic: en: fix ";='s 2019-06-22 04:29:03 +02:00
pannal e1f5290365 Update README.md 2019-06-22 04:07:30 +02:00
panni eefffcfb1b back to dev 2019-06-22 04:06:10 +02:00
panni 9e088a5e9d release 2.6.5.3109 2019-06-22 04:05:37 +02:00
panni 317c02bf06 prepare next release 2019-06-22 04:04:22 +02:00
panni 22724c269c core: bazarr compat 2019-06-21 15:04:00 +02:00
panni 2a48782b6b core: bazarr compat 2019-06-21 15:00:35 +02:00
panni e7c3039fde providers: subscene: detect login availability; fallback to non year results if none found with year 2019-06-21 04:49:54 +02:00
panni 2afba02b59 bump dev 2019-06-21 04:17:15 +02:00
panni 94928c2930 providers: add Napisy24 (polish) 2019-06-21 04:16:46 +02:00
panni 2c25191291 providers: subscene: support logging in 2019-06-20 16:11:21 +02:00
panni ba2f3f2172 back to dev 2019-06-06 02:18:34 +02:00
20 changed files with 446 additions and 83 deletions
+35
View File
@@ -1,3 +1,38 @@
2.6.5.3109
subscene, addic7ed and titlovi
- either of those providers might impose a reCAPTCHA verification. In order to use those providers, please create an account at an AntiCaptcha service ([anti-captcha.com](http://getcaptchasolution.com/kkvviom7nh) or [deathbycaptcha.com](http://deathbycaptcha.com)), add funds, then supply your credentials/apikey in the configuration
Changelog
- providers: add Napisy24 (polish)
- providers: subscene: reduce provider load by possibly half
- providers: subscene: support logging in (username/password are now required)
- providers: subscene: fallback to non year results if none found with year
2.6.5.3099
subscene, addic7ed and titlovi
- either of those providers might impose a reCAPTCHA verification. In order to use those providers, please create an account at an AntiCaptcha service ([anti-captcha.com](http://getcaptchasolution.com/kkvviom7nh) or [deathbycaptcha.com](http://deathbycaptcha.com)), add funds, then supply your credentials/apikey in the configuration
Changelog
- core: allow system DNS again by putting "system" as the DNS
- providers: subscene: fix again (subscene, contact us please, so we can end this)
2.6.5.3092
subscene, addic7ed and titlovi
- either of those providers might impose a reCAPTCHA verification. In order to use those providers, please create an account at an AntiCaptcha service ([anti-captcha.com](http://getcaptchasolution.com/kkvviom7nh) or [deathbycaptcha.com](http://deathbycaptcha.com)), add funds, then supply your credentials/apikey in the configuration
Changelog
- providers: subscene: fix endpoint (hopefully for longer now)
- providers: subscene: don't search for season packs (broken for now; relieves 50% of server load on provider)
- providers: subscene: don't calculate video fn for now
- providers: argenteam: backport fixes from bazarr
- subtitle: try decoding with utf-16 by default as well (zho/farsi)
- submod: HI: remove music tags by default
- core: compat (bazarr): add env var SZ_KEEP_ENCODING to keep encoding of subtitles
2.6.5.3074
+5 -1
View File
@@ -119,19 +119,23 @@ def agent_extract_embedded(video_part_map):
for plexapi_part in get_all_parts(plexapi_item):
item_count = item_count + 1
used_one_unknown_stream = False
used_one_known_stream = False
for requested_language in config.lang_list:
skip_unknown = used_one_unknown_stream or used_one_known_stream
embedded_subs = stored_subs.get_by_provider(plexapi_part.id, requested_language, "embedded")
current = stored_subs.get_any(plexapi_part.id, requested_language) or \
requested_language in scanned_video.external_subtitle_languages
if not embedded_subs:
stream_data = get_embedded_subtitle_streams(plexapi_part, requested_language=requested_language,
skip_unknown=used_one_unknown_stream)
skip_unknown=skip_unknown)
if stream_data:
stream = stream_data[0]["stream"]
if stream_data[0]["is_unknown"]:
used_one_unknown_stream = True
else:
used_one_known_stream = True
to_extract.append(({scanned_video: part_info}, plexapi_part, str(stream.index),
str(requested_language), not current))
+8
View File
@@ -761,6 +761,7 @@ class Config(object):
return {'opensubtitles': cast_bool(Prefs['provider.opensubtitles.enabled']),
# 'thesubdb': Prefs['provider.thesubdb.enabled'],
'podnapisi': cast_bool(Prefs['provider.podnapisi.enabled']),
'napisy24': cast_bool(Prefs['provider.napisy24.enabled']),
'titlovi': cast_bool(Prefs['provider.titlovi.enabled']),
'addic7ed': cast_bool(Prefs['provider.addic7ed.enabled']) and self.has_anticaptcha,
'tvsubtitles': cast_bool(Prefs['provider.tvsubtitles.enabled']),
@@ -801,6 +802,7 @@ class Config(object):
providers["argenteam"] = False
providers["assrt"] = False
providers["subscene"] = False
providers["napisy24"] = False
providers_forced_off = dict(providers)
if not self.unrar and providers["legendastv"]:
@@ -864,8 +866,14 @@ class Config(object):
'only_foreign': self.forced_only,
'also_foreign': self.forced_also,
},
'napisy24': {
'username': Prefs['provider.napisy24.username'],
'password': Prefs['provider.napisy24.password'],
},
'subscene': {
'only_foreign': self.forced_only,
'username': Prefs['provider.subscene.username'],
'password': Prefs['provider.subscene.password'],
},
'legendastv': {'username': Prefs['provider.legendastv.username'],
'password': Prefs['provider.legendastv.password'],
+1 -1
View File
@@ -394,7 +394,7 @@ def get_language_from_stream(lang_code):
return Language.fromietf(lang)
elif lang:
try:
return language_from_stream(lang)
return language_from_stream(lang_code)
except LanguageError:
pass
+24 -10
View File
@@ -177,6 +177,7 @@ def get_all_parts(plex_item):
def get_embedded_subtitle_streams(part, requested_language=None, skip_duplicate_unknown=True, skip_unknown=False):
streams = []
streams_unknown = []
all_streams = []
has_unknown = False
found_requested_language = False
for stream in part.streams:
@@ -189,27 +190,40 @@ def get_embedded_subtitle_streams(part, requested_language=None, skip_duplicate_
is_unknown = False
found_requested_language = requested_language and requested_language == language
stream_data = None
if not language and config.treat_und_as_first:
if not language:
# only consider first unknown subtitle stream
if has_unknown and skip_duplicate_unknown:
continue
if requested_language and config.treat_und_as_first:
if has_unknown and skip_duplicate_unknown:
Log.Debug("skipping duplicate unknown")
continue
language = Language.rebuild(list(config.lang_list)[0], forced=is_forced)
language = Language.rebuild(list(config.lang_list)[0], forced=is_forced)
else:
language = Language("unk")
is_unknown = True
has_unknown = True
streams_unknown.append({"stream": stream, "is_unknown": is_unknown, "language": language,
"is_forced": is_forced})
stream_data = {"stream": stream, "is_unknown": is_unknown, "language": language,
"is_forced": is_forced}
streams_unknown.append(stream_data)
if not requested_language or found_requested_language:
streams.append({"stream": stream, "is_unknown": is_unknown, "language": language,
"is_forced": is_forced})
stream_data = {"stream": stream, "is_unknown": is_unknown, "language": language,
"is_forced": is_forced}
streams.append(stream_data)
if found_requested_language:
break
if streams_unknown and not found_requested_language and not skip_unknown:
streams = streams_unknown
if stream_data:
all_streams.append(stream_data)
if requested_language:
if streams_unknown and not found_requested_language and not skip_unknown:
streams = streams_unknown
else:
streams = all_streams
return streams
+34
View File
@@ -335,6 +335,26 @@
"type": "bool",
"default": "true"
},
{
"id": "provider.napisy24.enabled",
"label": "Provider: Enable Napisy24 (pl)",
"type": "bool",
"default": "false"
},
{
"id": "provider.napisy24.username",
"label": "Napisy24 Username",
"type": "text",
"default": ""
},
{
"id": "provider.napisy24.password",
"label": "Napisy24 Password",
"type": "text",
"option": "hidden",
"default": "",
"secure": "true"
},
{
"id": "provider.addic7ed.enabled",
"label": "Provider: Enable Addic7ed (needs AntiCaptcha)",
@@ -431,6 +451,20 @@
"type": "bool",
"default": "true"
},
{
"id": "provider.subscene.username",
"label": "SubScene Username",
"type": "text",
"default": ""
},
{
"id": "provider.subscene.password",
"label": "SubScene Password",
"type": "text",
"option": "hidden",
"default": "",
"secure": "true"
},
{
"id": "provider.supersubtitles.enabled",
"label": "Provider: Enable feliratok.info (Hungarian)",
+2 -2
View File
@@ -13,7 +13,7 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>2.6.5.3099</string>
<string>2.6.5.3124</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.6.5.3099
Version 2.6.5.3124
Originally based on @bramwalet's awesome &lt;a href=&quot;https://github.com/bramwalet/Subliminal.bundle&quot;&gt;Subliminal.bundle&lt;/a&gt;
@@ -12,6 +12,13 @@ from_subscene = {
'Malay': 'msa', 'Pashto': 'pus', 'Punjabi': 'pan', 'Swahili': 'swa'
}
from_subscene_with_country = {
'Brazillian Portuguese': ('por', 'BR')
}
to_subscene_with_country = {val: key for key, val in from_subscene_with_country.items()}
to_subscene = {v: k for k, v in from_subscene.items()}
exact_languages_alpha3 = [
@@ -34,12 +41,12 @@ language_ids = {
'mkd': 48, 'mal': 64, 'mni': 65, 'mon': 72, 'pus': 67, 'pol': 31,
'por': 32, 'pan': 66, 'rus': 34, 'srp': 35, 'sin': 58, 'slk': 36,
'slv': 37, 'som': 70, 'tgl': 53, 'tam': 59, 'tel': 63, 'tha': 40,
'tur': 41, 'ukr': 56, 'urd': 42, 'yor': 71
'tur': 41, 'ukr': 56, 'urd': 42, 'yor': 71, 'pt-BR': 4
}
# TODO: specify codes for unspecified_languages
unspecified_languages = [
'Big 5 code', 'Brazillian Portuguese', 'Bulgarian/ English',
'Big 5 code', 'Bulgarian/ English',
'Chinese BG code', 'Dutch/ English', 'English/ German',
'Hungarian/ English', 'Rohingya'
]
@@ -50,6 +57,8 @@ alpha3_of_code = {l.name: l.alpha3 for l in supported_languages}
supported_languages.update({Language(l) for l in to_subscene})
supported_languages.update({Language(lang, cr) for lang, cr in to_subscene_with_country})
class SubsceneConverter(LanguageReverseConverter):
codes = {l.name for l in supported_languages}
@@ -61,9 +70,15 @@ class SubsceneConverter(LanguageReverseConverter):
if alpha3 in to_subscene:
return to_subscene[alpha3]
if (alpha3, country) in to_subscene_with_country:
return to_subscene_with_country[(alpha3, country)]
raise ConfigurationError('Unsupported language for subscene: %s, %s, %s' % (alpha3, country, script))
def reverse(self, code):
if code in from_subscene_with_country:
return from_subscene_with_country[code]
if code in from_subscene:
return (from_subscene[code],)
@@ -473,7 +473,7 @@ if is_windows_special_path:
SZAsyncProviderPool = SZProviderPool
def scan_video(path, dont_use_actual_file=False, hints=None, providers=None, skip_hashing=False):
def scan_video(path, dont_use_actual_file=False, hints=None, providers=None, skip_hashing=False, hash_from=None):
"""Scan a video from a `path`.
patch:
@@ -538,28 +538,34 @@ def scan_video(path, dont_use_actual_file=False, hints=None, providers=None, ski
video.alternative_titles.append(alt_guess["title"])
logger.debug("Adding alternative title: %s", alt_guess["title"])
if dont_use_actual_file:
if dont_use_actual_file and not hash_from:
return video
# size and hashes
if not skip_hashing:
video.size = os.path.getsize(path)
hash_path = hash_from or path
video.size = os.path.getsize(hash_path)
if video.size > 10485760:
logger.debug('Size is %d', video.size)
osub_hash = None
if "opensubtitles" in providers:
video.hashes['opensubtitles'] = hash_opensubtitles(path)
video.hashes['opensubtitles'] = osub_hash = hash_opensubtitles(hash_path)
if "shooter" in providers:
video.hashes['shooter'] = hash_shooter(path)
video.hashes['shooter'] = hash_shooter(hash_path)
if "thesubdb" in providers:
video.hashes['thesubdb'] = hash_thesubdb(path)
video.hashes['thesubdb'] = hash_thesubdb(hash_path)
if "napiprojekt" in providers:
try:
video.hashes['napiprojekt'] = hash_napiprojekt(path)
video.hashes['napiprojekt'] = hash_napiprojekt(hash_path)
except MemoryError:
logger.warning(u"Couldn't compute napiprojekt hash for %s", path)
logger.warning(u"Couldn't compute napiprojekt hash for %s", hash_path)
if "napisy24" in providers:
# Napisy24 uses the same hash as opensubtitles
video.hashes['napisy24'] = osub_hash or hash_opensubtitles(hash_path)
logger.debug('Computed hashes %r', video.hashes)
else:
@@ -575,7 +581,7 @@ def _search_external_subtitles(path, languages=None, only_one=False, scandir_gen
subtitles = {}
_scandir = _scandir_generic if scandir_generic else scandir
for entry in _scandir(dirpath):
if not entry.name and not scandir_generic:
if (not entry.name or entry.name in ('\x0c', '$', ',', '\x7f')) and not scandir_generic:
logger.debug('Could not determine the name of the file, retrying with scandir_generic')
return _search_external_subtitles(path, languages, only_one, True)
if not entry.is_file(follow_symlinks=False):
@@ -354,7 +354,6 @@ def patch_create_connection():
return _orig_create_connection((ip, port), *args, **kwargs)
except dns.exception.DNSException:
logger.warning("DNS: Couldn't resolve %s with DNS: %s", host, custom_resolver.nameservers)
raise
logger.debug("DNS: Falling back to default DNS or IP on %s", host)
return _orig_create_connection((host, port), *args, **kwargs)
@@ -0,0 +1,124 @@
import logging
import os
from io import BytesIO
from zipfile import ZipFile
from requests import Session
from subliminal_patch.subtitle import Subtitle
from subliminal_patch.providers import Provider
from subliminal import __short_version__
from subliminal.exceptions import AuthenticationError, ConfigurationError
from subliminal.subtitle import fix_line_ending
from subzero.language import Language
logger = logging.getLogger(__name__)
class Napisy24Subtitle(Subtitle):
'''Napisy24 Subtitle.'''
provider_name = 'napisy24'
def __init__(self, language, hash, imdb_id, napis_id):
super(Napisy24Subtitle, self).__init__(language)
self.hash = hash
self.imdb_id = imdb_id
self.napis_id = napis_id
@property
def id(self):
return self.hash
def get_matches(self, video):
matches = set()
# hash
if 'napisy24' in video.hashes and video.hashes['napisy24'] == self.hash:
matches.add('hash')
# imdb_id
if video.imdb_id and self.imdb_id == video.imdb_id:
matches.add('imdb_id')
return matches
class Napisy24Provider(Provider):
'''Napisy24 Provider.'''
languages = {Language(l) for l in ['pol']}
required_hash = 'napisy24'
api_url = 'http://napisy24.pl/run/CheckSubAgent.php'
def __init__(self, username=None, password=None):
if all((username, password)):
self.username = username
self.password = password
else:
self.username = 'subliminal'
self.password = 'lanimilbus'
self.session = None
def initialize(self):
self.session = Session()
self.session.headers['User-Agent'] = 'Subliminal/%s' % __short_version__
self.session.headers['Content-Type'] = 'application/x-www-form-urlencoded'
def terminate(self):
self.session.close()
def query(self, language, size, name, hash):
params = {
'postAction': 'CheckSub',
'ua': self.username,
'ap': self.password,
'fs': size,
'fh': hash,
'fn': os.path.basename(name),
'n24pref': 1
}
response = self.session.post(self.api_url, data=params, timeout=10)
response.raise_for_status()
response_content = response.content.split(b'||', 1)
n24_data = response_content[0].decode()
if n24_data[:2] != 'OK':
if n24_data[:11] == 'login error':
raise AuthenticationError('Login failed')
logger.error('Unknown response: %s', response.content)
return None
n24_status = n24_data[:4]
if n24_status == 'OK-0':
logger.info('No subtitles found')
return None
subtitle_info = dict(p.split(':', 1) for p in n24_data.split('|')[1:])
logger.debug('Subtitle info: %s', subtitle_info)
if n24_status == 'OK-1':
logger.info('No subtitles found but got video info')
return None
elif n24_status == 'OK-2':
logger.info('Found subtitles')
elif n24_status == 'OK-3':
logger.info('Found subtitles but not from Napisy24 database')
return None
subtitle_content = response_content[1]
subtitle = Napisy24Subtitle(language, hash, 'tt%s' % subtitle_info['imdb'].zfill(7), subtitle_info['napisId'])
with ZipFile(BytesIO(subtitle_content)) as zf:
subtitle.content = fix_line_ending(zf.open(zf.namelist()[0]).read())
return subtitle
def list_subtitles(self, video, languages):
subtitles = [self.query(l, video.size, video.name, video.hashes['napisy24']) for l in languages]
return [s for s in subtitles if s is not None]
def download_subtitle(self, subtitle):
# there is no download step, content is already filled from listing subtitles
pass
@@ -4,24 +4,34 @@ import io
import logging
import os
import time
import traceback
import requests
import inflect
import re
import json
import HTMLParser
import urlparse
from zipfile import ZipFile
from babelfish import language_converters
from guessit import guessit
from dogpile.cache.api import NO_VALUE
from subliminal import Episode, ProviderError
from subliminal.exceptions import ConfigurationError, ServiceUnavailable
from subliminal.utils import sanitize_release_group
from subliminal.cache import region
from subliminal_patch.http import RetryingCFSession
from subliminal_patch.providers import Provider
from subliminal_patch.providers.mixins import ProviderSubtitleArchiveMixin
from subliminal_patch.subtitle import Subtitle, guess_matches
from subliminal_patch.converters.subscene import language_ids, supported_languages
from subscene_api.subscene import search, Subtitle as APISubtitle
from subscene_api.subscene import search, Subtitle as APISubtitle, SITE_DOMAIN
from subzero.language import Language
p = inflect.engine()
language_converters.register('subscene = subliminal_patch.converters.subscene:SubsceneConverter')
logger = logging.getLogger(__name__)
@@ -112,28 +122,106 @@ class SubsceneProvider(Provider, ProviderSubtitleArchiveMixin):
skip_wrong_fps = False
hearing_impaired_verifiable = True
only_foreign = False
username = None
password = None
search_throttle = 2 # seconds
search_throttle = 8 # seconds
def __init__(self, only_foreign=False, username=None, password=None):
if not all((username, password)):
raise ConfigurationError('Username and password must be specified')
def __init__(self, only_foreign=False):
self.only_foreign = only_foreign
self.username = username
self.password = password
def initialize(self):
logger.info("Creating session")
self.session = RetryingCFSession()
prev_cookies = region.get("subscene_cookies2")
if prev_cookies != NO_VALUE:
logger.debug("Re-using old subscene cookies: %r", prev_cookies)
self.session.cookies.update(prev_cookies)
else:
logger.debug("Logging in")
self.login()
def login(self):
r = self.session.get("https://subscene.com/account/login")
if "Server Error" in r.content:
logger.error("Login unavailable; Maintenance?")
raise ServiceUnavailable("Login unavailable; Maintenance?")
match = re.search(r"<script id='modelJson' type='application/json'>\s*(.+)\s*</script>", r.content)
if match:
h = HTMLParser.HTMLParser()
data = json.loads(h.unescape(match.group(1)))
login_url = urlparse.urljoin(data["siteUrl"], data["loginUrl"])
time.sleep(1.0)
r = self.session.post(login_url,
{
"username": self.username,
"password": self.password,
data["antiForgery"]["name"]: data["antiForgery"]["value"]
})
pep_content = re.search(r"<form method=\"post\" action=\"https://subscene\.com/\">"
r".+name=\"id_token\".+?value=\"(?P<id_token>.+?)\".*?"
r"access_token\".+?value=\"(?P<access_token>.+?)\".+?"
r"token_type.+?value=\"(?P<token_type>.+?)\".+?"
r"expires_in.+?value=\"(?P<expires_in>.+?)\".+?"
r"scope.+?value=\"(?P<scope>.+?)\".+?"
r"state.+?value=\"(?P<state>.+?)\".+?"
r"session_state.+?value=\"(?P<session_state>.+?)\"",
r.content, re.MULTILINE | re.DOTALL)
if pep_content:
r = self.session.post(SITE_DOMAIN, pep_content.groupdict())
try:
r.raise_for_status()
except Exception:
raise ProviderError("Something went wrong when trying to log in: %s", traceback.format_exc())
else:
cj = self.session.cookies.copy()
store_cks = ("scene", "idsrv", "idsrv.xsrf", "idsvr.clients", "idsvr.session", "idsvr.username")
for cn in self.session.cookies.iterkeys():
if cn not in store_cks:
del cj[cn]
logger.debug("Storing cookies: %r", cj)
region.set("subscene_cookies2", cj)
return
raise ProviderError("Something went wrong when trying to log in #1")
def terminate(self):
logger.info("Closing session")
self.session.close()
def _create_filters(self, languages):
self.filters = dict(HearingImpaired="2")
acc_filters = self.filters.copy()
if self.only_foreign:
self.filters["ForeignOnly"] = "True"
acc_filters["ForeignOnly"] = self.filters["ForeignOnly"].lower()
logger.info("Only searching for foreign/forced subtitles")
self.filters["LanguageFilter"] = ",".join((str(language_ids[l.alpha3]) for l in languages
if l.alpha3 in language_ids))
selected_ids = []
for l in languages:
lid = language_ids.get(l.basename, language_ids.get(l.alpha3, None))
if lid:
selected_ids.append(str(lid))
acc_filters["SelectedIds"] = selected_ids
self.filters["LanguageFilter"] = ",".join(acc_filters["SelectedIds"])
last_filters = region.get("subscene_filters")
if last_filters != acc_filters:
region.set("subscene_filters", acc_filters)
logger.debug("Setting account filters to %r", acc_filters)
self.session.post("https://u.subscene.com/filter", acc_filters, allow_redirects=False)
logger.debug("Filter created: '%s'" % self.filters)
@@ -176,7 +264,11 @@ class SubsceneProvider(Provider, ProviderSubtitleArchiveMixin):
def parse_results(self, video, film):
subtitles = []
for s in film.subtitles:
subtitle = SubsceneSubtitle.from_api(s)
try:
subtitle = SubsceneSubtitle.from_api(s)
except NotImplementedError, e:
logger.info(e)
continue
subtitle.asked_for_release_group = video.release_group
if isinstance(video, Episode):
subtitle.asked_for_episode = video.episode
@@ -189,10 +281,16 @@ class SubsceneProvider(Provider, ProviderSubtitleArchiveMixin):
return subtitles
def do_search(self, *args, **kwargs):
try:
return search(*args, **kwargs)
except requests.HTTPError:
region.delete("subscene_cookies2")
def query(self, video):
#vfn = get_video_filename(video)
# vfn = get_video_filename(video)
subtitles = []
#logger.debug(u"Searching for: %s", vfn)
# logger.debug(u"Searching for: %s", vfn)
# film = search(vfn, session=self.session)
#
# if film and film.subtitles:
@@ -201,16 +299,17 @@ class SubsceneProvider(Provider, ProviderSubtitleArchiveMixin):
# else:
# logger.debug('No release results found')
#time.sleep(self.search_throttle)
# time.sleep(self.search_throttle)
# re-search for episodes without explicit release name
if isinstance(video, Episode):
#term = u"%s S%02iE%02i" % (video.series, video.season, video.episode)
more_than_one = len([video.series] + video.alternative_series) > 1
for series in [video.series] + video.alternative_series:
titles = list(set([video.series] + video.alternative_series))[:2]
# term = u"%s S%02iE%02i" % (video.series, video.season, video.episode)
more_than_one = len(titles) > 1
for series in titles:
term = u"%s - %s Season" % (series, p.number_to_words("%sth" % video.season).capitalize())
logger.debug('Searching for alternative results: %s', term)
film = search(term, session=self.session, release=False, throttle=self.search_throttle)
film = self.do_search(term, session=self.session, release=False, throttle=self.search_throttle)
if film and film.subtitles:
logger.debug('Alternative results found: %s', len(film.subtitles))
subtitles += self.parse_results(video, film)
@@ -233,11 +332,12 @@ class SubsceneProvider(Provider, ProviderSubtitleArchiveMixin):
if more_than_one:
time.sleep(self.search_throttle)
else:
more_than_one = len([video.title] + video.alternative_titles) > 1
for title in [video.title] + video.alternative_titles:
logger.debug('Searching for movie results: %s', title)
film = search(title, year=video.year, session=self.session, limit_to=None, release=False,
throttle=self.search_throttle)
titles = list(set([video.title] + video.alternative_titles))[:2]
more_than_one = len(titles) > 1
for title in titles:
logger.debug('Searching for movie results: %r', title)
film = self.do_search(title, year=video.year, session=self.session, limit_to=None, release=False,
throttle=self.search_throttle)
if film and film.subtitles:
subtitles += self.parse_results(video, film)
if more_than_one:
@@ -226,7 +226,7 @@ class TitloviProvider(Provider, ProviderSubtitleArchiveMixin):
page_link = self.server_url + sub.a.attrs['href']
# subtitle language
_lang = sub.select_one('.lang')
match = lang_re.search(_lang.attrs.get('src', _lang.attrs.get('cfsrc', '')))
match = lang_re.search(_lang.attrs.get('src', _lang.attrs.get('data-cfsrc', '')))
if match:
try:
# decode language
+1 -1
View File
@@ -21,7 +21,7 @@ if debug:
logging.basicConfig(level=logging.DEBUG)
#sub = Subtitle(Language.fromietf("eng:forced"), mods=["common", "remove_HI", "OCR_fixes", "fix_uppercase", "shift_offset(ms=-500)", "shift_offset(ms=500)", "shift_offset(s=2,ms=800)"])
sub = Subtitle(Language.fromietf("eng:forced"), mods=["common", "remove_HI", "OCR_fixes", "fix_uppercase", "shift_offset(ms=0,s=1)"])
sub = Subtitle(Language.fromietf("eng"), mods=["common", "remove_HI", "OCR_fixes", "fix_uppercase", "shift_offset(ms=0,s=1)"])
sub.content = open(fn).read()
sub.normalize()
content = sub.get_modified_content(debug=True)
@@ -125,7 +125,7 @@ class Subtitle(object):
subtitles = []
for row in rows:
if row.td.a is not None:
if row.td.a is not None and row.td.get("class", ["lazy"])[0] != "empty":
subtitles.append(cls.from_row(row))
return subtitles
@@ -255,26 +255,39 @@ def get_first_film(soup, section, year=None, session=None):
url = SITE_DOMAIN + t.div.a.get("href")
break
if not url:
return
# fallback to non-year results
logger.info("Falling back to non-year results as year wasn't found (%s)", year)
url = SITE_DOMAIN + tag.findNext("ul").find("li").div.a.get("href")
return Film.from_url(url, session=session)
def find_endpoint(session, content=None):
endpoint = region.get("subscene_endpoint2")
if endpoint is NO_VALUE:
if not content:
content = session.get(SITE_DOMAIN).text
m = ENDPOINT_RE.search(content)
if m:
endpoint = m.group(1).strip()
logger.debug("Switching main endpoint to %s", endpoint)
region.set("subscene_endpoint2", endpoint)
return endpoint
def search(term, release=True, session=None, year=None, limit_to=SearchTypes.Exact, throttle=0):
# note to subscene: if you actually start to randomize the endpoint, we'll have to query your server even more
if release:
endpoint = "release"
else:
endpoint = region.get("subscene_endpoint2")
if endpoint is NO_VALUE:
ret = session.get(SITE_DOMAIN)
time.sleep(throttle)
m = ENDPOINT_RE.search(ret.text)
if m:
endpoint = m.group(1).strip()
logger.debug("Switching main endpoint to %s", endpoint)
region.set("subscene_endpoint2", endpoint)
endpoint = find_endpoint(session)
time.sleep(throttle)
if not endpoint:
logger.error("Couldn't find endpoint, exiting")
return
soup = soup_for("%s/subtitles/%s" % (SITE_DOMAIN, endpoint), data={"query": term},
session=session)
@@ -8,6 +8,25 @@ repl_map = {
"dk": "da",
"nld": "nl",
"english": "en",
"alb": "sq",
"arm": "hy",
"baq": "eu",
"bur": "my",
"chi": "zh",
"cze": "cs",
"dut": "nl",
"fre": "fr",
"geo": "ka",
"ger": "de",
"gre": "el",
"ice": "is",
"mac": "mk",
"mao": "mi",
"may": "ms",
"per": "fa",
"rum": "ro",
"slo": "sk",
"tib": "bo",
}
File diff suppressed because one or more lines are too long
@@ -36,6 +36,7 @@ SZ_FIX_DATA = {
u" l ": u" I ",
u"'sjust": u"'s just",
u"'tjust": u"'t just",
u"\";": u"'s",
},
"WholeWords": {
u"I'11": u"I'll",
+2 -2
View File
@@ -52,10 +52,10 @@ def set_existing_languages(video, video_info, external_subtitles=False, embedded
video.subtitle_languages.add(language)
def parse_video(fn, hints, skip_hashing=False, dry_run=False, providers=None):
def parse_video(fn, hints, skip_hashing=False, dry_run=False, providers=None, hash_from=None):
logger.debug("Parsing video: %s, hints: %s", os.path.basename(fn), hints)
return scan_video(fn, hints=hints, dont_use_actual_file=dry_run, providers=providers,
skip_hashing=skip_hashing)
skip_hashing=skip_hashing, hash_from=hash_from)
def refine_video(video, no_refining=False, refiner_settings=None):
+13 -22
View File
@@ -90,38 +90,29 @@ the.vbm, mmgoodnow, Vertig0ne, thliu78, tattoomees, ostman, count_confucius, ehe
## Changelog
2.6.5.3099
2.6.5.3124
subscene, addic7ed and titlovi
- either of those providers might impose a reCAPTCHA verification. In order to use those providers, please create an account at an AntiCaptcha service ([anti-captcha.com](http://getcaptchasolution.com/kkvviom7nh) or [deathbycaptcha.com](http://deathbycaptcha.com)), add funds, then supply your credentials/apikey in the configuration
Changelog
- core: allow system DNS again by putting "system" as the DNS
- providers: subscene: fix again (subscene, contact us please, so we can end this)
2.6.5.3092
subscene, addic7ed and titlovi
- either of those providers might impose a reCAPTCHA verification. In order to use those providers, please create an account at an AntiCaptcha service ([anti-captcha.com](http://getcaptchasolution.com/kkvviom7nh) or [deathbycaptcha.com](http://deathbycaptcha.com)), add funds, then supply your credentials/apikey in the configuration
Changelog
- providers: subscene: fix endpoint (hopefully for longer now)
- providers: subscene: don't search for season packs (broken for now; relieves 50% of server load on provider)
- providers: subscene: don't calculate video fn for now
- providers: argenteam: backport fixes from bazarr
- subtitle: try decoding with utf-16 by default as well (zho/farsi)
- submod: HI: remove music tags by default
- core: compat (bazarr): add env var SZ_KEEP_ENCODING to keep encoding of subtitles
- core: http: fallback to default DNS when normal resolving fails; fixes #657
- core: extract embedded/menu: fix detection of unknown streams; don't use unknown streams if a known language was previously found
- core: language: use replacement map from bazarr
- providers: titlovi: fix matching
- providers: subscene: fix unknown language code error when "empty" result is returned
- providers: subscene: add support for pt-BR (based on Diaoul/subliminal@b22cf08)
- providers: subscene: explicitly set account filters for languages
- providers: subscene: limit alternative searches to 3; set throttle to 8
- providers: subscene: move login/cookies to initialization sequence
- submod: generic: en: fix ";='s
[older changes](CHANGELOG.md)
Subtitles provided by [OpenSubtitles.org](http://www.opensubtitles.org/), [Podnapisi.NET](https://www.podnapisi.net/), [TVSubtitles.net](http://www.tvsubtitles.net/), [Addic7ed.com](http://www.addic7ed.com/), [Legendas TV](http://legendas.tv/), [Napi Projekt](http://www.napiprojekt.pl/), [Shooter](http://shooter.cn/), [Titlovi](http://titlovi.com), [aRGENTeaM](http://argenteam.net), [SubScene](https://subscene.com/), [Hosszupuska](http://hosszupuskasub.com/)
Subtitles provided by [OpenSubtitles.org](http://www.opensubtitles.org/), [Podnapisi.NET](https://www.podnapisi.net/), [TVSubtitles.net](http://www.tvsubtitles.net/), [Addic7ed.com](http://www.addic7ed.com/), [Legendas TV](http://legendas.tv/), [Napi Projekt](http://www.napiprojekt.pl/), [Shooter](http://shooter.cn/), [Titlovi](http://titlovi.com), [aRGENTeaM](http://argenteam.net), [SubScene](https://subscene.com/), [Hosszupuska](http://hosszupuskasub.com/), [Napisy24](https://napisy24.pl/)
[3rd party licenses](https://github.com/pannal/Sub-Zero.bundle/tree/master/Licenses)