It's version 0.5

This commit is contained in:
Niken
2025-10-29 21:46:06 +03:00
parent a71a7fbd0c
commit e56401bf1d
19 changed files with 582 additions and 7 deletions
@@ -21,7 +21,7 @@ async def get_video_info(url: str) -> dict:
"--dump-json",
"--no-playlist",
"--cookies",
"~/myfirstprogramm/addons/example_addon/cookies.txt",
"/addons/download_mp3_to_youtube/cookies.txt",
url,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
@@ -116,7 +116,7 @@ async def download_mp3_isolated(url: str) -> tuple[str, dict]:
"--audio-format",
"mp3",
"--cookies",
"~/myfirstprogramm/addons/example_addon/cookies.txt",
"/addons/download_mp3_to_youtube/cookies.txt",
"--audio-quality",
"320K",
"--no-playlist",
+9
View File
@@ -0,0 +1,9 @@
def register(dp, state, bot):
from . import handlers
handlers.register_handlers(dp, state, bot)
def unregister(dp):
# Здесь можно удалить хендлеры, если нужно
dp.message_handlers.handlers.clear()
+29
View File
@@ -0,0 +1,29 @@
from aiogram import Dispatcher, Bot
from aiogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton, WebAppInfo
from models.state import BotState
from aiogram.filters import Command
from logging import getLogger
from datetime import datetime
logger = getLogger(__name__)
def get_day() -> int:
day = datetime.now().day
if day == 6:
return day + 1
return day
def register_handlers(dp: Dispatcher, state: BotState, bot: Bot):
@dp.message(Command("app"))
async def send_welcome(message: Message):
# Создаём инлайн-кнопку для открытия Web App
keyboard = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="Открыть мини-приложение", web_app=WebAppInfo(url=f"https://college.by/accounts/raspis/{datetime.now().month}/{get_day()}-PODNAM.htm"))]
])
await message.answer(
f"Расписание на {get_day()} число месяца:",
reply_markup=keyboard
)
+6 -1
View File
@@ -20,7 +20,7 @@ def register_handlers(dp: Dispatcher, state: BotState, bot: Bot):
poll_msg = await bot.send_poll(
chat_id=chat_id,
question="Кто опоздает?",
options=["Я", "Я очень сильно опоздаю", "Наверное"],
options=["Я", "Я очень сильно опоздаю", "Я пиздец как опоздаю", "Наверное"],
is_anonymous=False,
allows_multiple_answers=False,
)
@@ -56,6 +56,11 @@ def register_handlers(dp: Dispatcher, state: BotState, bot: Bot):
)
save_message(msg.chat.id, msg.message_id)
elif option_ids and option_ids[0] == 2:
msg = await bot.send_message(
chat_id=6394047531, text=f"{username} Пиздец опоздаеты"
)
save_message(msg.chat.id, msg.message_id)
elif option_ids[0] == 3:
msg = await bot.send_message(
chat_id=6394047531, text=f"{username} возможно опоздает"
)
+9
View File
@@ -0,0 +1,9 @@
def register(dp, state, bot):
from . import handlers
handlers.register_handlers(dp, state, bot)
def unregister(dp):
# Здесь можно удалить хендлеры, если нужно
dp.message_handlers.handlers.clear()
+73
View File
@@ -0,0 +1,73 @@
import requests
from random import randint, choice
from bs4 import BeautifulSoup
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"
MAXIMUM = 999
# Хранилище тегов в памяти
TAGS = set()
def add_tags(tags: list[str]):
TAGS.update(tags)
def del_tags(tags: list[str]):
for t in tags:
TAGS.discard(t)
def get_tags_str() -> str:
return "+".join(TAGS) if TAGS else "(нет тегов)"
def get_tags() -> str:
return "+".join(TAGS) if TAGS else ""
def get_url():
while True:
try:
tags = get_tags()
pid = randint(1, MAXIMUM)
# Формируем корректный URL с query‑параметрами
if tags:
url_page = f"{URL}&tags={tags}&pid={pid}"
else:
url_page = f"{URL}&pid={pid}"
r = requests.get(url_page, headers=HEADERS, timeout=5)
soup = BeautifulSoup(r.text, 'lxml')
block = soup.find(class_="image-list")
if not block:
continue
block = block.find_all("span")
if not block:
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')
flexi = soup_two.find(class_="flexi")
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
+85
View File
@@ -0,0 +1,85 @@
from aiogram import Dispatcher, Bot
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton, InputMediaPhoto, Message, CallbackQuery
from aiogram.filters import Command
from aiogram.exceptions import TelegramBadRequest, TelegramRetryAfter
from aiogram import F
from logging import getLogger
from storage.message_storage import save_message
from .get_post import get_url, add_tags, del_tags, get_tags_str
import asyncio
logger = getLogger(__name__)
def get_keyboard():
keyboard = InlineKeyboardMarkup(
inline_keyboard=[
[InlineKeyboardButton(text="Следующее фото", callback_data="next")]
]
)
return keyboard
def register_handlers(dp: Dispatcher, state, bot: Bot):
@dp.message(Command("rule34"))
async def rule34(message: Message):
msg = await message.answer_photo(
photo=get_url(),
caption="Вот фото 📷",
reply_markup=get_keyboard()
)
# сохраняем id сообщения, если нужно
save_message(msg.chat.id, msg.message_id)
@dp.callback_query(F.data == "next")
async def next_photo(callback: CallbackQuery):
for attempt in range(3): # максимум 3 попытки
try:
media = InputMediaPhoto(
media=get_url(),
caption=f"Новое фото 🌄 (попытка {attempt + 1})"
)
await callback.message.edit_media(
media=media,
reply_markup=get_keyboard()
)
break # успех — выходим из цикла
except TelegramRetryAfter as e:
# Telegram сказал подождать e.retry_after секунд
logger.warning(f"Flood control: ждем {e.retry_after} сек")
await asyncio.sleep(e.retry_after)
continue # пробуем снова
except TelegramBadRequest as e:
logger.warning(f"Ошибка при загрузке фото (попытка {attempt + 1}): {e}")
continue
else:
# если все попытки неудачные
logger.error("Не удалось загрузить фото после 3 попыток")
# закрываем "часики" в любом случае
await callback.answer()
@dp.message(Command("addteg"))
async def cmd_addteg(message: Message):
# Разбиваем текст после команды на теги
parts = message.text.split()[1:]
if not parts:
await message.answer("❌ Укажи теги через пробел: /addteg tag1 tag2")
return
add_tags(parts)
await message.answer(f"✅ Добавлены теги: {', '.join(parts)}\nТекущие: {get_tags_str()}")
@dp.message(Command("delteg"))
async def cmd_delteg(message: Message):
parts = message.text.split()[1:]
if not parts:
await message.answer("❌ Укажи теги для удаления: /delteg tag1 tag2")
return
del_tags(parts)
await message.answer(f"🗑 Удалены теги: {', '.join(parts)}\nТекущие: {get_tags_str()}")
+57
View File
@@ -0,0 +1,57 @@
import sqlite3
from datetime import datetime
DIR = "/Users/mac/myfirstprogramm/addons/todo/todo.db" # лучше указать полный путь
# создаём подключение
db = sqlite3.connect(DIR)
cursor = db.cursor()
# создаём таблицу, если её ещё нет
cursor.execute("""
CREATE TABLE IF NOT EXISTS tasks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
who INTEGER NOT NULL,
task TEXT NOT NULL,
due_date TEXT NOT NULL
)
""")
db.commit()
# функция для добавления задачи
def add_task(who: int, task: str, due_date: str):
cursor.execute(
"INSERT INTO tasks (who, task, due_date) VALUES (?, ?, ?)",
(who, task, due_date)
)
db.commit()
# функция для получения всех задач пользователя
def get_tasks(who: int):
cursor.execute("SELECT id, task, due_date FROM tasks WHERE who = ?", (who,))
return cursor.fetchall()
# функция для удаления всех задач пользователя
def delete_tasks_by_who(who: int):
cursor.execute("DELETE FROM tasks WHERE who = ?", (who,))
db.commit()
# пример использования
if __name__ == "__main__":
# добавляем задачи
add_task(123456789, "Сделать бота", datetime.now().strftime("%d.%m.%Y %H:%M:%S"))
add_task(123456789, "Проверить базу", datetime.now().strftime("%d.%m.%Y %H:%M:%S"))
print("Задачи до удаления:")
tasks = get_tasks(123456789)
for t in tasks:
print(t)
# удаляем все задачи пользователя
delete_tasks_by_who(123456789)
print("\nЗадачи после удаления:")
tasks = get_tasks(123456789)
for t in tasks:
print(t)
+9
View File
@@ -0,0 +1,9 @@
def register(dp, state, bot):
from . import handlers
handlers.register_handlers(dp, state, bot)
def unregister(dp):
# Здесь можно удалить хендлеры, если нужно
dp.message_handlers.handlers.clear()
+68
View File
@@ -0,0 +1,68 @@
from aiogram import Dispatcher, Bot
from aiogram.types import Message
from aiogram.filters import Command
from aiogram.fsm.state import State, StatesGroup
from aiogram.fsm.context import FSMContext
import logging
from .DB import get_tasks, add_task, delete_tasks_by_who
from storage.message_storage import save_message
from datetime import datetime
logger = logging.getLogger(__name__)
class TodoForm(StatesGroup):
waiting_for_task = State()
def register_handlers(dp: Dispatcher, state, bot: Bot):
# /todos — начать добавление задачи
@dp.message(Command("todos"))
async def cmd_todos(message: Message, state: FSMContext):
save_message(message.chat.id, message.message_id) # сохраняем сообщение
await message.answer("Введите текст задачи:")
await state.set_state(TodoForm.waiting_for_task)
# обработка текста задачи
@dp.message(TodoForm.waiting_for_task)
async def process_task(message: Message, state: FSMContext):
save_message(message.chat.id, message.message_id) # сохраняем сообщение
task_text = message.text
user_id = message.from_user.id
try:
created_at = datetime.now().strftime("%d.%m.%Y %H:%M:%S")
add_task(user_id, task_text, created_at)
reply = await message.answer(f"Задача сохранена ✅\n{task_text}")
save_message(reply.chat.id, reply.message_id) # сохраняем ответ бота
except Exception as e:
logger.error(f"Ошибка при добавлении задачи: {e}")
reply = await message.answer("Не удалось сохранить задачу ❌")
save_message(reply.chat.id, reply.message_id)
finally:
await state.clear()
# /todor — показать список задач
@dp.message(Command("todor"))
async def cmd_todor(message: Message):
save_message(message.chat.id, message.message_id) # сохраняем сообщение
user_id = message.from_user.id
try:
tasks = get_tasks(user_id)
if not tasks:
reply = await message.answer("У вас пока нет задач 📝")
save_message(reply.chat.id, reply.message_id)
return
text = "Ваши задачи:\n\n"
for tid, task, created_at in tasks:
text += f"{task} (создана {created_at})\n"
reply = await message.answer(text)
save_message(reply.chat.id, reply.message_id)
except Exception as e:
logger.error(f"Ошибка при чтении задач: {e}")
reply = await message.answer("Не удалось получить список задач ❌")
save_message(reply.chat.id, reply.message_id)
@dp.message(Command("todod"))
async def del_todo(message: Message):
delete_tasks_by_who(message.from_user.id)
+9
View File
@@ -0,0 +1,9 @@
def register(dp, state, bot):
from . import handlers
handlers.register_handlers(dp, state, bot)
def unregister(dp):
# Здесь можно удалить хендлеры, если нужно
dp.message_handlers.handlers.clear()
+99
View File
@@ -0,0 +1,99 @@
import asyncio
import aiosqlite
from datetime import datetime
from logging import getLogger
from aiogram import Dispatcher, Bot
from config import Config
from models.state import BotState
from utils.antispam import save_message
logger = getLogger(__name__)
def register_handlers(dp: Dispatcher, state: BotState, bot: Bot) -> int:
async def init_db():
async with aiosqlite.connect(Config.DAYS_TO_DB_PATH) as db:
await db.execute("""
CREATE TABLE IF NOT EXISTS days_to_new_year (
user_id INTEGER PRIMARY KEY,
days INTEGER NOT NULL,
timestamp TEXT NOT NULL
)
""")
await db.commit()
logger.info("База данных инициализирована")
async def save_days_to_db(user_id: int, days: int):
logger.debug(f"Сохраняем user_id={user_id}, days={days}")
async with aiosqlite.connect(Config.DAYS_TO_DB_PATH) as db:
await db.execute("""
INSERT OR REPLACE INTO days_to_new_year (user_id, days, timestamp)
VALUES (?, ?, ?)
""", (int(user_id), int(days), datetime.now().strftime("%Y-%m-%d %H:%M:%S")))
await db.commit()
logger.info(f"Запись сохранена: user_id={user_id}, days={days}")
async def get_last_days(user_id: int) -> int | None:
async with aiosqlite.connect(Config.DAYS_TO_DB_PATH) as db:
async with db.execute(
"SELECT days FROM days_to_new_year WHERE user_id = ?", (int(user_id),)
) as cursor:
row = await cursor.fetchone()
return row[0] if row else None
async def days_to_new_years() -> int:
now = datetime.now()
new_year = datetime(now.year + 1, 1, 1)
delta = (new_year - now).days
logger.debug(f"До Нового года осталось {delta} дней")
return delta
async def days_to_summer() -> int:
"""Считает дни до 1 июня текущего года (или следующего, если уже лето прошло)."""
now = datetime.now()
summer = datetime(now.year, 6, 1)
if now >= summer:
summer = datetime(now.year + 1, 6, 1)
delta = (summer - now).days
logger.debug(f"До лета осталось {delta} дней")
return delta
async def send_days_to_new_years(user_id: int):
days_ny = await days_to_new_years()
days_summer = await days_to_summer()
last_days = await get_last_days(user_id)
if last_days == days_ny:
logger.info(f"user_id={user_id}: запись уже есть ({days_ny} дней), пропускаем")
return
await save_days_to_db(user_id, days_ny)
message_text = (
f"🌞 До лета осталось {days_summer} дней!\n"
f"🎄 До Нового Года осталось {days_ny} дней!"
)
for chat_id in Config.CHAT_IDS:
try:
logger.info(f"Отправляем сообщение в чат {chat_id} для user_id={user_id}")
await bot.send_message(chat_id, message_text)
except Exception as e:
logger.error(f"Ошибка при отправке в чат {chat_id}: {e}")
async def periodic_task():
await init_db()
while True:
logger.info("Запуск цикла periodic_task")
for uid in Config.CHAT_IDS:
try:
msg = await send_days_to_new_years(int(uid))
if msg:
save_message(msg.chat.id, msg.message_id)
except Exception as e:
logger.exception(f"Ошибка при обработке uid={uid}: {e}")
logger.info("Завершён цикл periodic_task, спим 6 часов")
await asyncio.sleep(21600) # каждые 6 часов
asyncio.create_task(periodic_task())
return 0