1
0
Fork 0
forked from zovos/bot_tg
bot_tg/games/nude.py
2026-04-10 11:20:14 +03:00

160 lines
5.4 KiB
Python
Raw 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.

import logging
import random
from pathlib import PurePosixPath
from urllib.parse import urlparse
import aiohttp
from aiogram import types
logger = logging.getLogger(__name__)
CAPTIONS = [
"Шо ты блять псюнчик решил свой подергать?",
"Решил подрочить сука?",
"гнойный писюн у тебя кнч, да",
]
LESAINT_POSTS_API = "https://lesaintdesseins.fr/wp-json/wp/v2/posts"
LESAINT_REFERER = "https://lesaintdesseins.fr/"
LATEST_POSTS_LIMIT = 30
REQUEST_HEADERS = {
"User-Agent": (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/124.0.0.0 Safari/537.36"
),
"Accept": "application/json,text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
"Referer": LESAINT_REFERER,
}
def _extract_photo_candidates(posts: list[dict]) -> list[dict]:
candidates = []
for post in posts:
embedded = post.get("_embedded") or {}
media_items = embedded.get("wp:featuredmedia") or []
for media in media_items:
if media.get("media_type") != "image":
continue
media_details = media.get("media_details") or {}
sizes = media_details.get("sizes") or {}
image_url = (
(sizes.get("full") or {}).get("source_url")
or media.get("source_url")
)
if not image_url:
continue
candidates.append(
{
"image_url": image_url,
"post_url": post.get("link", LESAINT_REFERER),
"title": (post.get("title") or {}).get("rendered", "").strip(),
}
)
break
return candidates
def _guess_filename(image_url: str) -> str:
parsed = urlparse(image_url)
filename = PurePosixPath(parsed.path).name or "nude.jpg"
if "." not in filename:
filename = f"{filename}.jpg"
return filename
async def _fetch_latest_photo_candidates(session: aiohttp.ClientSession) -> list[dict]:
params = {
"per_page": str(LATEST_POSTS_LIMIT),
"orderby": "date",
"order": "desc",
"_embed": "wp:featuredmedia",
}
async with session.get(LESAINT_POSTS_API, params=params, headers=REQUEST_HEADERS) as resp:
if resp.status != 200:
body = await resp.text()
raise RuntimeError(f"API returned {resp.status}: {body[:300]}")
posts = await resp.json(content_type=None)
if not isinstance(posts, list):
raise RuntimeError("Unexpected API response format")
return _extract_photo_candidates(posts)
async def _download_photo(
session: aiohttp.ClientSession, image_url: str
) -> tuple[bytes | None, str]:
async with session.get(image_url, headers=REQUEST_HEADERS) as resp:
if resp.status != 200:
logger.warning("Image download failed for %s: %s", image_url, resp.status)
return None, _guess_filename(image_url)
content_type = resp.headers.get("Content-Type", "")
if "image" not in content_type.lower():
logger.warning(
"Unexpected content type for %s: %s", image_url, content_type
)
return None, _guess_filename(image_url)
return await resp.read(), _guess_filename(image_url)
async def handle_nude_cmd(message: types.Message):
args = message.text.split(maxsplit=1)
if len(args) > 1 and args[1].strip() == "-h":
help_msg = (
"🔥 <b>Справка по команде /nude:</b>\n\n"
"Берет случайную фотку из последних постов сайта le saint des seins.\n"
"• Источник: <code>https://lesaintdesseins.fr/</code>\n"
"• Достает последние посты через WordPress REST API\n"
"• Выбирает случайную картинку и отправляет ее прямо в Telegram\n\n"
"<i>Пример:</i> <code>/nude</code>"
)
await message.reply(help_msg, parse_mode="HTML")
return
timeout = aiohttp.ClientTimeout(total=30)
try:
async with aiohttp.ClientSession(timeout=timeout) as session:
candidates = await _fetch_latest_photo_candidates(session)
if not candidates:
await message.reply("Не удалось найти свежие фотки :(")
return
selected = random.choice(candidates)
caption = random.choice(CAPTIONS)
image_bytes, filename = await _download_photo(session, selected["image_url"])
if image_bytes:
photo = types.BufferedInputFile(image_bytes, filename=filename)
await message.answer_photo(photo=photo, caption=caption)
return
try:
photo = types.URLInputFile(selected["image_url"])
await message.answer_photo(photo=photo, caption=caption)
except Exception:
logger.exception("Failed to send photo by URL")
await message.answer(
f"{caption}\n{selected['image_url']}\n{selected['post_url']}"
)
except Exception:
logger.exception("Error in nude command")
await message.reply("Произошла ошибка при получении фото :(")