# █▀▀ ▄▀█ █▀▄▀█ █▀█ █▀▄ █▀
# █▀░ █▀█ █░▀░█ █▄█ █▄▀ ▄█
# https://t.me/famods
# 🔒 Licensed under the GNU AGPLv3
# 🌐 https://www.gnu.org/licenses/agpl-3.0.html
# ---------------------------------------------------------------------------------
# Name: Ptichki
# Description: Генератор птиц
# meta developer: @FAmods
# meta banner: https://github.com/FajoX1/FAmods/blob/main/assets/banners/ptichki.png?raw=true
# requires: aiohttp pillow
# ---------------------------------------------------------------------------------
import json
import random
import aiohttp
import logging
from io import BytesIO
from PIL import Image, ImageDraw, ImageFont
from .. import loader, utils
logger = logging.getLogger(__name__)
@loader.tds
class Ptichki(loader.Module):
"""Генератор птиц"""
strings = {
"name": "Ptichki",
"no_args": "🦅 Нужно {}{} {}",
"generation": "🦅 Генерирую птичку...",
}
async def client_ready(self, client, db):
self.db = db
self._client = client
self.assets_link = "https://famods.fajox.one/assets"
self.font_url = f"{self.assets_link}/impact.ttf"
self.birds_url = f"{self.assets_link}/birds/birds.json"
async def fetch_bytes(self, url: str) -> bytes:
async with aiohttp.ClientSession() as session:
async with session.get(url) as resp:
resp.raise_for_status()
return await resp.read()
async def get_bird_url(self) -> str:
async with aiohttp.ClientSession() as session:
async with session.get(self.birds_url) as resp:
birds_list = json.loads(await resp.text())
return f"{self.assets_link}/birds/{random.choice(birds_list)}.png"
async def generate_bird(self, text: str, format: str) -> bytes:
text = text.upper()
img_bytes = await self.fetch_bytes(
await self.get_bird_url()
)
img = Image.open(BytesIO(img_bytes)).convert("RGBA")
img.thumbnail((512, 512))
width, height = img.size
draw = ImageDraw.Draw(img)
font_bytes = await self.fetch_bytes(self.font_url)
font_size = 55
min_font_size = 12
max_width_fraction = 0.9
font = ImageFont.truetype(BytesIO(font_bytes), font_size)
text_width = font.getlength(text)
if text_width > max_width_fraction * width:
scale = (max_width_fraction * width) / text_width
font_size = max(int(font_size * scale), min_font_size)
font = ImageFont.truetype(BytesIO(font_bytes), font_size)
bbox = draw.textbbox((0, 0), text, font=font)
text_width = bbox[2] - bbox[0]
text_height = bbox[3] - bbox[1]
x = (width - text_width) / 2
y = height - text_height - (height * 0.05)
draw.text(
(x, y),
text,
font=font,
fill="white",
stroke_width=2,
stroke_fill="black"
)
output = BytesIO()
img.save(output, format=format.upper())
output.seek(0)
output.name = f"ptitchka.{format.lower()}"
return output
@loader.command()
async def ptichka(self, message):
"""[текст] - Сгенерировать стикер с птицей"""
text = utils.get_args_raw(message)
if not text:
return await utils.answer(
message,
self.strings["no_args"].format(
self.get_prefix(), "ptichka", "[текст]"
)
)
m = await utils.answer(message, self.strings['generation'])
await self.client.send_file(
message.peer_id,
mime_type="image/webp",
file=await self.generate_bird(text, format="webp"),
reply_to=getattr(message.reply_to, "reply_to_msg_id", None),
)
return await m.delete()
@loader.command()
async def ptichka_img(self, message):
"""[текст] - Сгенерировать фото с птицей"""
text = utils.get_args_raw(message)
if not text:
return await utils.answer(
message,
self.strings["no_args"].format(
self.get_prefix(), "ptichka_img", "[текст]"
)
)
m = await utils.answer(message, self.strings['generation'])
await self.client.send_file(
message.peer_id,
mime_type="image/png",
file=await self.generate_bird(text, format="png"),
reply_to=getattr(message.reply_to, "reply_to_msg_id", None),
)
return await m.delete()