WIP: recaptcha

This commit is contained in:
marco
2021-11-21 13:34:24 +01:00
parent 80019ab6b7
commit 15785a653e
6 changed files with 156 additions and 205 deletions
+2 -2
View File
@@ -1138,8 +1138,8 @@ def show_video_info(*args, **kwargs):
def show_recaptcha(key, referer): def show_recaptcha(key, referer):
from platformcode.recaptcha import Recaptcha from platformcode.recaptcha import Kodi
return Recaptcha("Recaptcha.xml", config.get_runtime_path()).Start(key, referer) return Kodi(key, referer).run()
def alert_no_disponible_server(server): def alert_no_disponible_server(server):
+138 -51
View File
@@ -1,77 +1,164 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import random
import time
from threading import Thread
from builtins import range
import xbmcgui import xbmcgui
from core import httptools from core import httptools
from core import scrapertools from core import filetools
from platformcode import config from platformcode import config, platformtools
from platformcode import platformtools from platformcode import logger
from lib.librecaptcha.recaptcha import ReCaptcha, Solver, DynamicSolver, MultiCaptchaSolver, Solution, \
ImageGridChallenge
lang = 'it' lang = 'it'
tiles_pos = (75+390, 90+40)
grid_width = 450
tiles_texture_focus = 'white.png'
tiles_texture_checked = 'Controls/check_mark.png'
class Recaptcha(xbmcgui.WindowXMLDialog):
def Start(self, key, referer):
self.referer = referer
self.key = key
self.headers = {'Referer': self.referer}
api_js = httptools.downloadpage("https://www.google.com/recaptcha/api.js?hl=" + lang).data class Kodi:
version = scrapertools.find_single_match(api_js, 'po.src\s*=\s*\'(.*?)\';').split("/")[5] def __init__(self, key, referer):
self.url = "https://www.google.com/recaptcha/api/fallback?k=" + self.key + "&hl=" + lang + "&v=" + version + "&t=2&ff=true" self.rc = ReCaptcha(
self.doModal() api_key=key,
# Reload site_url=referer,
if self.result == {}: user_agent=httptools.get_user_agent(),
self.result = Recaptcha("Recaptcha.xml", config.get_runtime_path()).Start(self.key, self.referer) )
return self.result def run(self) -> str:
result = self.rc.first_solver()
while not isinstance(result, str) and result is not False:
solution = self.run_solver(result)
if solution:
result = self.rc.send_solution(solution)
logger.debug(result)
platformtools.dialog_notification("Captcha corretto", "Verifica conclusa")
return result
def update_window(self): def run_solver(self, solver: Solver) -> Solution:
data = httptools.downloadpage(self.url, headers=self.headers).data a = {
self.message = scrapertools.find_single_match(data, DynamicSolver: DynamicKodi,
'<div class="rc-imageselect-desc[a-z-]*">(.*?)(?:</label>|</div>)').replace( MultiCaptchaSolver: MultiCaptchaKodi,
"<strong>", "[B]").replace("</strong>", "[/B]") }
self.token = scrapertools.find_single_match(data, 'name="c" value="([^"]+)"') b = a[type(solver)]
self.image = "https://www.google.com/recaptcha/api2/payload?k=%s&c=%s" % (self.key, self.token) c = b("Recaptcha.xml", config.get_runtime_path())
self.result = {} c.solver = solver
self.getControl(10020).setImage(self.image) return c.run()
self.getControl(10000).setText(self.message)
self.setFocusId(10005)
class SolverKodi(xbmcgui.WindowXMLDialog):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.mensaje = kwargs.get("mensaje") self.goal = ""
self.imagen = kwargs.get("imagen") self.closed = False
self.result = None
self.image_path = ''
self.indices = {}
logger.debug()
def show_image(self, image, goal):
self.image_path = config.get_temp_file(str(random.randint(1, 1000)) + '.png')
filetools.write(self.image_path, image)
self.goal = goal.replace('<strong>', '[B]').replace('</strong>', '[/B]')
self.doModal()
def onInit(self): def onInit(self):
#### Kodi 18 compatibility #### logger.debug(self.image_path)
if config.get_platform(True)['num_version'] < 18: self.getControl(10020).setImage(self.image_path, False)
self.setCoordinateResolution(2) self.getControl(10000).setText(self.goal)
self.update_window() self.setFocusId(10005)
for x in range(self.num_columns):
for y in range(self.num_rows):
self.addControl(xbmcgui.ControlRadioButton(int(tiles_pos[0] + x*grid_width/self.num_rows), int(tiles_pos[1] + y*grid_width/self.num_columns),
int(grid_width/self.num_rows), int(grid_width/self.num_columns), '', tiles_texture_focus, tiles_texture_focus,
focusTexture=tiles_texture_checked, noFocusTexture=tiles_texture_checked))
class MultiCaptchaKodi(SolverKodi):
"""
multicaptcha challenges present you with one large image split into a grid of tiles and ask you to select the tiles that contain a given object.
Occasionally, the image will not contain the object, but rather something that looks similar.
It is possible to select no tiles in this case, but reCAPTCHA may have been fooled by the similar-looking object and would reject a selection of no tiles.
"""
def run(self) -> Solution:
result = self.solver.first_challenge()
while not isinstance(result, Solution):
if not isinstance(result, ImageGridChallenge):
raise TypeError("Unexpected type: {}".format(type(result)))
indices = self.handle_challenge(result)
result = self.solver.select_indices(indices)
return result
def handle_challenge(self, challenge: ImageGridChallenge):
goal = challenge.goal.plain
self.num_rows = challenge.dimensions.rows
self.num_columns = challenge.dimensions.columns
num_tiles = challenge.dimensions.count
image = challenge.image
self.show_image(image, goal)
if self.closed:
return False
return self.result
def onClick(self, control): def onClick(self, control):
if control == 10003: if control == 10003:
self.result = None self.closed = True
self.close() self.close()
elif control == 10004: elif control == 10004:
self.result = {} self.result = None
self.close() self.close()
elif control == 10002: elif control == 10002:
self.result = [int(k) for k in range(9) if self.result.get(k, False)] self.result = [int(k) for k in range(9) if self.indices.get(k, False)]
post = { self.close()
"c": self.token, else:
"response": self.result index = control - 10005
} self.indices[control - 10005] = not self.indices.get(index, False)
data = httptools.downloadpage(self.url, post=post, headers=self.headers).data
from platformcode import logger class DynamicKodi(SolverKodi):
logger.debug(data) """
self.result = scrapertools.find_single_match(data, '<div class="fbc-verification-token">.*?>([^<]+)<') dynamic challenges present you with a grid of different images and ask you to select the images that match the given description.
if self.result: Each time you click an image, a new one takes its place. Usually, three images from the initial set match the description,
platformtools.dialog_notification("Captcha corretto", "Verifica conclusa") and at least one of the replacement images does as well.
"""
def run(self):
challenge = self.solver.get_challenge()
image = challenge.image
goal = challenge.goal.raw
self.num_rows = challenge.dimensions.rows
self.num_columns = challenge.dimensions.columns
num_tiles = challenge.dimensions.count
self.show_image(image, goal)
if self.closed:
return False
return self.result
def changeTile(self, path, index, delay):
from core.support import dbg
dbg()
time.sleep(delay)
tile = self.getControl(10005 + index)
self.addControl(xbmcgui.ControlImage(tile.getX(), tile.getY(), tile.getWidth(), tile.getHeigh(), path))
def onClick(self, control):
if control == 10003:
self.closed = True
self.close()
elif control == 10004:
self.result = None
self.close()
elif control == 10002:
self.result = self.solver.finish()
self.close() self.close()
else: else:
self.result = {} index = control - 10005
self.close() tile = self.solver.select_tile(index)
else: path = config.get_temp_file(str(random.randint(1, 1000)) + '.png')
self.result[control - 10005] = not self.result.get(control - 10005, False) filetools.write(path, tile.image)
Thread(target=self.changeTile, args=(path, index, tile.delay)).start()
-126
View File
@@ -92,132 +92,6 @@
<width>450</width> <width>450</width>
<height>450</height> <height>450</height>
</control> </control>
<control type="togglebutton" id="10005">
<top>90</top>
<left>75</left>
<width>150</width>
<height>150</height>
<texturefocus colordiffuse="AA232323">white.png</texturefocus>
<texturenofocus colordiffuse="00232323">white.png</texturenofocus>
<alttexturefocus colordiffuse="FF0082C2">Controls/check_mark.png</alttexturefocus>
<alttexturenofocus colordiffuse="FFFFFFFF">Controls/check_mark.png</alttexturenofocus>
<onup>10002</onup>
<ondown>10008</ondown>
<onleft>10007</onleft>
<onright>10006</onright>
</control>
<control type="togglebutton" id="10006">
<top>90</top>
<left>225</left>
<width>150</width>
<height>150</height>
<texturefocus colordiffuse="AA232323">white.png</texturefocus>
<texturenofocus colordiffuse="00232323">white.png</texturenofocus>
<alttexturefocus colordiffuse="FF0082C2">Controls/check_mark.png</alttexturefocus>
<alttexturenofocus colordiffuse="FFFFFFFF">Controls/check_mark.png</alttexturenofocus>
<onup>10003</onup>
<ondown>10009</ondown>
<onleft>10005</onleft>
<onright>10007</onright>
</control>
<control type="togglebutton" id="10007">
<top>90</top>
<left>375</left>
<width>150</width>
<height>150</height>
<texturefocus colordiffuse="AA232323">white.png</texturefocus>
<texturenofocus colordiffuse="00232323">white.png</texturenofocus>
<alttexturefocus colordiffuse="FF0082C2">Controls/check_mark.png</alttexturefocus>
<alttexturenofocus colordiffuse="FFFFFFFF">Controls/check_mark.png</alttexturenofocus>
<onup>10004</onup>
<ondown>10010</ondown>
<onleft>10006</onleft>
<onright>10005</onright>
</control>
<control type="togglebutton" id="10008">
<top>240</top>
<left>75</left>
<width>150</width>
<height>150</height>
<texturefocus colordiffuse="AA232323">white.png</texturefocus>
<texturenofocus colordiffuse="00232323">white.png</texturenofocus>
<alttexturefocus colordiffuse="FF0082C2">Controls/check_mark.png</alttexturefocus>
<alttexturenofocus colordiffuse="FFFFFFFF">Controls/check_mark.png</alttexturenofocus>
<onup>10005</onup>
<ondown>10011</ondown>
<onleft>10010</onleft>
<onright>10009</onright>
</control>
<control type="togglebutton" id="10009">
<top>240</top>
<left>225</left>
<width>150</width>
<height>150</height>
<texturefocus colordiffuse="AA232323">white.png</texturefocus>
<texturenofocus colordiffuse="00232323">white.png</texturenofocus>
<alttexturefocus colordiffuse="FF0082C2">Controls/check_mark.png</alttexturefocus>
<alttexturenofocus colordiffuse="FFFFFFFF">Controls/check_mark.png</alttexturenofocus>
<onup>10006</onup>
<ondown>10012</ondown>
<onleft>10008</onleft>
<onright>10010</onright>
</control>
<control type="togglebutton" id="10010">
<top>240</top>
<left>375</left>
<width>150</width>
<height>150</height>
<texturefocus colordiffuse="AA232323">white.png</texturefocus>
<texturenofocus colordiffuse="00232323">white.png</texturenofocus>
<alttexturefocus colordiffuse="FF0082C2">Controls/check_mark.png</alttexturefocus>
<alttexturenofocus colordiffuse="FFFFFFFF">Controls/check_mark.png</alttexturenofocus>
<onup>10007</onup>
<ondown>10013</ondown>
<onleft>10009</onleft>
<onright>10008</onright>
</control>
<control type="togglebutton" id="10011">
<top>390</top>
<left>75</left>
<width>150</width>
<height>150</height>
<texturefocus colordiffuse="AA232323">white.png</texturefocus>
<texturenofocus colordiffuse="00232323">white.png</texturenofocus>
<alttexturefocus colordiffuse="FF0082C2">Controls/check_mark.png</alttexturefocus>
<alttexturenofocus colordiffuse="FFFFFFFF">Controls/check_mark.png</alttexturenofocus>
<onup>10008</onup>
<ondown>10002</ondown>
<onleft>10013</onleft>
<onright>10012</onright>
</control>
<control type="togglebutton" id="10012">
<top>390</top>
<left>225</left>
<width>150</width>
<height>150</height>
<texturefocus colordiffuse="AA232323">white.png</texturefocus>
<texturenofocus colordiffuse="00232323">white.png</texturenofocus>
<alttexturefocus colordiffuse="FF0082C2">Controls/check_mark.png</alttexturefocus>
<alttexturenofocus colordiffuse="FFFFFFFF">Controls/check_mark.png</alttexturenofocus>
<onup>10009</onup>
<ondown>10003</ondown>
<onleft>10011</onleft>
<onright>10013</onright>
</control>
<control type="togglebutton" id="10013">
<top>390</top>
<left>375</left>
<width>150</width>
<height>150</height>
<texturefocus colordiffuse="AA232323">white.png</texturefocus>
<texturenofocus colordiffuse="00232323">white.png</texturenofocus>
<alttexturefocus colordiffuse="FF0082C2">Controls/check_mark.png</alttexturefocus>
<alttexturenofocus colordiffuse="FFFFFFFF">Controls/check_mark.png</alttexturenofocus>
<onup>10010</onup>
<ondown>10004</ondown>
<onleft>10012</onleft>
<onright>10011</onright>
</control>
</control> </control>
</controls> </controls>
</window> </window>
+1 -5
View File
@@ -4,12 +4,8 @@
"ignore_urls": [], "ignore_urls": [],
"patterns": [ "patterns": [
{ {
"pattern": "(https?://maxstream.video/uprot/[a-zA-Z0-9]+)", "pattern": "(https?://maxstream.video/(?:[^/]+/)?([a-zA-Z0-9]+))",
"url": "\\1" "url": "\\1"
},
{
"pattern": "https?://maxstream.video/(?:e/|embed-|cast/)?([a-z0-9]+)",
"url": "http://maxstream.video/\\1"
} }
] ]
}, },
+11 -18
View File
@@ -9,22 +9,15 @@ import requests
from core import httptools, scrapertools, support from core import httptools, scrapertools, support
from lib import jsunpack from lib import jsunpack
from platformcode import logger, config, platformtools from platformcode import logger, config, platformtools
if sys.version_info[0] >= 3:
import urllib.parse as urlparse
else:
import urlparse
def test_video_exists(page_url): def test_video_exists(page_url):
logger.debug("(page_url='%s')" % page_url) logger.debug("(page_url='%s')" % page_url)
global data global data, new_url
if 'uprot/' in page_url: new_url = httptools.downloadpage(page_url, follow_redirects=False, cloudscraper=True).headers.get('location', page_url)
id = httptools.downloadpage(page_url, follow_redirects=False, cloudscraper=True).headers.get('location').split('/')[-1] # page_url = requests.head('http://lozioangie.altervista.org/max_anticaptcha.php?id=' + id).headers.get('location')
else: data = httptools.downloadpage(new_url, cloudscraper=True).data
id = page_url.split('/')[-1]
page_url = requests.head('http://lozioangie.altervista.org/max_anticaptcha.php?id=' + id).headers.get('location')
data = httptools.downloadpage(page_url, cloudscraper=True).data
if scrapertools.find_single_match(data, '(?<!none);[^>]*>file was deleted'): if scrapertools.find_single_match(data, '(?<!none);[^>]*>file was deleted'):
return False, config.get_localized_string(70449) % "MaxStream" return False, config.get_localized_string(70449) % "MaxStream"
@@ -35,14 +28,14 @@ def test_video_exists(page_url):
def get_video_url(page_url, premium=False, user="", password="", video_password=""): def get_video_url(page_url, premium=False, user="", password="", video_password=""):
logger.debug("url=" + page_url) logger.debug("url=" + page_url)
video_urls = [] video_urls = []
global data global data, new_url
if 'captcha' in data: # if 'captcha' in data:
httptools.set_cookies(requests.get('http://lozioangie.altervista.org/maxcookie.php').json()) # httptools.set_cookies(requests.get('http://lozioangie.altervista.org/maxcookie.php').json())
data = httptools.downloadpage(page_url, cloudscraper=True).data # data = httptools.downloadpage(page_url, cloudscraper=True).data
# sitekey = scrapertools.find_multiple_matches(data, """data-sitekey=['"] *([^"']+)""") sitekey = scrapertools.find_multiple_matches(data, """data-sitekey=['"] *([^"']+)""")
# if sitekey: sitekey = sitekey[-1] if sitekey: sitekey = sitekey[-1]
# captcha = platformtools.show_recaptcha(sitekey, page_url) if sitekey else '' captcha = platformtools.show_recaptcha(sitekey, new_url) if sitekey else ''
# #
# possibleParam = scrapertools.find_multiple_matches(data, # possibleParam = scrapertools.find_multiple_matches(data,
# r"""<input.*?(?:name=["']([^'"]+).*?value=["']([^'"]*)['"]>|>)""") # r"""<input.*?(?:name=["']([^'"]+).*?value=["']([^'"]*)['"]>|>)""")
+1
View File
@@ -657,6 +657,7 @@ class SearchWindow(xbmcgui.WindowXML):
else: item.contentSerieName = self.RESULTS.getSelectedItem().getLabel() else: item.contentSerieName = self.RESULTS.getSelectedItem().getLabel()
item.folder = False item.folder = False
logger.debug(item)
Search(item, self.thActions) Search(item, self.thActions)
if close_action: if close_action:
self.close() self.close()