Files
limoka/fiksofficial/python-modules/IwaAnimation.py
2026-04-18 01:49:10 +00:00

204 lines
8.2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ______ ___ ___ _ _
# ____ | ___ \ | \/ | | | | |
# / __ \| |_/ / _| . . | ___ __| |_ _| | ___
# / / _` | __/ | | | |\/| |/ _ \ / _` | | | | |/ _ \
# | | (_| | | | |_| | | | | (_) | (_| | |_| | | __/
# \ \__,_\_| \__, \_| |_/\___/ \__,_|\__,_|_|\___|
# \____/ __/ |
# |___/
# На модуль распространяется лицензия "GNU General Public License v3.0"
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
# meta developer: @pymodule
import asyncio
import os
import toml
from .. import loader, utils
from herokutl.tl.types import Message
@loader.tds
class IwaAnimation(loader.Module):
"""Frame-by-frame text animations loaded from .anim TOML files"""
strings = {
"name": "IwaAnimation",
"err_no_reply": "<b>{e} Reply to a .anim file.</b>",
"err_not_anim": "<b>{e} File must have .anim extension.</b>",
"err_bad_format": "<b>{e} Invalid file format (missing name or cmd).</b>",
"err_no_frames": "<b>{e} No frames found in the file.</b>",
"err_not_found": "<b>{e} Animation not found.</b>",
"err_no_cmd": "<b>{e} Specify a command name.</b>",
"err_generic": "<b>{e} Error:</b>\n\n{exc}",
"ok_loaded": "<b>{s} Loaded: {name}\nCommand: <code>.anim {cmd}</code></b>",
"ok_deleted": "<b>{s} Deleted.</b>",
"list_header": "<blockquote><b>Animations:</b></blockquote>\n\n<blockquote expandable><b>",
"list_row": "• <code>{cmd}</code> — {name} ({n} frames)\n",
"list_footer": "</b></blockquote>",
"list_empty": "<b>{e} No animations.</b>",
}
strings_ru = {
"name": "IwaAnimation",
"err_no_reply": "<b>{e} Ответьте на .anim файл.</b>",
"err_not_anim": "<b>{e} Файл должен быть формата .anim</b>",
"err_bad_format": "<b>{e} Неверный формат файла (нет name или cmd).</b>",
"err_no_frames": "<b>{e} В файле нет кадров.</b>",
"err_not_found": "<b>{e} Анимация не найдена.</b>",
"err_no_cmd": "<b>{e} Укажи команду.</b>",
"err_generic": "<b>{e} Ошибка:</b>\n\n{exc}",
"ok_loaded": "<b>{s} Загружено: {name}\nКоманда: <code>.anim {cmd}</code></b>",
"ok_deleted": "<b>{s} Удалено.</b>",
"list_header": "<blockquote><b>Анимации:</b></blockquote>\n\n<blockquote expandable><b>",
"list_row": "• <code>{cmd}</code> — {name} ({n} кадров)\n",
"list_footer": "</b></blockquote>",
"list_empty": "<b>{e} Нет анимаций.</b>",
}
_E = "<emoji document_id=5774077015388852135>❌</emoji>"
_S = "<emoji document_id=5774022692642492953>✅</emoji>"
async def client_ready(self):
if not self.db.get("IwaAnimations", "anims", False):
self.db.set("IwaAnimations", "anims", {})
@loader.command(ru_doc="- Загрузить анимацию из полученного .anim файла")
async def lanimcmd(self, message: Message):
"""- Load animation from a replied .anim file"""
reply = await message.get_reply_message()
if not reply or not reply.document:
return await utils.answer(
message, self.strings["err_no_reply"].format(e=self._E)
)
filename = reply.file.name or ""
if not filename.endswith(".anim"):
return await utils.answer(
message, self.strings["err_not_anim"].format(e=self._E)
)
tmp = "anim_load.anim"
await reply.download_media(tmp)
try:
data = toml.load(tmp)
name = data.get("name")
cmd = data.get("cmd")
delay = float(data.get("time", 0.5))
if not name or not cmd:
return await utils.answer(
message, self.strings["err_bad_format"].format(e=self._E)
)
frames = []
for key in sorted(
(k for k in data if str(k).isdigit()), key=lambda x: int(x)
):
frame = data[key]
frames.append("\n".join(frame) if isinstance(frame, list) else str(frame))
if not frames:
return await utils.answer(
message, self.strings["err_no_frames"].format(e=self._E)
)
anims = self.db.get("IwaAnimations", "anims", {})
anims[cmd] = {"name": name, "frames": frames, "delay": delay}
self.db.set("IwaAnimations", "anims", anims)
await utils.answer(
message,
self.strings["ok_loaded"].format(s=self._S, name=name, cmd=cmd),
)
except Exception as exc:
await utils.answer(
message, self.strings["err_generic"].format(e=self._E, exc=exc)
)
finally:
if os.path.exists(tmp):
os.remove(tmp)
@loader.command(ru_doc="<cmd> - Воспроизвести загруженную анимацию")
async def animcmd(self, message: Message):
"""<cmd> - Play a loaded animation"""
cmd = utils.get_args_raw(message)
if not cmd:
return await utils.answer(
message, self.strings["err_no_cmd"].format(e=self._E)
)
anims = self.db.get("IwaAnimations", "anims", {})
if cmd not in anims:
return await utils.answer(
message, self.strings["err_not_found"].format(e=self._E)
)
anim = anims[cmd]
msg = await utils.answer(message, anim["frames"][0])
try:
for frame in anim["frames"][1:]:
await asyncio.sleep(anim["delay"])
await msg.edit(frame)
except Exception:
pass
@loader.command(ru_doc="- Отобразить список всех загруженных анимаций")
async def animscmd(self, message: Message):
"""- List all loaded animations"""
anims = self.db.get("IwaAnimations", "anims", {})
if not anims:
return await utils.answer(
message, self.strings["list_empty"].format(e=self._E)
)
text = self.strings["list_header"]
for cmd, data in anims.items():
text += self.strings["list_row"].format(
cmd=cmd, name=data["name"], n=len(data["frames"])
)
text += self.strings["list_footer"]
await utils.answer(message, text)
@loader.command(ru_doc="<cmd> - Удалить анимацию")
async def delanimcmd(self, message: Message):
"""<cmd> - Delete an animation"""
cmd = utils.get_args_raw(message)
anims = self.db.get("IwaAnimations", "anims", {})
if cmd not in anims:
return await utils.answer(
message, self.strings["err_not_found"].format(e=self._E)
)
anims.pop(cmd)
self.db.set("IwaAnimations", "anims", anims)
await utils.answer(message, self.strings["ok_deleted"].format(s=self._S))
@loader.command(ru_doc="<cmd> - Экспорт анимации в файл .anim")
async def dumpanimcmd(self, message: Message):
"""<cmd> - Export an animation to a .anim file"""
cmd = utils.get_args_raw(message)
anims = self.db.get("IwaAnimations", "anims", {})
if cmd not in anims:
return await utils.answer(
message, self.strings["err_not_found"].format(e=self._E)
)
anim = anims[cmd]
data = {"name": anim["name"], "cmd": cmd, "time": str(anim["delay"])}
for i, frame in enumerate(anim["frames"], start=1):
data[str(i)] = frame.split("\n")
file = f"{cmd}.anim"
try:
with open(file, "w", encoding="utf-8") as f:
toml.dump(data, f)
await message.delete()
await self._client.send_file(message.to_id, file)
finally:
if os.path.exists(file):
os.remove(file)