some fix for nude

This commit is contained in:
q 2026-04-10 11:17:45 +03:00
parent 06d97cbff0
commit 7afd8ca216

View file

@ -1,108 +1,159 @@
import aiohttp
from aiogram import types
import config
import logging import logging
import random import random
import re from pathlib import PurePosixPath
from urllib.parse import urlparse
import aiohttp
from aiogram import types
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
CAPTIONS = [ CAPTIONS = [
"Hot stuff 🔥", "Hot stuff 🔥",
"Sexy content 😏" "Sexy content 😏",
] ]
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): async def handle_nude_cmd(message: types.Message):
args = message.text.split(maxsplit=1) args = message.text.split(maxsplit=1)
if len(args) > 1 and args[1].strip() == "-h": if len(args) > 1 and args[1].strip() == "-h":
help_msg = ( help_msg = (
"🔥 <b>Справка по команде /nude:</b>\n\n" "🔥 <b>Справка по команде /nude:</b>\n\n"
"Получает случайные изображения взрослых женщин из открытых источников.\n" "Берет случайную фотку из последних постов сайта le saint des seins.\n"
"• Использует прямое сканирование сайтов для поиска контента\n" "• Источник: <code>https://lesaintdesseins.fr/</code>\n"
"• По умолчанию ищет популярные изображения\n" "• Достает последние посты через WordPress REST API\n"
"• Отправляет изображения напрямую\n\n" "• Выбирает случайную картинку и отправляет ее прямо в Telegram\n\n"
"<i>Пример:</i> <code>/nude</code>\n" "<i>Пример:</i> <code>/nude</code>"
"<i>По умолчанию:</i> Случайные изображения с популярных сайтов"
) )
await message.reply(help_msg, parse_mode="HTML") await message.reply(help_msg, parse_mode="HTML")
return return
# Список сайтов для сканирования timeout = aiohttp.ClientTimeout(total=30)
sites = [
"https://www.imagefap.com/gallery.php?pg=random",
"https://xhamster.com/photos?sort=random",
"https://spankbang.com/random"
]
random_site = random.choice(sites)
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": "gzip, deflate",
"Connection": "keep-alive",
"Upgrade-Insecure-Requests": "1"
}
try: try:
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession(timeout=timeout) as session:
async with session.get(random_site, headers=headers) as resp: candidates = await _fetch_latest_photo_candidates(session)
if resp.status != 200:
logger.error(f"Site access error: {resp.status}") if not candidates:
await message.reply("Не удалось получить доступ к сайту :(") await message.reply("Не удалось найти свежие фотки :(")
return return
html = await resp.text() selected = random.choice(candidates)
# Ищем URL изображений в HTML
img_patterns = [
r'<img[^>]+src="([^"]+)"',
r'<a[^>]+href="([^"]+\.(jpg|jpeg|png|gif|webp))"',
r'data-src="([^"]+)"'
]
img_urls = []
for pattern in img_patterns:
matches = re.findall(pattern, html, re.IGNORECASE)
img_urls.extend(matches)
if not img_urls:
await message.reply("Изображения не найдены на странице :(")
return
# Фильтруем и выбираем случайное изображение
valid_imgs = []
for img_url in img_urls:
if img_url.startswith('//'):
img_url = 'https:' + img_url
elif img_url.startswith('/'):
if 'imagefap.com' in random_site:
img_url = 'https://www.imagefap.com' + img_url
elif 'xhamster.com' in random_site:
img_url = 'https://xhamster.com' + img_url
elif 'spankbang.com' in random_site:
img_url = 'https://spankbang.com' + img_url
if any(ext in img_url.lower() for ext in ['.jpg', '.jpeg', '.png', '.gif', '.webp']):
valid_imgs.append(img_url)
if not valid_imgs:
await message.reply("Подходящие изображения не найдены :(")
return
final_img_url = random.choice(valid_imgs)
caption = random.choice(CAPTIONS) 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: try:
input_file = types.URLInputFile(final_img_url) photo = types.URLInputFile(selected["image_url"])
await message.answer_photo(photo=input_file, caption=caption) await message.answer_photo(photo=photo, caption=caption)
except Exception as e: except Exception:
logger.error(f"Error sending photo: {e}") logger.exception("Failed to send photo by URL")
await message.answer(f"{caption}\n{final_img_url}") await message.answer(
f"{caption}\n{selected['image_url']}\n{selected['post_url']}"
)
except Exception as e: except Exception:
logger.exception("Error in nude command") logger.exception("Error in nude command")
await message.reply("Произошла ошибка при обработке запроса :(") await message.reply("Произошла ошибка при получении фото :(")