# meta developer: @limokanews
from whoosh.index import create_in
from whoosh.fields import TEXT, ID, Schema
from whoosh.qparser import QueryParser, OrGroup
from whoosh.query import FuzzyTerm, Wildcard
import aiohttp
import random
import logging
import os
import html
import json
from telethon.types import Message
from .. import utils, loader
logger = logging.getLogger("Limoka")
class Search:
def __init__(self, query: str):
self.schema = Schema(
title=TEXT(stored=True), path=ID(stored=True), content=TEXT(stored=True)
)
self.query = query
def search_module(self, content):
if not os.path.exists("limoka_search"):
os.makedirs("limoka_search")
ix = create_in("limoka_search", self.schema)
writer = ix.writer()
for module_content in content:
writer.add_document(
title=module_content["id"],
path=module_content["id"],
content=module_content["content"],
)
writer.commit()
with ix.searcher() as searcher:
parser = QueryParser("content", ix.schema, group=OrGroup)
query = parser.parse(self.query)
fuzzy_query = FuzzyTerm("content", self.query, maxdist=1, prefixlength=2)
wildcard_query = Wildcard("content", f"*{self.query}*")
results = searcher.search(query)
if not results:
results = searcher.search(fuzzy_query)
if not results:
results = searcher.search(wildcard_query)
if results:
best_match = results[0]
return best_match["path"]
else:
return 0
class LimokaAPI:
async def get_all_modules(self) -> dict:
async with aiohttp.ClientSession() as session:
async with session.get(
"https://git.vsecoder.dev/root/limoka/-/raw/main/modules.json"
) as response:
text = await response.text()
return json.loads(text)
async def get_module_raw(self, module_path: str) -> str:
async with aiohttp.ClientSession() as session:
async with session.get(
f"https://git.vsecoder.dev/root/limoka/-/raw/main/{module_path}"
) as response:
return await response.text()
@loader.tds
class Limoka(loader.Module):
"""Hikka modules are now in one place with easy searching!"""
strings = {
"name": "Limoka",
"wait": (
"Just wait"
"\n🔍 A search is underway among {count} modules for the query: {query}"
"\n"
"\n{fact}"
),
"found": (
"🔍 Found the module {name} by query: {query}"
"\n"
"\nℹ️ Description: {description}"
"\n🧑💻 Developer: {username}"
"\n\n{commands}"
"\n🪄 {prefix}dlm https://git.vsecoder.dev/root/limoka/-/raw/main/{module_path}"
),
"command_template": "{emoji} {prefix}{command} {description}\n",
"emojis": {
1: "1️⃣",
2: "2️⃣",
3: "3️⃣",
4: "4️⃣",
5: "5️⃣",
6: "6️⃣",
7: "7️⃣",
8: "8️⃣",
9: "9️⃣",
},
"404": "❌ Not found by query: {query}",
"noargs": "❌ No args",
"?": "🔎 Request too short / not found",
"no_info": "No information",
"facts": [
"🛡 The limoka catalog is carefully moderated!",
"🚀 Limoka performance allows you to search for modules quickly!",
],
}
strings_ru = {
"wait": (
"Подождите"
"\n🔍 Идёт поиск среди {count} модулей по запросу: {query}"
"\n"
"\n{fact}"
),
"found": (
"🔍 Найден модуль {name} по запросу: {query}"
"\n"
"\nℹ️ Описание: {description}"
"\n🧑💻 Разработчик: {username}"
"\n"
"\n{commands}"
"\n"
"\n🪄 {prefix}dlm https://git.vsecoder.dev/root/limoka/-/raw/main/{module_path}"
),
"command_template": "{emoji} {prefix}{command} {description}\n",
"404": "❌ Не найдено по запросу: {query}",
"noargs": "❌ Нет аргументов",
"?": "🔎 Запрос слишком короткий / не найден",
"no_info": "Нет информации",
"facts": [
"🛡 Каталог лимоки тщательно модерируется!",
"🚀 Производительность лимоки позволяет вам искать модули с невероятной скоростью",
],
}
async def client_ready(self, client, db):
self.client = client
self.db = db
def __init__(self):
self.api = LimokaAPI()
@loader.command()
async def limoka(self, message: Message):
"""[query] - Search module"""
args = utils.get_args_raw(message)
if len(args) <= 1:
return await utils.answer(message, self.strings["?"])
if not args:
return await utils.answer(message, self.strings["noargs"])
modules = await self.api.get_all_modules()
await utils.answer(
message,
self.strings["wait"].format(
count=len(modules),
fact=random.choice(self.strings["facts"]),
query=args,
),
)
modules = await self.api.get_all_modules()
contents = []
for module_path, module_data in modules.items():
contents.append(
{
"id": module_path,
"content": module_data["name"],
}
)
for module_path, module_data in modules.items():
contents.append(
{
"id": module_path,
"content": module_data["description"],
}
)
for module_path, module_data in modules.items():
for func in module_data["commands"]:
for command, description in func.items():
contents.append({"id": module_path, "content": command})
contents.append({"id": module_path, "content": description})
searcher = Search(args.lower())
try:
result = searcher.search_module(contents)
except IndexError:
return await utils.answer(message, self.strings["?"])
module_path = result
if module_path is None or module_path == 0:
return await utils.answer(message, self.strings["404"].format(query=args))
module_info = modules[module_path]
dev_username = module_info["meta"].get("developer", "Unknown")
commands = []
command_count = 0
end_count_cmds = False
for func in module_info["commands"]:
if end_count_cmds:
break
for command, description in func.items():
if command_count == 9:
commands.append("...")
end_count_cmds = True
break
command_count += 1
emoji = self.strings["emojis"].get(command_count, "")
commands.append(
self.strings["command_template"].format(
prefix=self.get_prefix(),
command=html.escape(command.replace("cmd", "")),
emoji=emoji,
description=(
html.escape(description)
if description
else self.strings["no_info"]
),
)
)
name = module_info["name"]
description = (
html.escape(module_info["description"])
if module_info["description"]
else self.strings["no_info"]
)
banner = module_info["meta"]["banner"]
if description:
translated_desc = await self._client.translate(
message.peer_id,
message,
to_lang=self._db.get("hikka.translations", "lang", "en")[0:2],
raw_text=description,
entities=message.entities,
)
try:
await utils.answer_file(
message,
banner,
self.strings["found"].format(
query=args,
name=name if name else self.strings["no_info"],
description=(
translated_desc if description else self.strings["no_info"]
),
username=dev_username,
commands="".join(commands),
prefix=self.get_prefix(),
module_path=module_path.replace("\\", "/"),
),
)
except Exception:
await utils.answer(
message,
self.strings["found"].format(
query=args,
name=name if name else self.strings["no_info"],
description=(
translated_desc if description else self.strings["no_info"]
),
username=dev_username,
commands="".join(commands),
prefix=self.get_prefix(),
module_path=module_path,
),
)