diff --git a/src/code/bot.py b/src/code/bot.py index 353bd0f..f18653c 100644 --- a/src/code/bot.py +++ b/src/code/bot.py @@ -7,6 +7,8 @@ from handlers import router async def main() -> None: dp.include_router(router) await bot.delete_webhook(drop_pending_updates=True) + + await setup_bot_commands() await dp.start_polling(bot, allowed_updates=dp.resolve_used_update_types()) diff --git a/src/code/database.py b/src/code/database.py new file mode 100644 index 0000000..f110316 --- /dev/null +++ b/src/code/database.py @@ -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() \ No newline at end of file diff --git a/src/code/handlers.py b/src/code/handlers.py index 282a303..9a6a849 100644 --- a/src/code/handlers.py +++ b/src/code/handlers.py @@ -1,27 +1,115 @@ -from aiogram import types, F, Router -from aiogram.types import (Message, InlineQuery, InlineQueryResultArticle, InputTextMessageContent, ChosenInlineResult, - ContentType, InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery, FSInputFile, - InputMediaPhoto, InlineQueryResultPhoto) +from aiogram import F, Router +from aiogram.types import (Message, ContentType, InlineKeyboardButton, InlineKeyboardMarkup, CallbackQuery, FSInputFile) from aiogram.filters import Command, CommandStart -from aiogram.utils.keyboard import InlineKeyboardBuilder -from init import * from scripts import * +from database import * router = Router() @router.message(CommandStart()) async def start_handler(msg: Message) -> None: - await msg.answer("Привет мир!") + await msg.answer("Здравствуйте! Этот бот поможет вам добраться до кабинета в структуре корпусов Московского " + "Политехнического Университета. Для начала работы просто пропишите команду /route") @router.message(Command("help")) async def help_handler(msg: Message) -> None: - text = "Текст\n\n" + text = "Напомню, что за команды у нас тут есть)\n\n" - text += "/dates - Текст\n\n" - text += "/picture - Текст\n\n" - text += "/gallery - Текст" + text += "/help - Команда помощи, выведет все доступные команды\n\n" + text += "/route - Команда выводит маршрут до введённого кабинета" 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("Данного маршрута в нашей базе пока нет, извините за неудобство, можете написать " + "желаемые маршруты на почту support@new-devs.ru") + 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("Данного маршрута в нашей базе пока нет, извините за неудобство, можете написать " + "желаемые маршруты на почту support@new-devs.ru") + return 0 + + msg_finally = await msg.edit_text("2. Видео готово!") + + await msg.answer_video_note(video_note=FSInputFile(path)) + await msg_finally.delete() diff --git a/src/code/init.py b/src/code/init.py index 4004301..f3eda99 100644 --- a/src/code/init.py +++ b/src/code/init.py @@ -2,9 +2,22 @@ from aiogram import Bot, Dispatcher from aiogram.enums.parse_mode import ParseMode from aiogram.fsm.storage.memory import MemoryStorage from aiogram.client.bot import DefaultBotProperties +from aiogram.types import BotCommand, BotCommandScopeDefault +from aiogram.methods import SetMyCommands 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)) dp = Dispatcher(storage=MemoryStorage()) diff --git a/src/code/scripts.py b/src/code/scripts.py index 24ad5c6..3413dee 100644 --- a/src/code/scripts.py +++ b/src/code/scripts.py @@ -1,15 +1,101 @@ -from csv import reader, writer +from moviepy import VideoFileClip, concatenate_videoclips +import os -def write_log(text): - with open("../data/database/log.txt", "a") as f: - f.writelines(text) +def get_routes(id_building: str, id_cab: str, other=False): + + 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): - data = [] - with open(f'../data/database/{filename}', 'r', encoding='utf-8') as csvfile: - csvreader = reader(csvfile) - for row in csvreader: - data.append(row) + match id_building: + #авbfnn + case "av": + 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 "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 diff --git a/src/data/cache/av-4b-04f-04401c-all.mp4 b/src/data/cache/av-4b-04f-04401c-all.mp4 new file mode 100644 index 0000000..354b34d Binary files /dev/null and b/src/data/cache/av-4b-04f-04401c-all.mp4 differ diff --git a/src/data/cache/av-4b-04f-04401c-small.mp4 b/src/data/cache/av-4b-04f-04401c-small.mp4 new file mode 100644 index 0000000..981141a Binary files /dev/null and b/src/data/cache/av-4b-04f-04401c-small.mp4 differ diff --git a/src/data/cache/av-4b-04f-04412c-all.mp4 b/src/data/cache/av-4b-04f-04412c-all.mp4 new file mode 100644 index 0000000..4fc88e7 Binary files /dev/null and b/src/data/cache/av-4b-04f-04412c-all.mp4 differ diff --git a/src/data/cache/av-4b-04f-04412c-small.mp4 b/src/data/cache/av-4b-04f-04412c-small.mp4 new file mode 100644 index 0000000..c318756 Binary files /dev/null and b/src/data/cache/av-4b-04f-04412c-small.mp4 differ diff --git a/src/data/users/732366984.json b/src/data/users/732366984.json new file mode 100644 index 0000000..ff64eb6 --- /dev/null +++ b/src/data/users/732366984.json @@ -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"]} \ No newline at end of file diff --git a/src/data/users/934493329.json b/src/data/users/934493329.json new file mode 100644 index 0000000..69826be --- /dev/null +++ b/src/data/users/934493329.json @@ -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"]} \ No newline at end of file