I add command /admin /vadmin /iadmin /hello I create database and I improve code

It's version 0.3.0
This commit is contained in:
Niken
2025-10-11 23:02:30 +03:00
parent cce8c7dc70
commit 772d3d5b83
17 changed files with 349 additions and 18 deletions
+2
View File
@@ -13,3 +13,5 @@ utils/__pycache__/
storage/message.txt storage/message.txt
/addons/dowloadmp4_to_youtube/gettoken.py /addons/dowloadmp4_to_youtube/gettoken.py
/drevo.py /drevo.py
/addons/example_addon/cookies.txt
/storage/message.db
@@ -19,6 +19,7 @@ async def get_video_info(url: str) -> dict:
'yt-dlp', 'yt-dlp',
'--dump-json', '--dump-json',
'--no-playlist', '--no-playlist',
'--cookies', '~/myfirstprogramm/addons/example_addon/cookies.txt',
url, url,
stdout=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE stderr=asyncio.subprocess.PIPE
@@ -108,6 +109,7 @@ async def download_mp3_isolated(url: str) -> tuple[str, dict]:
process = await asyncio.create_subprocess_exec( process = await asyncio.create_subprocess_exec(
'yt-dlp', 'yt-dlp',
'-x', '--audio-format', 'mp3', '-x', '--audio-format', 'mp3',
'--cookies', '~/myfirstprogramm/addons/example_addon/cookies.txt',
'--audio-quality', '320K', '--audio-quality', '320K',
'--no-playlist', '--no-playlist',
'-o', output_template, '-o', output_template,
+7
View File
@@ -0,0 +1,7 @@
def register(dp, state, bot):
from . import handlers
handlers.register_handlers(dp, state, bot)
def unregister(dp):
# Здесь можно удалить хендлеры, если нужно
dp.message_handlers.handlers.clear()
+35
View File
@@ -0,0 +1,35 @@
from aiogram import Dispatcher, Bot
from aiogram.types import Message
from aiogram.filters import Command
from models.state import BotState
from config import Config
import logging
from utils.antispam import admin_required
from storage.message_storage import save_message # импортируем функцию
logger = logging.getLogger(__name__)
def register_handlers(dp: Dispatcher, state: BotState, bot: Bot):
@dp.message(Command("hello"))
@admin_required(1)
async def hello(message: Message):
# сохраняем саму команду пользователя
save_message(message.chat.id, message.message_id)
for admin_id in Config.ADMINS:
try:
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:
logger.error(f"Ошибка при отправке админу {admin_id}: {e}")
confirm_msg = await message.answer("✅ Всем админам отправлено приветствие.")
# сохраняем подтверждение пользователю
save_message(confirm_msg.chat.id, confirm_msg.message_id)
+5 -1
View File
@@ -3,11 +3,15 @@ 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"
logger = getLogger(__name__) 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(message: Message): async def id(message: Message):
id = message.from_user.id id = message.from_user.id
await message.reply(str(id)) msg = await message.reply(str(id))
+7
View File
@@ -0,0 +1,7 @@
def register(dp, state, bot):
from . import handlers
handlers.register_handlers(dp, state, bot)
def unregister(dp):
# Здесь можно удалить хендлеры, если нужно
dp.message_handlers.handlers.clear()
+79
View File
@@ -0,0 +1,79 @@
from config import Config
import aiohttp
from aiogram.types import BufferedInputFile
from utils.antispam import admin_required
from aiogram import Dispatcher, Bot
from aiogram.types import Message
from models.state import BotState
from aiogram.filters import Command
from logging import getLogger
from aiogram.types import PollAnswer
from storage.message_storage import save_message
logger = getLogger(__name__)
API_URL = "http://127.0.0.1:7700/speak"
from config import Config
import aiohttp
from aiogram.types import BufferedInputFile
from utils.antispam import admin_required
from aiogram import Dispatcher, Bot
from aiogram.types import Message
from models.state import BotState
from aiogram.filters import Command
from logging import getLogger
from aiogram.types import PollAnswer
from storage.message_storage import save_message
logger = getLogger(__name__)
API_URL = "http://127.0.0.1:7700/speak"
def register_handlers(dp: Dispatcher, state: BotState, bot: Bot):
@dp.message(Command("poll"))
@admin_required(5)
async def send_poll(message: Message):
for chat_id in Config.CHAT_IDS:
try:
poll_msg = await bot.send_poll(
chat_id=chat_id,
question="Кто опоздает?",
options=["Я", "Не знаю", "Наверное"],
is_anonymous=False,
allows_multiple_answers=False
)
# сохраняем сам опрос
save_message(poll_msg.chat.id, poll_msg.message_id)
logger.info(f"Опрос отправлен в чат {chat_id}")
except Exception as e:
logger.error(f"Ошибка при отправке в чат {chat_id}: {e}")
confirm_msg = await message.answer("✅ Сообщение отправлено.")
save_message(confirm_msg.chat.id, confirm_msg.message_id)
@dp.poll_answer()
async def handle_poll_answer(poll_answer: PollAnswer):
user = poll_answer.user
option_ids = poll_answer.option_ids
# username или fallback на имя
username = f"@{user.username}" if user.username else user.first_name
# всегда пишем в первый чат из Config.CHAT_IDS
if option_ids and option_ids[0] == 0:
msg = await bot.send_message(
chat_id=6394047531,
text=f"{username} опоздает"
)
save_message(msg.chat.id, msg.message_id)
else:
msg = await bot.send_message(
chat_id=6394047531,
text=f"{username} выбрал вариант {option_ids}"
)
save_message(msg.chat.id, msg.message_id)
+7
View File
@@ -0,0 +1,7 @@
def register(dp, state, bot):
from . import handlers
handlers.register_handlers(dp, state, bot)
def unregister(dp):
# Здесь можно удалить хендлеры, если нужно
dp.message_handlers.handlers.clear()
+133
View File
@@ -0,0 +1,133 @@
from config import Config
import aiohttp
from aiogram.types import BufferedInputFile
from utils.antispam import admin_required
from aiogram import Dispatcher, Bot
from aiogram.types import Message
from models.state import BotState
from aiogram.filters import Command
from logging import getLogger
logger = getLogger(__name__)
API_URL = "http://127.0.0.1:7700/speak"
def register_handlers(dp: Dispatcher, state: BotState, bot: Bot):
@dp.message(Command("vadmin"))
@admin_required(0)
async def vadmin(message: Message):
parts = message.text.split(maxsplit=1)
if len(parts) < 2:
await message.reply("❗ Укажи текст после /vadmin")
return
phrase = parts[1]
# Запрос к TTS API
async with aiohttp.ClientSession() as session:
async with session.post(API_URL, json={"text": phrase}) as resp:
if resp.status != 200:
await message.reply("Ошибка генерации аудио")
return
audio_bytes = await resp.read()
audio_file = BufferedInputFile(audio_bytes, filename="speech.wav")
# Рассылка в чаты
for chat_id in Config.CHAT_IDS:
try:
await bot.send_audio(chat_id, audio=audio_file, caption="🎙 Текст")
except Exception as e:
await message.reply(f"Не удалось отправить в {chat_id}: {e}")
await message.reply("✅ Озвучка разослана.")
@dp.message(Command("admin"))
@admin_required(0)
async def admin(message: Message):
raw_text = message.text or message.caption
if not raw_text and not (message.photo or message.document or message.audio or message.video):
await message.reply("❌ Укажи текст или прикрепи файл/медиа: /admin <сообщение>")
return
# Отрезаем саму команду (/admin)
args = raw_text.split(maxsplit=1) if raw_text else []
text_to_send = args[1] if len(args) > 1 else ""
for chat_id in Config.CHAT_IDS:
try:
if message.photo:
# Фото
photo = message.photo[-1].file_id
await bot.send_photo(chat_id, photo, caption=text_to_send)
elif message.document:
# Документ
await bot.send_document(chat_id, message.document.file_id, caption=text_to_send)
elif message.audio:
# Аудио (музыка)
await bot.send_audio(chat_id, message.audio.file_id, caption=text_to_send)
elif message.video:
# Видео
await bot.send_video(chat_id, message.video.file_id, caption=text_to_send)
else:
# Только текст
await bot.send_message(chat_id, text_to_send)
logger.info(f"Сообщение отправлено в чат {chat_id}")
except Exception as e:
logger.error(f"Ошибка при отправке в чат {chat_id}: {e}")
await message.answer("✅ Сообщение отправлено.")
@dp.message(Command("iadmin"))
@admin_required(0)
async def id_admin(message: Message):
raw_text = message.text or message.caption
if not raw_text and not (message.photo or message.document or message.audio or message.video):
await message.reply("❌ Укажи ID чата и текст или прикрепи файл/медиа: /iadmin <chat_id> <сообщение>")
return
# Отрезаем саму команду (/iadmin)
args = raw_text.split(maxsplit=2) if raw_text else []
if len(args) < 2:
await message.reply("❌ Укажи ID чата: /iadmin <chat_id> <сообщение>")
return
try:
chat_id = int(args[1]) # первый аргумент — ID чата
except ValueError:
await message.reply("❌ Неверный формат chat_id")
return
text_to_send = args[2] if len(args) > 2 else ""
try:
if message.photo:
# Фото
photo = message.photo[-1].file_id
await bot.send_photo(chat_id, photo, caption=text_to_send)
elif message.document:
# Документ
await bot.send_document(chat_id, message.document.file_id, caption=text_to_send)
elif message.audio:
# Аудио (музыка)
await bot.send_audio(chat_id, message.audio.file_id, caption=text_to_send)
elif message.video:
# Видео
await bot.send_video(chat_id, message.video.file_id, caption=text_to_send)
else:
# Только текст
await bot.send_message(chat_id, text_to_send)
logger.info(f"Сообщение отправлено в чат {chat_id}")
await message.answer("✅ Сообщение отправлено.")
except Exception as e:
logger.error(f"Ошибка при отправке в чат {chat_id}: {e}")
await message.answer(f"❌ Ошибка при отправке: {e}")
+3
View File
@@ -24,6 +24,9 @@ class TelegramBot:
#add addons #add addons
self.addons.load("example_addon") self.addons.load("example_addon")
self.addons.load("id") self.addons.load("id")
self.addons.load("send_message")
self.addons.load("poll")
self.addons.load("hello")
async def start(self): async def start(self):
"""Запуск бота""" """Запуск бота"""
+6 -1
View File
@@ -15,7 +15,12 @@ class Config:
# Admins (user_id: уровень) # Admins (user_id: уровень)
ADMINS: Dict[int, int] = { ADMINS: Dict[int, int] = {
850906163: 0, 850906163: 0,
6394047531: 5 6394047531: 4
}
Names: Dict[int, str] = {
850906163: "Ляпич",
6394047531: "Прокопович"
} }
# Chats # Chats
+5 -1
View File
@@ -3,7 +3,7 @@ from aiogram.types import Message
from aiogram.filters import Command from aiogram.filters import Command
from config import Config from config import Config
from models.state import BotState from models.state import BotState
from utils.antispam import admin_required from utils.antispam import admin_required, saving
from services.watcher_service import WatcherService from services.watcher_service import WatcherService
from storage.message_storage import load_messages, save_message, clear_messages from storage.message_storage import load_messages, save_message, clear_messages
from logging import getLogger from logging import getLogger
@@ -17,6 +17,7 @@ logger = getLogger(__name__)
def register_handlers(dp: Dispatcher, state: BotState, bot: Bot): def register_handlers(dp: Dispatcher, state: BotState, bot: Bot):
@dp.message(Command("log")) @dp.message(Command("log"))
@saving
@admin_required(3) @admin_required(3)
async def send_log(message: Message): async def send_log(message: Message):
try: try:
@@ -26,6 +27,7 @@ def register_handlers(dp: Dispatcher, state: BotState, bot: Bot):
await message.answer("Файл логов пока не создан.") await message.answer("Файл логов пока не создан.")
@dp.message(Command("status")) @dp.message(Command("status"))
@saving
@admin_required(3) @admin_required(3)
async def send_status(message: Message): async def send_status(message: Message):
from utils.analytics import analyze_bot_logs from utils.analytics import analyze_bot_logs
@@ -48,6 +50,7 @@ def register_handlers(dp: Dispatcher, state: BotState, bot: Bot):
await message.answer(f"❌ Ошибка при проверке статуса: {str(e)}") await message.answer(f"❌ Ошибка при проверке статуса: {str(e)}")
@dp.message(Command("analytics")) @dp.message(Command("analytics"))
@saving
@admin_required(1) @admin_required(1)
async def stat(message: Message): async def stat(message: Message):
from utils.analytics import analyze_bot_logs from utils.analytics import analyze_bot_logs
@@ -78,6 +81,7 @@ def register_handlers(dp: Dispatcher, state: BotState, bot: Bot):
save_message(sent.chat.id, sent.message_id) save_message(sent.chat.id, sent.message_id)
@dp.message(Command("power")) @dp.message(Command("power"))
@saving
@admin_required(2) @admin_required(2)
async def power_control(message: types.Message): async def power_control(message: types.Message):
args = message.text.split() args = message.text.split()
+2 -1
View File
@@ -2,12 +2,13 @@ from aiogram import types, Dispatcher
from aiogram.filters import Command from aiogram.filters import Command
from models.state import BotState from models.state import BotState
from services.schedule_service import ScheduleService from services.schedule_service import ScheduleService
from utils.antispam import is_chat_spam from utils.antispam import is_chat_spam, saving
from storage.message_storage import save_message from storage.message_storage import save_message
def register_handlers(dp: Dispatcher, state: BotState): def register_handlers(dp: Dispatcher, state: BotState):
@dp.message(Command("rasp")) @dp.message(Command("rasp"))
@saving
async def send_schedule(message: types.Message): async def send_schedule(message: types.Message):
"""Отправка расписания""" """Отправка расписания"""
if is_chat_spam(message.chat.id, state): if is_chat_spam(message.chat.id, state):
+1
View File
@@ -46,6 +46,7 @@ class WatcherService:
try: try:
await self._check_all_groups() await self._check_all_groups()
delay = randint(Config.WATCHER_BASE_DELAY, Config.WATCHER_BASE_DELAY + 100) delay = randint(Config.WATCHER_BASE_DELAY, Config.WATCHER_BASE_DELAY + 100)
logger.info(f"Следущая проверка через {delay}")
await asyncio.sleep(delay) await asyncio.sleep(delay)
except asyncio.CancelledError: except asyncio.CancelledError:
break break
+26
View File
@@ -0,0 +1,26 @@
import sqlite3
import os
DIR = "/Users/mac/myfirstprogramm/storage/message.db"
if __name__ == "__main__":
db = sqlite3.connect(DIR)
cursor = db.cursor()
# cursor.execute("""CREATE TABLE message (
# chat_id integer,
# message_id integer
# )""")
# db.commit()
cursor.execute("SELECT * FROM message")
print(cursor.fetchone())
db.close()
def get_db():
return sqlite3.connect(DIR)
+20 -14
View File
@@ -1,23 +1,29 @@
import os from .DB import get_db
MESSAGES_FILE = "storage/message.txt"
# --- функция для записи message_id ---
def save_message(chat_id: int, message_id: int): def save_message(chat_id: int, message_id: int):
with open(MESSAGES_FILE, "a", encoding="utf-8") as f: db = get_db()
f.write(f"{chat_id},{message_id}\n") cur = db.cursor()
cur.execute("INSERT INTO message VALUES (?, ?)", (int(chat_id), int(message_id)))
db.commit()
cur.close()
db.close()
# --- функция для загрузки всех сообщений ---
def load_messages(): def load_messages():
if not os.path.exists(MESSAGES_FILE): db = get_db()
return [] cur = db.cursor()
with open(MESSAGES_FILE, "r", encoding="utf-8") as f: cur.execute("SELECT * FROM message")
lines = f.readlines() rows = cur.fetchall()
return [tuple(map(int, line.strip().split(","))) for line in lines if line.strip()] cur.close()
db.close()
return rows
# --- функция для очистки файла ---
def clear_messages(): def clear_messages():
open(MESSAGES_FILE, "w").close() db = get_db()
cur = db.cursor()
cur.execute("DELETE FROM message")
db.commit()
cur.close()
db.close()
+9
View File
@@ -3,6 +3,7 @@ from functools import wraps
from aiogram import types from aiogram import types
from models.state import BotState from models.state import BotState
from config import Config from config import Config
from storage.message_storage import save_message
def is_chat_spam(chat_id: int, state: BotState) -> bool: def is_chat_spam(chat_id: int, state: BotState) -> bool:
@@ -41,3 +42,11 @@ def admin_required(need_level: int):
return wrapper return wrapper
return decorator return decorator
def saving(func):
"""Декоратор для сохранения входящего сообщения"""
@wraps(func)
async def wrapper(message: types.Message, *args, **kwargs):
save_message(message.chat.id, message.message_id)
return await func(message, *args, **kwargs)
return wrapper