Compare commits
12 Commits
i18n
...
2.6.5.3041
| Author | SHA1 | Date | |
|---|---|---|---|
| 4568e222d1 | |||
| 344025226a | |||
| f546fcffce | |||
| 068c2d4d00 | |||
| ccf5a902e5 | |||
| 8c72cf9057 | |||
| 1ce14aa231 | |||
| 643485b879 | |||
| 5b3d9f26be | |||
| 14f2f45f20 | |||
| 8ac6c9d7a7 | |||
| 237a47b8ed |
+3
-3
@@ -13,7 +13,7 @@
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>2.6.5.3023</string>
|
||||
<string>2.6.5.3041</string>
|
||||
<key>PlexFrameworkVersion</key>
|
||||
<string>2</string>
|
||||
<key>PlexPluginClass</key>
|
||||
@@ -23,7 +23,7 @@
|
||||
<key>PlexPluginConsoleLogging</key>
|
||||
<string>0</string>
|
||||
<key>PlexPluginDevMode</key>
|
||||
<string>1</string>
|
||||
<string>0</string>
|
||||
<key>PlexPluginCodePolicy</key>
|
||||
<!-- this allows channels to access some python methods which are otherwise blocked, as well as import external code libraries, and interact with the PMS HTTP API -->
|
||||
<string>Elevated</string>
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
<h1>Sub-Zero for Plex</h1><i>Subtitles done right</i>
|
||||
|
||||
Version 2.6.5.3023 DEV
|
||||
Version 2.6.5.3041
|
||||
|
||||
Originally based on @bramwalet's awesome <a href="https://github.com/bramwalet/Subliminal.bundle">Subliminal.bundle</a>
|
||||
|
||||
|
||||
@@ -84,6 +84,7 @@ class CloudflareScraper(Session):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.delay = kwargs.pop('delay', 8)
|
||||
self.debug = False
|
||||
self._was_cf = False
|
||||
self._ua = None
|
||||
self._hdrs = None
|
||||
|
||||
@@ -145,6 +146,7 @@ class CloudflareScraper(Session):
|
||||
# Check if Cloudflare anti-bot is on
|
||||
try:
|
||||
if self.is_cloudflare_challenge(resp):
|
||||
self._was_cf = True
|
||||
# Work around if the initial request is not a GET,
|
||||
# Superseed with a GET then re-request the orignal METHOD.
|
||||
if resp.request.method != 'GET':
|
||||
@@ -154,6 +156,7 @@ class CloudflareScraper(Session):
|
||||
resp = self.solve_cf_challenge(resp, **kwargs)
|
||||
except NeedsCaptchaException:
|
||||
# solve the captcha
|
||||
self._was_cf = True
|
||||
site_key = re.search(r'data-sitekey="(.+?)"', resp.content).group(1)
|
||||
challenge_s = re.search(r'type="hidden" name="s" value="(.+?)"', resp.content).group(1)
|
||||
challenge_ray = re.search(r'data-ray="(.+?)"', resp.content).group(1)
|
||||
@@ -165,13 +168,13 @@ class CloudflareScraper(Session):
|
||||
cookies=self.cookies.get_dict(),
|
||||
is_invisible=True)
|
||||
|
||||
logger.info("cf: Solving captcha")
|
||||
parsed_url = urlparse(resp.url)
|
||||
domain = parsed_url.netloc
|
||||
logger.info("cf: %s: Solving captcha", domain)
|
||||
result = pitcher.throw()
|
||||
if not result:
|
||||
raise Exception("cf: Couldn't solve captcha!")
|
||||
|
||||
parsed_url = urlparse(resp.url)
|
||||
domain = parsed_url.netloc
|
||||
submit_url = '{}://{}/cdn-cgi/l/chk_captcha'.format(parsed_url.scheme, domain)
|
||||
method = resp.request.method
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ class CFSession(CloudflareScraper):
|
||||
|
||||
cache_key = "cf_data2_%s" % domain
|
||||
|
||||
if not self.cookies.get("__cfduid", "", domain=domain):
|
||||
if not self.cookies.get("cf_clearance", "", domain=domain):
|
||||
cf_data = region.get(cache_key)
|
||||
if cf_data is not NO_VALUE:
|
||||
cf_cookies, user_agent, hdrs = cf_data
|
||||
@@ -80,14 +80,18 @@ class CFSession(CloudflareScraper):
|
||||
|
||||
ret = super(CFSession, self).request(method, url, *args, **kwargs)
|
||||
|
||||
try:
|
||||
cf_data = self.get_cf_live_tokens(domain)
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
if cf_data != region.get(cache_key) and cf_data[0]["__cfduid"] and cf_data[0]["cf_clearance"]:
|
||||
logger.debug("Storing cf data for %s: %s", domain, cf_data)
|
||||
region.set(cache_key, cf_data)
|
||||
if self._was_cf:
|
||||
self._was_cf = False
|
||||
logger.debug("We've hit CF, trying to store previous data")
|
||||
try:
|
||||
cf_data = self.get_cf_live_tokens(domain)
|
||||
except:
|
||||
logger.debug("Couldn't get CF live tokens for re-use. Cookies: %r", self.cookies)
|
||||
pass
|
||||
else:
|
||||
if cf_data != region.get(cache_key) and cf_data[0]["cf_clearance"]:
|
||||
logger.debug("Storing cf data for %s: %s", domain, cf_data)
|
||||
region.set(cache_key, cf_data)
|
||||
|
||||
return ret
|
||||
|
||||
@@ -101,10 +105,10 @@ class CFSession(CloudflareScraper):
|
||||
"Unable to find Cloudflare cookies. Does the site actually have "
|
||||
"Cloudflare IUAM (\"I'm Under Attack Mode\") enabled?")
|
||||
|
||||
return (OrderedDict([
|
||||
return (OrderedDict(filter(lambda x: x[1], [
|
||||
("__cfduid", self.cookies.get("__cfduid", "", domain=cookie_domain)),
|
||||
("cf_clearance", self.cookies.get("cf_clearance", "", domain=cookie_domain))
|
||||
]),
|
||||
])),
|
||||
self._ua, self._hdrs
|
||||
)
|
||||
|
||||
@@ -262,6 +266,7 @@ def patch_create_connection():
|
||||
if host in dns_cache:
|
||||
ip = dns_cache[host]
|
||||
logger.debug("DNS: Using %s=%s from cache", host, ip)
|
||||
return _orig_create_connection((ip, port), *args, **kwargs)
|
||||
else:
|
||||
try:
|
||||
ip = custom_resolver.query(host)[0].address
|
||||
|
||||
@@ -140,7 +140,7 @@ class TitloviProvider(Provider, ProviderSubtitleArchiveMixin):
|
||||
|
||||
def initialize(self):
|
||||
self.session = RetryingCFSession()
|
||||
load_verification("titlovi", self.session)
|
||||
#load_verification("titlovi", self.session)
|
||||
|
||||
def terminate(self):
|
||||
self.session.close()
|
||||
@@ -181,42 +181,8 @@ class TitloviProvider(Provider, ProviderSubtitleArchiveMixin):
|
||||
r = self.session.get(self.search_url, params=params, timeout=10)
|
||||
r.raise_for_status()
|
||||
except RequestException as e:
|
||||
captcha_passed = False
|
||||
if e.response.status_code == 403 and "data-sitekey" in e.response.content:
|
||||
logger.info('titlovi: Solving captcha. This might take a couple of minutes, but should only '
|
||||
'happen once every so often')
|
||||
|
||||
site_key = re.search(r'data-sitekey="(.+?)"', e.response.content).group(1)
|
||||
challenge_s = re.search(r'type="hidden" name="s" value="(.+?)"', e.response.content).group(1)
|
||||
challenge_ray = re.search(r'data-ray="(.+?)"', e.response.content).group(1)
|
||||
if not all([site_key, challenge_s, challenge_ray]):
|
||||
raise Exception("titlovi: Captcha site-key not found!")
|
||||
|
||||
pitcher = pitchers.get_pitcher()("titlovi", e.request.url, site_key,
|
||||
user_agent=self.session.headers["User-Agent"],
|
||||
cookies=self.session.cookies.get_dict(),
|
||||
is_invisible=True)
|
||||
|
||||
result = pitcher.throw()
|
||||
if not result:
|
||||
raise Exception("titlovi: Couldn't solve captcha!")
|
||||
|
||||
s_params = {
|
||||
"s": challenge_s,
|
||||
"id": challenge_ray,
|
||||
"g-recaptcha-response": result,
|
||||
}
|
||||
r = self.session.get(self.server_url + "/cdn-cgi/l/chk_captcha", params=s_params, timeout=10,
|
||||
allow_redirects=False)
|
||||
r.raise_for_status()
|
||||
r = self.session.get(self.search_url, params=params, timeout=10)
|
||||
r.raise_for_status()
|
||||
store_verification("titlovi", self.session)
|
||||
captcha_passed = True
|
||||
|
||||
if not captcha_passed:
|
||||
logger.exception('RequestException %s', e)
|
||||
break
|
||||
logger.exception('RequestException %s', e)
|
||||
break
|
||||
else:
|
||||
try:
|
||||
soup = BeautifulSoup(r.content, 'lxml')
|
||||
|
||||
@@ -16,8 +16,12 @@ Check out **[the Sub-Zero Wiki](https://github.com/pannal/Sub-Zero.bundle/wiki)*
|
||||
|
||||
---
|
||||
|
||||
## Helping development
|
||||
|
||||
If you like this, buy me a beer: <br>[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=G9VKR2B8PMNKG) <br>or become a Patreon starting at **1 $ / month** <br><a href="https://www.patreon.com/subzero_plex" target="_blank"><img src="http://www.wenspencer.com/wp-content/uploads/2017/02/patreon-button.png" height="42" /></a> <br>or use the OpenSubtitles Sub-Zero affiliate link to become VIP <br>**10€/year, ad-free subs, 1000 subs/day, no-cache *VIP* server**<br><a href="http://v.ht/osvip" target="_blank"><img src="https://static.opensubtitles.org/gfx/logo.gif" height="50" /></a>
|
||||
|
||||
If you register with an anti-captcha service and you decide to use [Anti-Captcha.com](http://getcaptchasolution.com/kkvviom7nh), you can use [this affiliate link](http://getcaptchasolution.com/kkvviom7nh) to help development.
|
||||
|
||||
## Introduction
|
||||
#### What's Sub-Zero?
|
||||
Sub-Zero is a metadata agent and interface-plugin at the same time, for the popular Plex Media Server environment.
|
||||
@@ -84,10 +88,20 @@ the.vbm, mmgoodnow, Vertig0ne, thliu78, tattoomees, ostman, count_confucius, ehe
|
||||
|
||||
## Changelog
|
||||
|
||||
2.6.5.3017
|
||||
2.6.5.3041
|
||||
|
||||
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 or deathbycaptcha.com), add funds, then supply your credentials/apikey in the configuration
|
||||
- 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: only reference guessed title if there actually is one
|
||||
core: cf: optimize
|
||||
core/config: add setting for one existing language to be enough, fixes #491
|
||||
core/compat: dns: support nameservers via ENV[dns_resolvers]; don't fall back to default DNS when configured custom DNS failed
|
||||
providers: titlovi: prevent repeated captcha solving for CF
|
||||
|
||||
|
||||
2.6.5.3017
|
||||
|
||||
Changelog
|
||||
- core: SRT parsing: handle (bad) ASS color tag in SRT
|
||||
|
||||
Reference in New Issue
Block a user