{}
{} loaded {}{}{}{}",
+ "loaded": "🔭 Module {}
{} loaded {}{}{}{}\n\n{}",
"no_class": "What class needs to be unloaded?",
"unloaded": "🧹 Module unloaded.",
"not_unloaded": "🚫 Module not unloaded.",
@@ -159,6 +110,7 @@ class LoaderMod(loader.Module):
"add_repo_config_doc": "Additional repos to load from",
"share_link_doc": "Share module link in result message of .dlmod",
"modlink": "\n🌍 Link: {}
",
+ "blob_link": "🚸 Do not use `blob` links to download modules. Consider switching to `raw` instead",
}
strings_ru = {
@@ -173,7 +125,7 @@ class LoaderMod(loader.Module):
"provide_module": "⚠️ Укажи модуль для загрузки",
"bad_unicode": "🚫 Неверная кодировка модуля",
"load_failed": "🚫 Загрузка не увенчалась успехом. Смотри логи.",
- "loaded": "🔭 Модуль {}
{} загружен {}{}{}{}",
+ "loaded": "🔭 Модуль {}
{} загружен {}{}{}{}\n\n{}",
"no_class": "А что выгружать то?",
"unloaded": "🧹 Модуль выгружен.",
"not_unloaded": "🚫 Модуль не выгружен.",
@@ -203,13 +155,14 @@ class LoaderMod(loader.Module):
"_cls_doc": "Загружает модули",
"share_link_doc": "Указывать ссылку на модуль после загрузки через .dlmod",
"modlink": "\n🌍 Ссылка: {}
",
+ "blob_link": "🚸 Не используй `blob` ссылки для загрузки модулей. Лучше загружать из `raw`",
}
def __init__(self):
self.config = loader.ModuleConfig(
loader.ConfigValue(
"MODULES_REPO",
- "https://mods.hikariatama.ru/",
+ "https://mods.hikariatama.ru",
lambda: self.strings("repo_config_doc"),
validator=loader.validators.Link(),
),
@@ -217,17 +170,17 @@ class LoaderMod(loader.Module):
"ADDITIONAL_REPOS",
# Currenly the trusted developers are specified
[
- "https://github.com/hikariatama/host/raw/master/",
- "https://github.com/MoriSummerz/ftg-mods/raw/main/",
- "https://gitlab.com/CakesTwix/friendly-userbot-modules/-/raw/master/",
+ "https://github.com/hikariatama/host/raw/master",
+ "https://github.com/MoriSummerz/ftg-mods/raw/main",
+ "https://github.com/iamnalinor/FTG-modules/raw/main",
+ "https://gitlab.com/CakesTwix/friendly-userbot-modules/-/raw/master",
],
lambda: self.strings("add_repo_config_doc"),
validator=loader.validators.Series(validator=loader.validators.Link()),
),
loader.ConfigValue(
"share_link",
- False,
- lambda: self.strings("share_link_doc"),
+ doc=lambda: self.strings("share_link_doc"),
validator=loader.validators.Boolean(),
),
)
@@ -283,22 +236,12 @@ class LoaderMod(loader.Module):
async def dlpresetcmd(self, message: Message) -> None:
"""Set modules preset"""
args = utils.get_args(message)
-
if not args:
await utils.answer(message, self.strings("select_preset"))
return
- try:
- await self.get_repo_list(args[0])
- except requests.exceptions.HTTPError as e:
- if e.response.status_code == 404:
- await utils.answer(message, self.strings("no_preset"))
- return
-
- raise
-
+ await self.get_repo_list(args[0])
self.set("chosen_preset", args[0])
- self.set("loaded_modules", {})
await utils.answer(message, self.strings("preset_loaded"))
await self.allmodules.commands["restart"](
@@ -306,7 +249,7 @@ class LoaderMod(loader.Module):
)
async def _get_modules_to_load(self):
- preset = self.get("chosen_preset", None)
+ preset = self.get("chosen_preset")
if preset != "disable":
possible_mods = (await self.get_repo_list(preset)).values()
@@ -318,15 +261,27 @@ class LoaderMod(loader.Module):
return todo
async def _get_repo(self, repo: str, preset: str) -> str:
+ repo = repo.strip("/")
+ preset_id = f"{repo}/{preset}"
+
+ if self._links_cache.get(preset_id, {}).get("exp", 0) >= time.time():
+ return self._links_cache[preset_id]["data"]
+
res = await utils.run_sync(
requests.get,
- f'{repo.strip("/")}/{preset}.txt',
+ f"{repo}/{preset}.txt",
)
+
if not str(res.status_code).startswith("2"):
logger.debug(f"Can't load {repo=}, {preset=}, {res.status_code=}")
- return ""
+ return []
- return res.text
+ self._links_cache[preset_id] = {
+ "exp": time.time() + 5 * 60,
+ "data": [link for link in res.text.strip().splitlines() if link],
+ }
+
+ return self._links_cache[preset_id]["data"]
async def get_repo_list(self, preset: Optional[str] = None):
if preset is None or preset == "none":
@@ -334,15 +289,8 @@ class LoaderMod(loader.Module):
return {
repo: {
- f"Preset_mod_{repo_id}_{i}": f'{repo.strip("/")}/{link}.py'
- for i, link in enumerate(
- set(
- filter(
- lambda x: x,
- (await self._get_repo(repo, preset)).split("\n"),
- )
- )
- )
+ f"Mod/{repo_id}/{i}": f'{repo.strip("/")}/{link}.py'
+ for i, link in enumerate(set(await self._get_repo(repo, preset)))
}
for repo_id, repo in enumerate(
[self.config["MODULES_REPO"]] + self.config["ADDITIONAL_REPOS"]
@@ -360,24 +308,38 @@ class LoaderMod(loader.Module):
del links[self.config["MODULES_REPO"]]
return main_repo + converter(links)
+ async def _find_link(self, module_name: str) -> Union[str, bool]:
+ links = await self.get_links_list()
+ return next(
+ (
+ link
+ for link in links
+ if link.lower().endswith(f"/{module_name.lower()}.py")
+ ),
+ False,
+ )
+
async def download_and_install(
self,
module_name: str,
message: Optional[Message] = None,
):
try:
+ blob_link = False
+ module_name = module_name.strip()
if urlparse(module_name).netloc:
url = module_name
+ if re.match(
+ r"^(https:\/\/github\.com\/.*?\/.*?\/blob\/.*\.py)|"
+ r"(https:\/\/gitlab\.com\/.*?\/.*?\/-\/blob\/.*\.py)$",
+ url,
+ ):
+ url = url.replace("/blob/", "/raw/")
+ blob_link = True
else:
- links = await self.get_links_list()
+ url = await self._find_link(module_name)
- try:
- url = next(
- link
- for link in links
- if link.lower().endswith(f"/{module_name.lower()}.py")
- )
- except Exception:
+ if not url:
if message is not None:
await utils.answer(message, self.strings("no_module"))
@@ -398,6 +360,7 @@ class LoaderMod(loader.Module):
message,
module_name,
url,
+ blob_link=blob_link,
)
except Exception:
logger.exception(f"Failed to load {module_name}")
@@ -421,10 +384,7 @@ class LoaderMod(loader.Module):
elif mode == "once":
save = True
- if path_ is not None:
- await self.load_module(doc, call, origin=path_, save_fs=save)
- else:
- await self.load_module(doc, call, save_fs=save)
+ await self.load_module(doc, call, origin=path_ or "