It's version 0.6.2 I clear code

This commit is contained in:
Niken
2025-11-23 23:17:00 +03:00
parent b6c1c60609
commit 7495062a8a
15 changed files with 183 additions and 97 deletions
+3
View File
@@ -18,3 +18,6 @@ storage/message.txt
/addons/todo/todo.db /addons/todo/todo.db
/addons/rule34/urls.db /addons/rule34/urls.db
/addons/x_days_to/days_to_new_year.db /addons/x_days_to/days_to_new_year.db
/addons/hello/photo_2025-11-17_20-57-54.jpg
/addons/poll/img.png
/addons/hello/мемы/
-1
View File
@@ -1,6 +1,5 @@
def register(dp, state, bot): def register(dp, state, bot):
from . import handlers from . import handlers
handlers.register_handlers(dp, state, bot) handlers.register_handlers(dp, state, bot)
@@ -13,7 +13,7 @@ from mutagen.id3 import ID3, APIC, error
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
async def get_video_info(url: str) -> dict: async def get_video_info(url: str) -> Optional[dict]:
"""Получает информацию о видео через yt-dlp""" """Получает информацию о видео через yt-dlp"""
try: try:
process = await asyncio.create_subprocess_exec( process = await asyncio.create_subprocess_exec(
@@ -63,8 +63,8 @@ def apply_metadata(mp3_path: str, metadata: dict):
# Сначала удаляем старые теги ID3 если есть # Сначала удаляем старые теги ID3 если есть
try: try:
ID3(mp3_path).delete() ID3(mp3_path).delete()
except: except Exception as e:
pass logger.warning(f"Не удалось удалить старые ID3 теги: {e}")
# Добавляем текстовые теги # Добавляем текстовые теги
try: try:
+15 -10
View File
@@ -3,7 +3,7 @@ import base64
from io import BytesIO from io import BytesIO
import asyncio import asyncio
import aiohttp import aiohttp
from PIL import Image
from aiogram import Dispatcher, Bot from aiogram import Dispatcher, Bot
from aiogram.types import Message, BufferedInputFile from aiogram.types import Message, BufferedInputFile
from aiogram.filters import Command from aiogram.filters import Command
@@ -43,6 +43,11 @@ async def generate_img2img(prompt: str, init_image: BytesIO) -> BytesIO | None:
:return: BytesIO с результатом или None при ошибке :return: BytesIO с результатом или None при ошибке
""" """
try: try:
# Определяем размеры оригинала
init_image.seek(0)
with Image.open(init_image) as img:
width, height = img.size
# кодируем входное изображение в base64 # кодируем входное изображение в base64
init_image_base64 = base64.b64encode(init_image.getvalue()).decode("utf-8") init_image_base64 = base64.b64encode(init_image.getvalue()).decode("utf-8")
@@ -50,15 +55,15 @@ async def generate_img2img(prompt: str, init_image: BytesIO) -> BytesIO | None:
"init_images": [init_image_base64], "init_images": [init_image_base64],
"prompt": prompt, "prompt": prompt,
"negative_prompt": "blurry, low quality, bad anatomy, watermark, text, cropped", "negative_prompt": "blurry, low quality, bad anatomy, watermark, text, cropped",
"steps": 20, # можно 1520 "steps": 25,
"width": 1024, # лучше подставлять размеры исходного фото "width": width, # берём ширину оригинала
"height": 1024, "height": height, # берём высоту оригинала
"sampler_name": "Euler a", # мягкий и стабильный для img2img "sampler_name": "Euler a",
"Schedule_type": "Karras", "scheduler": "Karras", # исправлен ключ
"cfg_scale": 6, # чуть ниже, чем для txt2img "cfg_scale": 10,
"seed": -1, "seed": -1,
"denoising_strength": 0.8, # 0.3–0.5 для «сохранить стиль», 0.6–0.8 для «перерисовать» "denoising_strength": 0.45,
"restore_faces": True, # если работаешь с людьми "restore_faces": True,
"override_settings": { "override_settings": {
"sd_model_checkpoint": "waiNSFWIllustrious_v150.safetensors" "sd_model_checkpoint": "waiNSFWIllustrious_v150.safetensors"
}, },
@@ -101,7 +106,7 @@ async def generate_image(prompt: str) -> BytesIO | None:
"hr_scale": 2, # во сколько раз увеличить при highres fix "hr_scale": 2, # во сколько раз увеличить при highres fix
"hr_upscaler": "Latent", # апскейлер для highres fix "hr_upscaler": "Latent", # апскейлер для highres fix
"override_settings": { "override_settings": {
"sd_model_checkpoint": "waiNSFWIllustrious_v150.safetensors" # выбор модели "sd_model_checkpoint": "sd_xl_base_1.safetensors" # выбор модели
}, },
} }
+42 -8
View File
@@ -1,32 +1,66 @@
from aiogram import Dispatcher, Bot from aiogram import Dispatcher, Bot
from aiogram.types import Message from aiogram.types import Message, FSInputFile
from aiogram.filters import Command from aiogram.filters import Command
from models.state import BotState from models.state import BotState
from config import Config from config import Config
import logging import logging
from utils.antispam import admin_required from utils.antispam import admin_required
from storage.message_storage import save_message # импортируем функцию from storage.message_storage import save_message # импортируем функцию
import os
import asyncio
from random import choice, seed
from time import time
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
async def list_files():
# Запускаем синхронный os.listdir в отдельном потоке
return await asyncio.to_thread(os.listdir, "/Users/mac/myfirstprogramm/addons/hello/мемы")
def register_handlers(dp: Dispatcher, state: BotState, bot: Bot): def register_handlers(dp: Dispatcher, state: BotState, bot: Bot):
i = 0
@dp.message(Command("hello")) @dp.message(Command("hello"))
@admin_required(1) @admin_required(1)
async def hello(message: Message): async def hello(message: Message):
# сохраняем саму команду пользователя # сохраняем саму команду пользователя
nonlocal i
save_message(message.chat.id, message.message_id) save_message(message.chat.id, message.message_id)
for admin_id in Config.ADMINS: for admin_id in Config.ADMINS:
try: try:
name = Config.Names.get(admin_id, "Админ") if 1345058877 == admin_id:
msg = await bot.send_message( name = Config.Names.get(admin_id, "Админ")
chat_id=admin_id, text=f"🤖 Я готов к работе, господин {name}!" photo = FSInputFile("/Users/mac/myfirstprogramm/addons/hello/photo_2025-11-17_20-57-54.jpg")
) msg = await bot.send_photo(
# сохраняем сообщение, отправленное админу chat_id=admin_id, photo=photo, caption=f"🤖 Я готов к работе, господин {name}!"
save_message(msg.chat.id, msg.message_id) )
logger.info(f"Сообщение отправлено админу {admin_id} ({name})") save_message(msg.chat.id, msg.message_id)
logger.info(f"Фото отправлено админу {admin_id} ({name})")
elif 6394047531 == admin_id:
png = choice(await list_files())
i += 1
seed(time() + i)
name = Config.Names.get(admin_id, "Админ")
photo = FSInputFile(f"/Users/mac/myfirstprogramm/addons/hello/мемы/{png}")
msg = await bot.send_photo(
chat_id=admin_id, photo=photo, caption=f"🤖 Я готов к работе, господин {name}!"
)
save_message(msg.chat.id, msg.message_id)
logger.info(f"Фото {f"/Users/mac/myfirstprogramm/addons/hello/мемы/{png}"} отправлено админу {admin_id} ({name})")
else:
name = Config.Names.get(admin_id, "Админ")
msg = await bot.send_message(
chat_id=admin_id, text=f"🤖 Я готов к работе, господин {name}!"
)
# сохраняем сообщение, отправленное админу
save_message(msg.chat.id, msg.message_id)
logger.info(f"Сообщение отправлено админу {admin_id} ({name})")
except Exception as e: except Exception as e:
logger.error(f"Ошибка при отправке админу {admin_id}: {e}") logger.error(f"Ошибка при отправке админу {admin_id}: {e}")
+24 -5
View File
@@ -3,7 +3,6 @@ from aiogram import Dispatcher, Bot
from aiogram.types import Message from aiogram.types import Message
from aiogram.filters import Command from aiogram.filters import Command
from models.state import BotState from models.state import BotState
from utils.antispam import saving
API_URL = "http://127.0.0.1:7700/speak" API_URL = "http://127.0.0.1:7700/speak"
@@ -12,7 +11,27 @@ logger = getLogger(__name__)
def register_handlers(dp: Dispatcher, state: BotState, bot: Bot): def register_handlers(dp: Dispatcher, state: BotState, bot: Bot):
@dp.message(Command("id")) @dp.message(Command("id"))
@saving async def id_handler(message: Message):
async def id(message: Message): # Разбираем аргументы команды
id = message.from_user.id args = message.text.split()
msg = await message.reply(str(id)) if len(args) > 1:
try:
user_id = int(args[1]) # берём ID из аргумента
except ValueError:
await message.reply("ID должен быть числом")
return
else:
# если аргумента нет — берём ID самого пользователя
user_id = message.from_user.id
# Получаем фото профиля
photos = await bot.get_user_profile_photos(user_id=user_id)
if photos.total_count > 0:
for i, photo_sizes in enumerate(photos.photos):
file_id = photo_sizes[-1].file_id # самое большое разрешение
await message.answer_photo(file_id, caption=f"Аватар #{i + 1}")
await message.reply(f"ID пользователя: {user_id}")
else:
await message.reply(f"У пользователя {user_id} нет аватара")
+22 -12
View File
@@ -1,7 +1,7 @@
from config import Config from config import Config
from utils.antispam import admin_required from utils.antispam import admin_required
from aiogram import Dispatcher, Bot from aiogram import Dispatcher, Bot
from aiogram.types import Message from aiogram.types import Message, FSInputFile
from models.state import BotState from models.state import BotState
from aiogram.filters import Command from aiogram.filters import Command
from logging import getLogger from logging import getLogger
@@ -20,7 +20,7 @@ def register_handlers(dp: Dispatcher, state: BotState, bot: Bot):
poll_msg = await bot.send_poll( poll_msg = await bot.send_poll(
chat_id=chat_id, chat_id=chat_id,
question="Кто опоздает?", question="Кто опоздает?",
options=["Я", "Я очень сильно опоздаю", "Я пиздец как опоздаю", "Наверное", "Не опоздаю"], options=["Я", "Я очень сильно опоздаю", "Я пиздец как опоздаю", "Наверное", "я ДОЛБОЯЩЕР и я к 2 паре", "Не опоздаю"],
is_anonymous=False, is_anonymous=False,
allows_multiple_answers=False, allows_multiple_answers=False,
) )
@@ -44,39 +44,49 @@ def register_handlers(dp: Dispatcher, state: BotState, bot: Bot):
# всегда пишем в первый чат из Config.CHAT_IDS # всегда пишем в первый чат из Config.CHAT_IDS
# 6394047531 # 6394047531
#850906163
STARAST = 6394047531
if option_ids and option_ids[0] == 0: if not option_ids:
msg = await bot.send_message( msg = await bot.send_message(
chat_id=6394047531, text=f"{username} опоздает" chat_id=STARAST, text=f"{username} Отменил свой голос"
)
save_message(msg.chat.id, msg.message_id)
elif option_ids and option_ids[0] == 0:
msg = await bot.send_message(
chat_id=STARAST, text=f"{username} опоздает"
) )
save_message(msg.chat.id, msg.message_id) save_message(msg.chat.id, msg.message_id)
elif option_ids and option_ids[0] == 1: elif option_ids and option_ids[0] == 1:
msg = await bot.send_message( msg = await bot.send_message(
chat_id=6394047531, text=f"{username} сильно опоздает" chat_id=STARAST, text=f"{username} сильно опоздает"
) )
save_message(msg.chat.id, msg.message_id) save_message(msg.chat.id, msg.message_id)
elif option_ids and option_ids[0] == 2: elif option_ids and option_ids[0] == 2:
msg = await bot.send_message( msg = await bot.send_message(
chat_id=6394047531, text=f"{username} Пиздец опоздает" chat_id=STARAST, text=f"{username} Пиздец опоздает"
) )
save_message(msg.chat.id, msg.message_id) save_message(msg.chat.id, msg.message_id)
elif option_ids[0] == 3: elif option_ids[0] == 3:
msg = await bot.send_message( msg = await bot.send_message(
chat_id=6394047531, text=f"{username} возможно опоздает" chat_id=STARAST, text=f"{username} возможно опоздает"
) )
save_message(msg.chat.id, msg.message_id) save_message(msg.chat.id, msg.message_id)
elif option_ids[0] == 4: elif option_ids[0] == 4:
msg = await bot.send_message( photo = FSInputFile("/Users/mac/myfirstprogramm/addons/poll/img.png")
chat_id=6394047531, text=f"{username} возможно опоздает" msg = await bot.send_photo(
chat_id=STARAST, photo=photo, caption=f"{username} ДОЛБОЯЩЕР"
) )
save_message(msg.chat.id, msg.message_id) save_message(msg.chat.id, msg.message_id)
elif not option_ids:
elif option_ids[0] == 5:
msg = await bot.send_message( msg = await bot.send_message(
chat_id=6394047531, text=f"{username} Отменил свой голос" chat_id=STARAST, text=f"{username} не опоздает"
) )
save_message(msg.chat.id, msg.message_id) save_message(msg.chat.id, msg.message_id)
else: else:
msg = await bot.send_message( msg = await bot.send_message(
chat_id=6394047531, text=f"{username} выбрал вариант {option_ids}" chat_id=STARAST, text=f"{username} выбрал вариант {option_ids}"
) )
save_message(msg.chat.id, msg.message_id) save_message(msg.chat.id, msg.message_id)
+61 -45
View File
@@ -1,11 +1,8 @@
import requests import asyncio
from random import randint, choice from random import randint, choice
from bs4 import BeautifulSoup from playwright.async_api import async_playwright
BASE_URL = "https://rule34.xxx" BASE_URL = "https://rule34.xxx"
HEADERS = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
}
URL = f"{BASE_URL}/index.php?page=post&s=list" URL = f"{BASE_URL}/index.php?page=post&s=list"
MAXIMUM = 999 MAXIMUM = 999
@@ -25,49 +22,68 @@ def get_tags_str() -> str:
def get_tags() -> str: def get_tags() -> str:
return "+".join(TAGS) if TAGS else "" return "+".join(TAGS) if TAGS else ""
def get_url():
while True:
try:
tags = get_tags()
pid = randint(1, MAXIMUM)
# Формируем корректный URL с query‑параметрами async def get_url():
if tags: async with async_playwright() as p:
url_page = f"{URL}&tags={tags}&pid={pid}" browser = await p.firefox.launch(headless=True)
else: page = await browser.new_page(user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64)")
url_page = f"{URL}&pid={pid}"
r = requests.get(url_page, headers=HEADERS, timeout=5) while True:
soup = BeautifulSoup(r.text, 'lxml') try:
block = soup.find(class_="image-list") tags = get_tags()
if not block: pid = randint(1, MAXIMUM)
continue
block = block.find_all("span") # Формируем корректный URL
if not block: if tags:
url_page = f"{URL}&tags={tags}&pid={pid}"
else:
url_page = f"{URL}&pid={pid}"
await page.goto(url_page, timeout=5000)
# Ищем блок с картинками
block = await page.query_selector(".image-list")
if not block:
continue
spans = await block.query_selector_all("span")
if not spans:
continue
link_el = await choice(spans).query_selector("a")
if not link_el:
continue
href = await link_el.get_attribute("href")
if not href:
continue
await page.goto(f"{BASE_URL}{href}", timeout=30000)
flexi = await page.query_selector(".flexi")
if not flexi:
continue
img_el = await flexi.query_selector("img")
if not img_el:
continue
url = await img_el.get_attribute("src")
if not url:
continue
await browser.close()
return url
except Exception as e:
print(f"[get_url ERROR] {e}")
continue continue
link = choice(block).find("a")
if not link:
continue
r2 = requests.get(f"{BASE_URL}{link.get('href')}", headers=HEADERS, timeout=10) # Пример использования
soup_two = BeautifulSoup(r2.text, 'lxml') async def main():
result = await get_url()
flexi = soup_two.find(class_="flexi") print("Result URL:", result)
if not flexi:
continue
img = flexi.find("img")
if not img:
continue
url = img.get("src")
if not url:
continue
return url
except Exception as e:
print(f"[get_url ERROR] {e}")
continue
if __name__ == "__main__":
asyncio.run(main())
+2 -2
View File
@@ -26,7 +26,7 @@ def register_handlers(dp: Dispatcher, state, bot: Bot):
@dp.message(Command("rule34")) @dp.message(Command("rule34"))
async def rule34(message: Message): async def rule34(message: Message):
msg = await message.answer_photo( msg = await message.answer_photo(
photo=get_url(), photo= await get_url(),
caption="Вот фото 📷", caption="Вот фото 📷",
reply_markup=get_keyboard() reply_markup=get_keyboard()
) )
@@ -39,7 +39,7 @@ def register_handlers(dp: Dispatcher, state, bot: Bot):
for attempt in range(3): # максимум 3 попытки for attempt in range(3): # максимум 3 попытки
try: try:
media = InputMediaPhoto( media = InputMediaPhoto(
media=get_url(), media=await get_url(),
caption=f"Новое фото 🌄 (попытка {attempt + 1})" caption=f"Новое фото 🌄 (попытка {attempt + 1})"
) )
await callback.message.edit_media( await callback.message.edit_media(
+1
View File
@@ -8,6 +8,7 @@ from aiogram.types import Message
from models.state import BotState from models.state import BotState
from aiogram.filters import Command from aiogram.filters import Command
from logging import getLogger from logging import getLogger
import aiohttp
logger = getLogger(__name__) logger = getLogger(__name__)
+1 -1
View File
@@ -28,7 +28,7 @@ class TelegramBot:
self.addons.load("poll") self.addons.load("poll")
self.addons.load("hello") self.addons.load("hello")
# self.addons.load("draw") # self.addons.load("draw")
# self.addons.load("gpt") self.addons.load("gpt")
# self.addons.load("rule34") # self.addons.load("rule34")
# self.addons.load("todo") # self.addons.load("todo")
self.addons.load("miniapps") self.addons.load("miniapps")
+2 -2
View File
@@ -22,7 +22,7 @@ class Config:
# Admins (user_id: уровень) # Admins (user_id: уровень)
ADMINS: Dict[int, int] = {850906163: 0, 6394047531: 4, 1345058877: 3} ADMINS: Dict[int, int] = {850906163: 0, 6394047531: 4, 1345058877: 3}
Names: Dict[int, str] = {850906163: "Ляпич", 6394047531: "Прокопович"} Names: Dict[int, str] = {850906163: "Ляпич", 6394047531: "Прокопович", 1345058877: "Сом"}
# Chats # Chats
CHAT_IDS = [-1003038389942] CHAT_IDS = [-1003038389942]
@@ -32,7 +32,7 @@ class Config:
} }
# Settings # Settings
ANTISPAM_DELAY = 600 ANTISPAM_DELAY = 20
WATCHER_BASE_DELAY = 600 WATCHER_BASE_DELAY = 600
# Пути # Пути
+1 -1
View File
@@ -41,7 +41,7 @@ def register_handlers(dp: Dispatcher, state: BotState):
@dp.message(Command("prasp")) @dp.message(Command("prasp"))
@saving @saving
async def send_schedule(message: types.Message): async def send_pschedule(message: types.Message):
"""Отправка расписания""" """Отправка расписания"""
if is_chat_spam(message.chat.id, state): if is_chat_spam(message.chat.id, state):
await message.answer("НЕ СПАМЬТЕ!!!") await message.answer("НЕ СПАМЬТЕ!!!")
+2 -2
View File
@@ -92,8 +92,8 @@ class ScheduleService:
return result, url, day, month return result, url, day, month
@staticmethod
def exact_group_regex(self, group: str) -> re.Pattern: def exact_group_regex(group: str) -> re.Pattern:
# ищем как отдельный токен: граница слева/справа или начало/конец # ищем как отдельный токен: граница слева/справа или начало/конец
pattern = rf"(^|{BOUNDARY}){re.escape(group)}({BOUNDARY}|$)" pattern = rf"(^|{BOUNDARY}){re.escape(group)}({BOUNDARY}|$)"
return re.compile(pattern) return re.compile(pattern)
+4 -5
View File
@@ -157,16 +157,15 @@ def analyze_bot_logs(log_file_path="bot.log"):
return stats return stats
def calculate_duration_hours(start_str, end_str): def calculate_duration_hours(start_str: str, end_str: str) -> float:
"""Вычисляет продолжительность в часах""" """Вычисляет продолжительность в часах"""
fmt = "%Y-%m-%d %H:%M:%S"
try: try:
fmt = "%Y-%m-%d %H:%M:%S"
start = datetime.strptime(start_str, fmt) start = datetime.strptime(start_str, fmt)
end = datetime.strptime(end_str, fmt) end = datetime.strptime(end_str, fmt)
return round((end - start).total_seconds() / 3600, 2) return round((end - start).total_seconds() / 3600, 2)
except: except (ValueError, TypeError):
return 0 return 0.0
def calculate_success_rate(stats): def calculate_success_rate(stats):
"""Рассчитывает процент успешных операций""" """Рассчитывает процент успешных операций"""