This commit is contained in:
IGlek 2025-05-19 21:54:47 +03:00
parent c651369b17
commit a678f005bd
11 changed files with 230 additions and 22 deletions

View file

@ -7,6 +7,8 @@ from handlers import router
async def main() -> None: async def main() -> None:
dp.include_router(router) dp.include_router(router)
await bot.delete_webhook(drop_pending_updates=True) await bot.delete_webhook(drop_pending_updates=True)
await setup_bot_commands()
await dp.start_polling(bot, allowed_updates=dp.resolve_used_update_types()) await dp.start_polling(bot, allowed_updates=dp.resolve_used_update_types())

17
src/code/database.py Normal file
View file

@ -0,0 +1,17 @@
import json
class JsonTools:
def __init__(self, user_id):
self.f_name = f"../data/users/{user_id}.json"
def save_json(self, data):
with open(self.f_name, "w", encoding="utf8") as f:
return json.dump(data, f)
def read_json(self):
with open(self.f_name, "r", encoding="utf8") as f:
return json.load(f)
def get_buildings(self):
return self.read_json().keys()

View file

@ -1,27 +1,115 @@
from aiogram import types, F, Router from aiogram import F, Router
from aiogram.types import (Message, InlineQuery, InlineQueryResultArticle, InputTextMessageContent, ChosenInlineResult, from aiogram.types import (Message, ContentType, InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery, FSInputFile)
ContentType, InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery, FSInputFile,
InputMediaPhoto, InlineQueryResultPhoto)
from aiogram.filters import Command, CommandStart from aiogram.filters import Command, CommandStart
from aiogram.utils.keyboard import InlineKeyboardBuilder
from init import *
from scripts import * from scripts import *
from database import *
router = Router() router = Router()
@router.message(CommandStart()) @router.message(CommandStart())
async def start_handler(msg: Message) -> None: async def start_handler(msg: Message) -> None:
await msg.answer("Привет мир!") await msg.answer("Здравствуйте! Этот бот поможет вам добраться до кабинета в структуре корпусов Московского "
"Политехнического Университета. Для начала работы просто пропишите команду <b>/route</b>")
@router.message(Command("help")) @router.message(Command("help"))
async def help_handler(msg: Message) -> None: async def help_handler(msg: Message) -> None:
text = "<b>Текст</b>\n\n" text = "<b>Напомню, что за команды у нас тут есть)</b>\n\n"
text += "<b>/dates</b> - Текст\n\n" text += "<b>/help</b> - Команда помощи, выведет все доступные команды\n\n"
text += "<b>/picture</b> - Текст\n\n" text += "<b>/route</b> - Команда выводит маршрут до введённого кабинета"
text += "<b>/gallery</b> - Текст"
await msg.answer(text) await msg.answer(text)
@router.message(Command("route"))
async def route_handler(msg: Message) -> None:
buttons = [[InlineKeyboardButton(text=f"На Большой Семёновской", callback_data="edu:bs")],
[InlineKeyboardButton(text=f"На Павла Корчагина", callback_data="edu:pk")],
[InlineKeyboardButton(text=f"На Прянишкова", callback_data="edu:pr"),
InlineKeyboardButton(text=f"На Михалковской", callback_data="edu:mi")],
[InlineKeyboardButton(text=f"На Автозаводской", callback_data="edu:av")]]
keyboard = InlineKeyboardMarkup(inline_keyboard=buttons)
await msg.answer(text="Выберите корпус на котором вы хотите проложить маршрут:", reply_markup=keyboard)
@router.callback_query(F.data.startswith("edu:"))
async def route_button(call: CallbackQuery) -> None:
action = call.data.split(":")[1]
user_dict = dict()
user_dict[action] = []
JsonTools(call.from_user.id).save_json(user_dict)
await call.message.edit_text("Укажите до какого кабинет вам необходимо добраться "
"(обязательно напишите кабинет в точности как указано в личном кабинет):")
@router.message(F.content_type == ContentType.TEXT)
async def add_cabinet(msg: Message) -> None:
cab = msg.text.lower()
jsn = JsonTools(msg.from_user.id)
user_dict = jsn.read_json()
edu_keys = list(user_dict.keys())
if ((cab[0] == "м" and len(cab) == 5 and "mi" == edu_keys[0]) or
(cab[:2] == "ав" and len(cab) == 6 and "av" == edu_keys[0]) or
(cab[:2] == "пк" and len(cab) == 6 and "pk" == edu_keys[0]) or
(cab[:2] == "пр" and len(cab) == 6 and "pr" == edu_keys[0]) or
(cab[0] in ["а", "б", "в", "н", "нд"] and "bs" == edu_keys[0])):
lst_routes = get_routes(edu_keys[0], cab)
if lst_routes:
user_dict[edu_keys[0]] = lst_routes
jsn.save_json(user_dict)
buttons = [[InlineKeyboardButton(text=f"От входа на территорию", callback_data="route:build")],
[InlineKeyboardButton(text=f"От входа в корпус", callback_data="route:floor")]]
keyboard = InlineKeyboardMarkup(inline_keyboard=buttons)
await msg.answer("Кабинет успешно получен, обрабатываем путь! Откуда вам проложить маршрут:", reply_markup=keyboard)
else:
await msg.answer("Обрыв программы по неизвестной причине!")
else:
await msg.answer("Вы скинули не кабинет! Я же вижу)")
@router.callback_query(F.data.startswith("route:"))
async def var_button(call: CallbackQuery) -> None:
action = call.data.split(":")[1]
jsn = JsonTools(call.from_user.id)
user_dict = jsn.read_json()
edu_keys = list(user_dict.keys())
lst_routes = user_dict[edu_keys[0]]
msg = await call.message.answer("1. Получение видео...")
path = ""
if action == "build":
if os.path.exists(f"../data/cache/{lst_routes[-1][21:].replace('.mp4', '-all.mp4')}"):
path = f"../data/cache/{lst_routes[-1][21:].replace('.mp4', '-all.mp4')}"
else:
path = make_full_clip(lst_routes)
if not path:
await msg.edit_text("Данного маршрута в нашей базе пока нет, извините за неудобство, можете написать "
"желаемые маршруты на почту <a href='mailto:support@new-devs.ru' >support@new-devs.ru</a>")
return 0
elif action == "floor":
if os.path.exists(f"../data/cache/{lst_routes[-1][21:].replace('.mp4', '-small.mp4')}"):
path = f"../data/cache/{lst_routes[-1][21:].replace('.mp4', '-small.mp4')}"
else:
path = make_full_clip(lst_routes[1:])
if not path:
await msg.edit_text("Данного маршрута в нашей базе пока нет, извините за неудобство, можете написать "
"желаемые маршруты на почту <a href='mailto:support@new-devs.ru' >support@new-devs.ru</a>")
return 0
msg_finally = await msg.edit_text("2. Видео готово!")
await msg.answer_video_note(video_note=FSInputFile(path))
await msg_finally.delete()

View file

@ -2,9 +2,22 @@ from aiogram import Bot, Dispatcher
from aiogram.enums.parse_mode import ParseMode from aiogram.enums.parse_mode import ParseMode
from aiogram.fsm.storage.memory import MemoryStorage from aiogram.fsm.storage.memory import MemoryStorage
from aiogram.client.bot import DefaultBotProperties from aiogram.client.bot import DefaultBotProperties
from aiogram.types import BotCommand, BotCommandScopeDefault
from aiogram.methods import SetMyCommands
import config import config
# Структурированное определение команд для меню
async def setup_bot_commands():
commands = [
BotCommand(command="help", description="Получить помощь"),
BotCommand(command="route", description="Построить маршрут")
]
await bot(SetMyCommands(
commands=commands,
scope=BotCommandScopeDefault()
))
bot = Bot(token=config.BOT_TOKEN, default=DefaultBotProperties(parse_mode=ParseMode.HTML)) bot = Bot(token=config.BOT_TOKEN, default=DefaultBotProperties(parse_mode=ParseMode.HTML))
dp = Dispatcher(storage=MemoryStorage()) dp = Dispatcher(storage=MemoryStorage())

View file

@ -1,15 +1,101 @@
from csv import reader, writer from moviepy import VideoFileClip, concatenate_videoclips
import os
def write_log(text): def get_routes(id_building: str, id_cab: str, other=False):
with open("../data/database/log.txt", "a") as f:
f.writelines(text) if other:
id_cab = id_cab.replace('-', "")
building=id_cab[0]
cab_num=id_cab[1:]
corp_route=f"../videos/{id_building}/{id_building}-{building}b.mp4"
cab_route=f"../videos/{id_building}/{id_building}-{building}b-{cab_num}.mp4"
return [corp_route,cab_route]
def view_csv(filename): match id_building:
data = [] #авbfnn
with open(f'../data/database/{filename}', 'r', encoding='utf-8') as csvfile: case "av":
csvreader = reader(csvfile) building = id_cab[2]
for row in csvreader: floor = id_cab[3]
data.append(row) cab_num = id_cab[4:]
corp_route = f"../videos/{id_building}/buildings/{id_building}-{building}b.mp4"
floor_route = f"../videos/{id_building}/floors/{id_building}-{building}b-0{floor}f.mp4"
cab_route = f"../videos/{id_building}/offices/{id_building}-{building}b-0{floor}f-0{building}{floor}{cab_num}c.mp4"
return [corp_route, floor_route, cab_route]
case "mi":
building = id_cab[1]
floor = id_cab[2]
cab_num = id_cab[3:]
corp_route = f"../videos/{id_building}/buildings/{id_building}-{building}b.mp4"
floor_route = f"../videos/{id_building}/floors/{id_building}-{building}b-0{floor}f.mp4"
cab_route = f"../videos/{id_building}/offices/{id_building}-{building}b-0{floor}f-0{building}{floor}{cab_num}c.mp4"
return [corp_route, floor_route, cab_route]
case "pk":
building = id_cab[2]
floor = id_cab[3]
cab_num = id_cab[4:]
corp_route = f"../videos/{id_building}/buildings/{id_building}-{building}b.mp4"
floor_route = f"../videos/{id_building}/floors/{id_building}-{building}b-0{floor}f.mp4"
cab_route = f"../videos/{id_building}/offices/{id_building}-{building}b-0{floor}f-0{building}{floor}{cab_num}c.mp4"
return [corp_route, floor_route, cab_route]
case "pr":
building = id_cab[2]
floor = id_cab[3]
cab_num = id_cab[4:]
corp_route = f"../videos/{id_building}/buildings/{id_building}-{building}b.mp4"
floor_route = f"../videos/{id_building}/floors/{id_building}-{building}b-0{floor}f.mp4"
cab_route = f"../videos/{id_building}/offices/{id_building}-{building}b-0{floor}f-0{building}{floor}{cab_num}c.mp4"
return [corp_route, floor_route, cab_route]
#id_building: bs
#id_cab: bfnn
case "bs":
id_cab= id_cab.replace('-',"")
building = id_cab[0]
floor = id_cab[1]
cab_num = id_cab[3:]
corp_route = f"../videos/{id_building}/buildings/{id_building}-{building}b.mp4"
floor_route = f"../videos/{id_building}/floors/{id_building}-{building}b-0{floor}f.mp4"
cab_route = f"../videos/{id_building}/offices/{id_building}-{building}b-0{floor}f-0{building}{floor}{cab_num}c.mp4"
return [corp_route, floor_route, cab_route]
return None
def make_full_clip(paths):
if not all(os.path.exists(path) for path in paths):
print("Некоторые файлы не найдены")
return None
clips = [VideoFileClip(path) for path in paths] # cоздаем список клипов
full_clip = concatenate_videoclips(clips) # cклеиваем все клипы
full_clip = full_clip.without_audio() # удаляем звук
full_clip = full_clip.time_transform(lambda t: t * 1.5).with_duration(full_clip.duration / 1.5) # ускоряем в 1.5 раз
full_clip = full_clip.resized(height=512)
full_clip_name = f"{paths[-1][21:].replace('.mp4', '')}-{'all' if len(paths) == 3 else 'small'}.mp4" # генерируем рандомный 5-ти значный ключ
# рендерим видео с параметрами
full_clip.write_videofile(f"../data/cache/{full_clip_name}",
fps=30,
codec="libx264",
bitrate="1500k",
preset="fast",
ffmpeg_params=["-crf", "23"])
return f"../data/cache/{full_clip_name}"
return data

BIN
src/data/cache/av-4b-04f-04401c-all.mp4 vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
src/data/cache/av-4b-04f-04412c-all.mp4 vendored Normal file

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1 @@
{"av": ["../videos/av/buildings/av-4b.mp4", "../videos/av/floors/av-4b-04f.mp4", "../videos/av/offices/av-4b-04f-04412c.mp4"]}

View file

@ -0,0 +1 @@
{"bs": ["../videos/bs/buildings/bs-\u0430b.mp4", "../videos/bs/floors/bs-\u0430b-02f.mp4", "../videos/bs/offices/bs-\u0430b-02f-0\u043021\u0430c.mp4"]}