mirror of https://github.com/coddrago/Heroku
Patch
- New installation banner - Add automatic blob->raw convertion in loaderpull/1/head
parent
993b005adf
commit
dc7434e036
|
@ -29,6 +29,7 @@
|
|||
# scope: inline
|
||||
|
||||
import asyncio
|
||||
import contextlib
|
||||
import importlib
|
||||
import inspect
|
||||
import logging
|
||||
|
@ -36,6 +37,7 @@ import os
|
|||
import re
|
||||
import ast
|
||||
import sys
|
||||
import time
|
||||
import uuid
|
||||
from collections import ChainMap
|
||||
from importlib.machinery import ModuleSpec
|
||||
|
@ -52,66 +54,15 @@ from ..inline.types import InlineCall
|
|||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
VALID_URL = r"[-[\]_.~:/?#@!$&'()*+,;%<=>a-zA-Z0-9]+"
|
||||
|
||||
VALID_PIP_PACKAGES = re.compile(
|
||||
r"^\s*# ?requires:(?: ?)((?:{url} )*(?:{url}))\s*$".format(url=VALID_URL),
|
||||
r"^\s*# ?requires:(?: ?)((?:{url} )*(?:{url}))\s*$".format(
|
||||
url=r"[-[\]_.~:/?#@!$&'()*+,;%<=>a-zA-Z0-9]+"
|
||||
),
|
||||
re.MULTILINE,
|
||||
)
|
||||
|
||||
USER_INSTALL = "PIP_TARGET" not in os.environ and "VIRTUAL_ENV" not in os.environ
|
||||
|
||||
GIT_REGEX = re.compile(
|
||||
r"^https?://github\.com((?:/[a-z0-9-]+){2})(?:/tree/([a-z0-9-]+)((?:/[a-z0-9-]+)*))?/?$",
|
||||
flags=re.IGNORECASE,
|
||||
)
|
||||
|
||||
|
||||
def unescape_percent(text):
|
||||
i = 0
|
||||
ln = len(text)
|
||||
is_handling_percent = False
|
||||
out = ""
|
||||
|
||||
while i < ln:
|
||||
char = text[i]
|
||||
|
||||
if char == "%" and not is_handling_percent:
|
||||
is_handling_percent = True
|
||||
i += 1
|
||||
continue
|
||||
|
||||
if char == "d" and is_handling_percent:
|
||||
out += "."
|
||||
is_handling_percent = False
|
||||
i += 1
|
||||
continue
|
||||
|
||||
out += char
|
||||
is_handling_percent = False
|
||||
i += 1
|
||||
|
||||
return out
|
||||
|
||||
|
||||
def get_git_api(url):
|
||||
m = GIT_REGEX.search(url)
|
||||
|
||||
if m is None:
|
||||
return None
|
||||
|
||||
branch = m.group(2)
|
||||
path_ = m.group(3)
|
||||
api_url = f"https://api.github.com/repos{m.group(1)}/contents"
|
||||
|
||||
if path_ is not None and len(path_) > 0:
|
||||
api_url += path_
|
||||
|
||||
if branch:
|
||||
api_url += f"?ref={branch}"
|
||||
|
||||
return api_url
|
||||
|
||||
|
||||
@loader.tds
|
||||
class LoaderMod(loader.Module):
|
||||
|
@ -129,7 +80,7 @@ class LoaderMod(loader.Module):
|
|||
"provide_module": "<b>⚠️ Provide a module to load</b>",
|
||||
"bad_unicode": "<b>🚫 Invalid Unicode formatting in module</b>",
|
||||
"load_failed": "<b>🚫 Loading failed. See logs for details</b>",
|
||||
"loaded": "<b>🔭 Module </b><code>{}</code>{}<b> loaded {}</b>{}{}{}",
|
||||
"loaded": "<b>🔭 Module </b><code>{}</code>{}<b> loaded {}</b>{}{}{}\n\n{}",
|
||||
"no_class": "<b>What class needs to be unloaded?</b>",
|
||||
"unloaded": "<b>🧹 Module unloaded.</b>",
|
||||
"not_unloaded": "<b>🚫 Module not unloaded.</b>",
|
||||
|
@ -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🌍 <b>Link: </b><code>{}</code>",
|
||||
"blob_link": "🚸 <b>Do not use `blob` links to download modules. Consider switching to `raw` instead</b>",
|
||||
}
|
||||
|
||||
strings_ru = {
|
||||
|
@ -173,7 +125,7 @@ class LoaderMod(loader.Module):
|
|||
"provide_module": "<b>⚠️ Укажи модуль для загрузки</b>",
|
||||
"bad_unicode": "<b>🚫 Неверная кодировка модуля</b>",
|
||||
"load_failed": "<b>🚫 Загрузка не увенчалась успехом. Смотри логи.</b>",
|
||||
"loaded": "<b>🔭 Модуль </b><code>{}</code>{}<b> загружен {}</b>{}{}{}",
|
||||
"loaded": "<b>🔭 Модуль </b><code>{}</code>{}<b> загружен {}</b>{}{}{}\n\n{}",
|
||||
"no_class": "<b>А что выгружать то?</b>",
|
||||
"unloaded": "<b>🧹 Модуль выгружен.</b>",
|
||||
"not_unloaded": "<b>🚫 Модуль не выгружен.</b>",
|
||||
|
@ -203,13 +155,14 @@ class LoaderMod(loader.Module):
|
|||
"_cls_doc": "Загружает модули",
|
||||
"share_link_doc": "Указывать ссылку на модуль после загрузки через .dlmod",
|
||||
"modlink": "\n🌍 <b>Ссылка: </b><code>{}</code>",
|
||||
"blob_link": "🚸 <b>Не используй `blob` ссылки для загрузки модулей. Лучше загружать из `raw`</b>",
|
||||
}
|
||||
|
||||
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 "<string>", save_fs=save)
|
||||
|
||||
@loader.owner
|
||||
async def loadmodcmd(self, message: Message) -> None:
|
||||
|
@ -526,6 +486,7 @@ class LoaderMod(loader.Module):
|
|||
origin: Optional[str] = "<string>",
|
||||
did_requirements: Optional[bool] = False,
|
||||
save_fs: Optional[bool] = False,
|
||||
blob_link: Optional[bool] = False,
|
||||
) -> None:
|
||||
if any(
|
||||
line.replace(" ", "") == "#scope:ffmpeg" for line in doc.splitlines()
|
||||
|
@ -543,10 +504,7 @@ class LoaderMod(loader.Module):
|
|||
return
|
||||
|
||||
if re.search(r"# ?scope: ?hikka_min", doc):
|
||||
ver = re.search(
|
||||
r"# ?scope: ?hikka_min ([0-9]+\.[0-9]+\.[0-9]+)",
|
||||
doc,
|
||||
).group(1)
|
||||
ver = re.search(r"# ?scope: ?hikka_min ((\d+\.){2}\d+)", doc).group(1)
|
||||
ver_ = tuple(map(int, ver.split(".")))
|
||||
if main.__version__ < ver_:
|
||||
if isinstance(message, Message):
|
||||
|
@ -580,6 +538,8 @@ class LoaderMod(loader.Module):
|
|||
else ""
|
||||
)
|
||||
|
||||
blob_link = self.strings("blob_link") if blob_link else ""
|
||||
|
||||
if name is None:
|
||||
try:
|
||||
node = ast.parse(doc)
|
||||
|
@ -625,7 +585,7 @@ class LoaderMod(loader.Module):
|
|||
lambda x: not x.startswith(("-", "_", ".")),
|
||||
map(
|
||||
str.strip,
|
||||
VALID_PIP_PACKAGES.search(doc)[1].split(" "),
|
||||
VALID_PIP_PACKAGES.search(doc)[1].split(),
|
||||
),
|
||||
)
|
||||
)
|
||||
|
@ -681,19 +641,10 @@ class LoaderMod(loader.Module):
|
|||
|
||||
importlib.invalidate_caches()
|
||||
|
||||
return await self.load_module(
|
||||
doc,
|
||||
message,
|
||||
name,
|
||||
origin,
|
||||
True,
|
||||
save_fs,
|
||||
) # Try again
|
||||
return await self.load_module(utils.get_kwargs()) # Try again
|
||||
except loader.LoadError as e:
|
||||
try:
|
||||
with contextlib.suppress(ValueError):
|
||||
self.allmodules.modules.remove(instance) # skipcq: PYL-E0601
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if message:
|
||||
await utils.answer(message, f"🚫 <b>{utils.escape_html(str(e))}</b>")
|
||||
|
@ -725,20 +676,16 @@ class LoaderMod(loader.Module):
|
|||
from_dlmod=bool(message),
|
||||
)
|
||||
except loader.LoadError as e:
|
||||
try:
|
||||
with contextlib.suppress(ValueError):
|
||||
self.allmodules.modules.remove(instance)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if message:
|
||||
await utils.answer(message, f"🚫 <b>{utils.escape_html(str(e))}</b>")
|
||||
return
|
||||
except loader.SelfUnload as e:
|
||||
logging.debug(f"Unloading {instance}, because it raised `SelfUnload`")
|
||||
try:
|
||||
with contextlib.suppress(ValueError):
|
||||
self.allmodules.modules.remove(instance)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if message:
|
||||
await utils.answer(message, f"🚫 <b>{utils.escape_html(str(e))}</b>")
|
||||
|
@ -768,23 +715,23 @@ class LoaderMod(loader.Module):
|
|||
if instance.__doc__:
|
||||
modhelp += f"<i>\nℹ️ {utils.escape_html(inspect.getdoc(instance))}</i>\n"
|
||||
|
||||
loaded_msg = lambda: self.strings("loaded").format(
|
||||
modname.strip(),
|
||||
version,
|
||||
utils.ascii_face(),
|
||||
modhelp,
|
||||
developer,
|
||||
self.strings("modlink").format(origin)
|
||||
if origin != "<string>" and self.config["share_link"]
|
||||
else "",
|
||||
blob_link,
|
||||
)
|
||||
|
||||
if any(
|
||||
line.replace(" ", "") == "#scope:disable_onload_docs"
|
||||
for line in doc.splitlines()
|
||||
):
|
||||
await utils.answer(
|
||||
message,
|
||||
self.strings("loaded").format(
|
||||
modname.strip(),
|
||||
version,
|
||||
utils.ascii_face(),
|
||||
modhelp,
|
||||
developer,
|
||||
self.strings("modlink").format(origin)
|
||||
if origin != "<string>" and self.config["share_link"]
|
||||
else "",
|
||||
),
|
||||
)
|
||||
await utils.answer(message, loaded_msg())
|
||||
return
|
||||
|
||||
for _name, fun in sorted(
|
||||
|
@ -817,32 +764,9 @@ class LoaderMod(loader.Module):
|
|||
)
|
||||
|
||||
try:
|
||||
await utils.answer(
|
||||
message,
|
||||
self.strings("loaded").format(
|
||||
modname.strip(),
|
||||
version,
|
||||
utils.ascii_face(),
|
||||
modhelp,
|
||||
developer,
|
||||
self.strings("modlink").format(origin)
|
||||
if origin != "<string>" and self.config["share_link"]
|
||||
else "",
|
||||
),
|
||||
)
|
||||
await utils.answer(message, loaded_msg())
|
||||
except telethon.errors.rpcerrorlist.MediaCaptionTooLongError:
|
||||
await message.reply(
|
||||
self.strings("loaded").format(
|
||||
modname.strip(),
|
||||
version,
|
||||
utils.ascii_face(),
|
||||
modhelp,
|
||||
developer,
|
||||
self.strings("modlink").format(origin)
|
||||
if origin != "<string>" and self.config["share_link"]
|
||||
else "",
|
||||
)
|
||||
)
|
||||
await message.reply(loaded_msg())
|
||||
|
||||
@loader.owner
|
||||
async def unloadmodcmd(self, message: Message) -> None:
|
||||
|
@ -913,6 +837,8 @@ class LoaderMod(loader.Module):
|
|||
self._client = client
|
||||
self._fully_loaded = False
|
||||
|
||||
self._links_cache = {}
|
||||
|
||||
self.allmodules.add_aliases(self.lookup("settings").get("aliases", {}))
|
||||
|
||||
main.hikka.ready.set()
|
||||
|
@ -932,6 +858,7 @@ class LoaderMod(loader.Module):
|
|||
)
|
||||
|
||||
asyncio.ensure_future(self._update_modules())
|
||||
asyncio.ensure_future(self.get_repo_list("full"))
|
||||
|
||||
@loader.loop(interval=3, wait_before=True, autostart=True)
|
||||
async def _modules_config_autosaver(self):
|
||||
|
@ -944,7 +871,7 @@ class LoaderMod(loader.Module):
|
|||
continue
|
||||
|
||||
delattr(mod.config._config[option], "_save_marker")
|
||||
self._db.setdefault(mod.__class__.__name__, {},).setdefault(
|
||||
self._db.setdefault(mod.__class__.__name__, {}).setdefault(
|
||||
"__config__", {}
|
||||
)[option] = config.value
|
||||
self._db.save()
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
</div>
|
||||
<div class="wrapper">
|
||||
<div class="blur main finish_block">
|
||||
<div id="installation_icon"></div>
|
||||
<div class="title">Hikka is installed</div>
|
||||
<div class="description">
|
||||
{% if heroku %}
|
||||
|
|
|
@ -162,6 +162,18 @@ body {
|
|||
top: 0;
|
||||
height: 50vh;
|
||||
}
|
||||
|
||||
.title {
|
||||
height: auto;
|
||||
line-height: auto;
|
||||
}
|
||||
|
||||
.finish_block, .auth {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes floating {
|
||||
|
@ -248,3 +260,8 @@ label {
|
|||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#installation_icon {
|
||||
height: 200px;
|
||||
margin-bottom: 35px;
|
||||
}
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
function auth(callback) {
|
||||
bodymovin.loadAnimation({
|
||||
container: document.getElementById("tg_icon"),
|
||||
renderer: 'canvas',
|
||||
loop: true,
|
||||
autoplay: true,
|
||||
path: 'https://raw.githubusercontent.com/hikariatama/Hikka/master/assets/noface.json',
|
||||
rendererSettings: {
|
||||
clearCanvas: true,
|
||||
}
|
||||
});
|
||||
$(".main").fadeOut(500, () => {
|
||||
$(".auth").hide().fadeIn(500);
|
||||
bodymovin.loadAnimation({
|
||||
container: document.getElementById("tg_icon"),
|
||||
renderer: 'canvas',
|
||||
loop: true,
|
||||
autoplay: true,
|
||||
path: 'https://raw.githubusercontent.com/hikariatama/Hikka/master/assets/noface.json',
|
||||
rendererSettings: {
|
||||
clearCanvas: true,
|
||||
}
|
||||
});
|
||||
fetch("/web_auth", {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
|
@ -80,6 +80,16 @@ function finish_login() {
|
|||
.then(() => {
|
||||
window.expanse = true;
|
||||
$(".installation").fadeOut(2000, () => {
|
||||
bodymovin.loadAnimation({
|
||||
container: document.getElementById("installation_icon"),
|
||||
renderer: 'canvas',
|
||||
loop: true,
|
||||
autoplay: true,
|
||||
path: 'https://assets1.lottiefiles.com/animated_stickers/lf_tgs_j7miwfxd.json',
|
||||
rendererSettings: {
|
||||
clearCanvas: true,
|
||||
}
|
||||
});
|
||||
$(".finish_block").fadeIn(300);
|
||||
});
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue