# █ █ ▀ █▄▀ ▄▀█ █▀█ ▀ # █▀█ █ █ █ █▀█ █▀▄ █ # © Copyright 2022 # https://t.me/hikariatama # # 🔒 Licensed under the GNU AGPLv3 # 🌐 https://www.gnu.org/licenses/agpl-3.0.html # scope: hikka_min 1.2.10 # meta pic: https://img.icons8.com/fluency/240/000000/spell-check.png # meta banner: https://mods.hikariatama.ru/badges/speller.jpg # meta developer: @hikarimods # scope: hikka_only # requires: requests cloudscraper requests_toolbelt aiohttp bs4 langid import asyncio import random import re import string from typing import Union import aiohttp import cloudscraper import langid import requests from bs4 import BeautifulSoup from requests_toolbelt import MultipartEncoder from telethon.tl.types import Message from .. import loader, utils URL = "https://services.gingersoftware.com/Ginger/correct/jsonSecured/GingerTheTextFull" # noqa API_KEY = "6ae0c3a0-afdc-4532-a810-82ded0054236" class GingerIt(object): def __init__(self): self.url = URL self.api_key = API_KEY self.api_version = "2.0" self.lang = "US" def parse(self, text, verify=True): session = cloudscraper.create_scraper() request = session.get( self.url, params={ "lang": self.lang, "apiKey": self.api_key, "clientVersion": self.api_version, "text": text, }, verify=verify, ) data = request.json() return self._process_data(text, data) @staticmethod def _change_char(original_text, from_position, to_position, change_with): return "{}{}{}".format( original_text[:from_position], change_with, original_text[to_position + 1 :] ) def _process_data(self, text, data): result = text corrections = [] for suggestion in reversed(data["Corrections"]): start = suggestion["From"] end = suggestion["To"] if suggestion["Suggestions"]: suggest = suggestion["Suggestions"][0] result = self._change_char(result, start, end, suggest["Text"]) corrections.append( { "start": start, "text": text[start : end + 1], "correct": suggest.get("Text", None), "definition": suggest.get("Definition", None), } ) return {"text": text, "result": result, "corrections": corrections} async def process(text: str) -> str: fields = {"mytext": text, "autofix": "1", "lang_var": "Russian"} boundary = "----WebKitFormBoundary" + "".join( random.sample(string.ascii_letters + string.digits, 16) ) m = MultipartEncoder(fields=fields, boundary=boundary) a = requests.post( "https://www.russiancorrector.com", headers={ "Pragma": "no-cache", "Cache-Control": "no-cache", "Upgrade-Insecure-Requests": "1", "Origin": "https://www.russiancorrector.com", "Content-Type": m.content_type, "User-Agent": ( "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML," " like Gecko) Chrome/92.0.4515.131 Safari/537.36" ), "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "Sec-GPC": "1", "Sec-Fetch-Site": "same-origin", "Sec-Fetch-Mode": "navigate", "Sec-Fetch-User": "?1", "Sec-Fetch-Dest": "document", "Referer": "https://www.russiancorrector.com/", "Accept-Encoding": "gzip, deflate, br", "Accept-Language": "en-US,en;q=0.9,ru;q=0.8", }, data=m, ).text url = "https://www.russiancorrector.com" + re.search( r"var url = \'(.+?)\'", a ).group(1) res = "__wait__123" while res == "__wait__123": async with aiohttp.ClientSession() as session: async with session.request("GET", url) as resp: res = await resp.text() if res != "__wait__123": break await asyncio.sleep(1) return res def parse(text: str) -> Union[bool, str]: if "We could not find any errors in your text" in text: return False soup = BeautifulSoup(text, "html.parser") for misspell in soup.find_all("div", class_="misspelling"): try: misspell.replace_with( misspell.find("li", class_="replace-option").get_text() or "" ) except Exception: misspell.replace_with("") return ( re.sub(r" {2,}", " ", soup.get_text().strip().replace("\n", " ")) .replace("Types and number of errors found: ", "") .replace( ( "Autocorrect: Check box to correct errors automatically, where" " possible.A list of all corrected errors will be shown on the results" " page. Submit" ), "", ) .strip() ) @loader.tds class SpellCheckMod(loader.Module): """Just a simple two-lang spell checker""" strings = { "name": "SpellCheck", "processing": ( "👩‍🏫 Let me take a look... Seems like this message is misspelled!" ), } strings_ru = { "processing": "👩‍🏫 Дай глянуть. Похоже, тут есть ошибки!", "_cmd_doc_spell": "Проверить сообщение на грамотность", "_cls_doc": "Проверяет правописание", } async def spellcmd(self, message: Message): """Perform spell check on reply""" reply = await message.get_reply_message() if not reply or not getattr(reply, "raw_text", False): await message.delete() message = await utils.answer(message, self.strings("processing")) text = reply.text tt = langid.classify(text)[0] if tt == "en": spell_checker = GingerIt() result = spell_checker.parse(text) corrected_text = result["result"] elif tt == "ru": corrected_text = parse(await process(text)) else: await message.delete() return if corrected_text == text or not corrected_text: await message.delete() await utils.answer(message, f"✍️ {corrected_text}")