Skip to content

Commit

Permalink
Merge pull request #83 from SirFilippov/languages/ru
Browse files Browse the repository at this point in the history
Added Russian translations
  • Loading branch information
Xewdy444 authored Mar 13, 2024
2 parents 7ec3e7a + f51c994 commit 443dc91
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 59 deletions.
38 changes: 19 additions & 19 deletions playwright_recaptcha/recaptchav2/async_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
RecaptchaSolveError,
)
from .recaptcha_box import AsyncRecaptchaBox
from .translations import TRANSLATIONS


class AsyncAudioFile(speech_recognition.AudioFile):
Expand Down Expand Up @@ -115,29 +116,28 @@ async def _get_task_object(recaptcha_box: AsyncRecaptchaBox) -> Optional[str]:
The object ID. Returns None if the task object is not recognized.
"""
object_dict = {
"taxis": "/m/0pg52",
"bus": "/m/01bjv",
"school bus": "/m/02yvhj",
"motorcycles": "/m/04_sv",
"tractors": "/m/013xlm",
"chimneys": "/m/01jk_4",
"crosswalks": "/m/014xcs",
"traffic lights": "/m/015qff",
"bicycles": "/m/0199g",
"parking meters": "/m/015qbp",
"cars": "/m/0k4j",
"bridges": "/m/015kr",
"boats": "/m/019jd",
"palm trees": "/m/0cdl1",
"mountains or hills": "/m/09d_r",
"fire hydrant": "/m/01pns0",
"stairs": "/m/01lynh",
"/m/0pg52": TRANSLATIONS["taxis"],
"/m/01bjv": TRANSLATIONS["bus"],
"/m/04_sv": TRANSLATIONS["motorcycles"],
"/m/013xlm": TRANSLATIONS["tractors"],
"/m/01jk_4": TRANSLATIONS["chimneys"],
"/m/014xcs": TRANSLATIONS["crosswalks"],
"/m/015qff": TRANSLATIONS["traffic_lights"],
"/m/0199g": TRANSLATIONS["bicycles"],
"/m/015qbp": TRANSLATIONS["parking_meters"],
"/m/0k4j": TRANSLATIONS["cars"],
"/m/015kr": TRANSLATIONS["bridges"],
"/m/019jd": TRANSLATIONS["boats"],
"/m/0cdl1": TRANSLATIONS["palm_trees"],
"/m/09d_r": TRANSLATIONS["mountains_or_hills"],
"/m/01pns0": TRANSLATIONS["fire_hydrant"],
"/m/01lynh": TRANSLATIONS["stairs"],
}

task = await recaptcha_box.bframe_frame.locator("div").all_inner_texts()

for object_name, object_id in object_dict.items():
if object_name in task[0]:
for object_id, translations in object_dict.items():
if any(translation in task[0] for translation in translations):
return object_id

return None
Expand Down
70 changes: 49 additions & 21 deletions playwright_recaptcha/recaptchav2/recaptcha_box.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from playwright.sync_api import Locator as SyncLocator

from ..errors import RecaptchaNotFoundError
from .translations import TRANSLATIONS

Locator = Union[AsyncLocator, SyncLocator]
Frame = Union[AsyncFrame, SyncFrame]
Expand Down Expand Up @@ -99,49 +100,68 @@ async def async_wrapper(self: AsyncRecaptchaBox) -> bool:
@property
def checkbox(self) -> Locator:
"""The reCAPTCHA checkbox locator."""
return self.anchor_frame.get_by_role("checkbox", name="I'm not a robot")
return self.anchor_frame.get_by_role(
"checkbox", name=re.compile("|".join(TRANSLATIONS["im_not_a_robot"]))
)

@property
def audio_challenge_button(self) -> Locator:
"""The reCAPTCHA audio challenge button locator."""
return self.bframe_frame.get_by_role("button", name="Get an audio challenge")
return self.bframe_frame.get_by_role(
"button", name=re.compile("|".join(TRANSLATIONS["get_an_audio_challenge"]))
)

@property
def image_challenge_button(self) -> Locator:
"""The reCAPTCHA image challenge button locator."""
return self.bframe_frame.get_by_role("button", name="Get a visual challenge")
return self.bframe_frame.get_by_role(
"button", name=re.compile("|".join(TRANSLATIONS["get_a_visual_challenge"]))
)

@property
def new_challenge_button(self) -> Locator:
"""The reCAPTCHA new challenge button locator."""
return self.bframe_frame.get_by_role("button", name="Get a new challenge")
return self.bframe_frame.get_by_role(
"button", name=re.compile("|".join(TRANSLATIONS["get_a_new_challenge"]))
)

@property
def audio_download_button(self) -> Locator:
"""The reCAPTCHA audio download button locator."""
return self.bframe_frame.get_by_role(
"link", name="Alternatively, download audio as MP3"
"link",
name=re.compile(
"|".join(TRANSLATIONS["alternatively_download_audio_as_mp3"])
),
)

@property
def audio_challenge_textbox(self) -> Locator:
"""The reCAPTCHA audio challenge textbox locator."""
return self.bframe_frame.get_by_role("textbox", name="Enter what you hear")
return self.bframe_frame.get_by_role(
"textbox", name=re.compile("|".join(TRANSLATIONS["enter_what_you_hear"]))
)

@property
def skip_button(self) -> Locator:
"""The reCAPTCHA skip button locator."""
return self.bframe_frame.get_by_role("button", name="Skip")
return self.bframe_frame.get_by_role(
"button", name=re.compile("|".join(TRANSLATIONS["skip"]))
)

@property
def next_button(self) -> Locator:
"""The reCAPTCHA next button locator."""
return self.bframe_frame.get_by_role("button", name="Next")
return self.bframe_frame.get_by_role(
"button", name=re.compile("|".join(TRANSLATIONS["next"]))
)

@property
def verify_button(self) -> Locator:
"""The reCAPTCHA verify button locator."""
return self.bframe_frame.get_by_role("button", name="Verify")
return self.bframe_frame.get_by_role(
"button", name=re.compile("|".join(TRANSLATIONS["verify"]))
)

@property
def tile_selector(self) -> Locator:
Expand Down Expand Up @@ -379,7 +399,9 @@ def rate_limit_is_visible(self) -> bool:
bool
True if the reCAPTCHA rate limit message is visible, False otherwise.
"""
return self.bframe_frame.get_by_text("Try again later").is_visible()
return self.bframe_frame.get_by_text(
re.compile("|".join(TRANSLATIONS["try_again_later"]))
).is_visible()

@RecaptchaBox._check_if_attached
def solve_failure_is_visible(self) -> bool:
Expand All @@ -392,7 +414,7 @@ def solve_failure_is_visible(self) -> bool:
True if the reCAPTCHA solve failure message is visible, False otherwise.
"""
return self.bframe_frame.get_by_text(
"Multiple correct solutions required - please solve more."
re.compile("|".join(TRANSLATIONS["multiple_correct_solutions_required"]))
).is_visible()

@RecaptchaBox._check_if_attached
Expand All @@ -405,7 +427,9 @@ def audio_challenge_is_visible(self) -> bool:
bool
True if the reCAPTCHA audio challenge is visible, False otherwise.
"""
return self.bframe_frame.get_by_text("Press PLAY to listen").is_visible()
return self.bframe_frame.get_by_text(
re.compile("|".join(TRANSLATIONS["press_play_to_listen"]))
).is_visible()

@RecaptchaBox._check_if_attached
def try_again_is_visible(self) -> bool:
Expand All @@ -418,7 +442,7 @@ def try_again_is_visible(self) -> bool:
True if the reCAPTCHA try again message is visible, False otherwise.
"""
return self.bframe_frame.get_by_text(
re.compile("Please try again")
re.compile("|".join(TRANSLATIONS["please_try_again"]))
).is_visible()

@RecaptchaBox._check_if_attached
Expand All @@ -432,7 +456,7 @@ def check_new_images_is_visible(self) -> bool:
True if the reCAPTCHA check new images message is visible, False otherwise.
"""
return self.bframe_frame.get_by_text(
re.compile("Please also check the new images")
re.compile("|".join(TRANSLATIONS["please_also_check_the_new_images"]))
).is_visible()

@RecaptchaBox._check_if_attached
Expand All @@ -447,7 +471,7 @@ def select_all_matching_is_visible(self) -> bool:
False otherwise.
"""
return self.bframe_frame.get_by_text(
re.compile("Please select all matching images")
re.compile("|".join(TRANSLATIONS["please_select_all_matching_images"]))
).is_visible()

@RecaptchaBox._check_if_attached
Expand Down Expand Up @@ -557,7 +581,9 @@ async def rate_limit_is_visible(self) -> bool:
bool
True if the reCAPTCHA rate limit message is visible, False otherwise.
"""
return await self.bframe_frame.get_by_text("Try again later").is_visible()
return await self.bframe_frame.get_by_text(
re.compile("|".join(TRANSLATIONS["try_again_later"]))
).is_visible()

@RecaptchaBox._check_if_attached
async def solve_failure_is_visible(self) -> bool:
Expand All @@ -570,7 +596,7 @@ async def solve_failure_is_visible(self) -> bool:
True if the reCAPTCHA solve failure message is visible, False otherwise.
"""
return await self.bframe_frame.get_by_text(
"Multiple correct solutions required - please solve more."
re.compile("|".join(TRANSLATIONS["multiple_correct_solutions_required"]))
).is_visible()

@RecaptchaBox._check_if_attached
Expand All @@ -583,7 +609,9 @@ async def audio_challenge_is_visible(self) -> bool:
bool
True if the reCAPTCHA audio challenge is visible, False otherwise.
"""
return await self.bframe_frame.get_by_text("Press PLAY to listen").is_visible()
return await self.bframe_frame.get_by_text(
re.compile("|".join(TRANSLATIONS["press_play_to_listen"]))
).is_visible()

@RecaptchaBox._check_if_attached
async def try_again_is_visible(self) -> bool:
Expand All @@ -596,7 +624,7 @@ async def try_again_is_visible(self) -> bool:
True if the reCAPTCHA try again message is visible, False otherwise.
"""
return await self.bframe_frame.get_by_text(
re.compile("Please try again")
re.compile("|".join(TRANSLATIONS["please_try_again"]))
).is_visible()

@RecaptchaBox._check_if_attached
Expand All @@ -610,7 +638,7 @@ async def check_new_images_is_visible(self) -> bool:
True if the reCAPTCHA check new images message is visible, False otherwise.
"""
return await self.bframe_frame.get_by_text(
re.compile("Please also check the new images")
re.compile("|".join(TRANSLATIONS["please_also_check_the_new_images"]))
).is_visible()

@RecaptchaBox._check_if_attached
Expand All @@ -625,7 +653,7 @@ async def select_all_matching_is_visible(self) -> bool:
False otherwise.
"""
return await self.bframe_frame.get_by_text(
re.compile("Please select all matching images")
re.compile("|".join(TRANSLATIONS["please_select_all_matching_images"]))
).is_visible()

@RecaptchaBox._check_if_attached
Expand Down
38 changes: 19 additions & 19 deletions playwright_recaptcha/recaptchav2/sync_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
RecaptchaSolveError,
)
from .recaptcha_box import SyncRecaptchaBox
from .translations import TRANSLATIONS


class SyncSolver:
Expand Down Expand Up @@ -77,29 +78,28 @@ def _get_task_object(recaptcha_box: SyncRecaptchaBox) -> Optional[str]:
The object ID. Returns None if the task object is not recognized.
"""
object_dict = {
"taxis": "/m/0pg52",
"bus": "/m/01bjv",
"school bus": "/m/02yvhj",
"motorcycles": "/m/04_sv",
"tractors": "/m/013xlm",
"chimneys": "/m/01jk_4",
"crosswalks": "/m/014xcs",
"traffic lights": "/m/015qff",
"bicycles": "/m/0199g",
"parking meters": "/m/015qbp",
"cars": "/m/0k4j",
"bridges": "/m/015kr",
"boats": "/m/019jd",
"palm trees": "/m/0cdl1",
"mountains or hills": "/m/09d_r",
"fire hydrant": "/m/01pns0",
"stairs": "/m/01lynh",
"/m/0pg52": TRANSLATIONS["taxis"],
"/m/01bjv": TRANSLATIONS["bus"],
"/m/04_sv": TRANSLATIONS["motorcycles"],
"/m/013xlm": TRANSLATIONS["tractors"],
"/m/01jk_4": TRANSLATIONS["chimneys"],
"/m/014xcs": TRANSLATIONS["crosswalks"],
"/m/015qff": TRANSLATIONS["traffic_lights"],
"/m/0199g": TRANSLATIONS["bicycles"],
"/m/015qbp": TRANSLATIONS["parking_meters"],
"/m/0k4j": TRANSLATIONS["cars"],
"/m/015kr": TRANSLATIONS["bridges"],
"/m/019jd": TRANSLATIONS["boats"],
"/m/0cdl1": TRANSLATIONS["palm_trees"],
"/m/09d_r": TRANSLATIONS["mountains_or_hills"],
"/m/01pns0": TRANSLATIONS["fire_hydrant"],
"/m/01lynh": TRANSLATIONS["stairs"],
}

task = recaptcha_box.bframe_frame.locator("div").all_inner_texts()

for object_name, object_id in object_dict.items():
if object_name in task[0]:
for object_id, translations in object_dict.items():
if any(translation in task[0] for translation in translations):
return object_id

return None
Expand Down
48 changes: 48 additions & 0 deletions playwright_recaptcha/recaptchav2/translations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
TRANSLATIONS = {
"im_not_a_robot": ("I'm not a robot", "Я не робот"),
"get_an_audio_challenge": ("Get an audio challenge", "Пройти аудиотест"),
"get_a_visual_challenge": ("Get a visual challenge", "Пройти визуальный тест"),
"get_a_new_challenge": ("Get a new challenge", "Обновить"),
"alternatively_download_audio_as_mp3": (
"Alternatively, download audio as MP3",
"Скачать MP3-файл",
),
"enter_what_you_hear": ("Enter what you hear", "Введите прозвучавшие слова"),
"skip": ("Skip", "Пропустить"),
"next": ("Next", "Далее"),
"verify": ("Verify", "Подтвердить"),
"try_again_later": ("Try again later", "Повторите попытку позже"),
"multiple_correct_solutions_required": (
"Multiple correct solutions required - please solve more",
"Вы должны выполнить несколько заданий",
),
"press_play_to_listen": (
"Press PLAY to listen",
'Чтобы прослушать, нажмите "Воспроизвести"',
),
"please_try_again": ("Please try again", "Повторите попытку"),
"please_also_check_the_new_images": (
"Please also check the new images",
"Просмотрите также новые изображение",
),
"please_select_all_matching_images": (
"Please select all matching images",
"Выберите все совпадающие изображения",
),
"taxis": ("taxis", "такси"),
"bus": ("bus", "автобус"),
"motorcycles": ("motorcycles", "мотоциклы"),
"tractors": ("tractors", "трактора"),
"chimneys": ("chimneys", "дымовые трубы"),
"crosswalks": ("crosswalks", "пешеходные переходы"),
"traffic_lights": ("traffic lights", "светофоры"),
"bicycles": ("bicycles", "велосипеды"),
"parking_meters": ("parking meters", "парковочные автоматы"),
"cars": ("cars", "автомобили"),
"bridges": ("bridges", "мостами"),
"boats": ("boats", "лодки"),
"palm_trees": ("palm trees", "пальмы"),
"mountains_or_hills": ("mountains or hills", "горы или холмы"),
"fire_hydrant": ("fire hydrant", "гидрантами", "пожарные гидранты"),
"stairs": ("stairs", "лестницы"),
}

0 comments on commit 443dc91

Please sign in to comment.