diff --git a/code/bot.py b/code/bot.py
new file mode 100644
index 0000000..74ee4b2
--- /dev/null
+++ b/code/bot.py
@@ -0,0 +1,18 @@
+import asyncio, logging, warnings
+
+from init import *
+from handlers import router
+
+
+async def main() -> None:
+ dp.include_router(router)
+ await bot.delete_webhook(drop_pending_updates=True)
+ await dp.start_polling(bot, allowed_updates=dp.resolve_used_update_types(), skipUpdates=True)
+
+
+if __name__ == "__main__":
+ logging.basicConfig(level=logging.INFO)
+ # warnings.filterwarnings("ignore")
+
+ try: asyncio.run(main())
+ except KeyboardInterrupt: pass
diff --git a/code/config.py b/code/config.py
new file mode 100644
index 0000000..31d1e5a
--- /dev/null
+++ b/code/config.py
@@ -0,0 +1,4 @@
+botToken = "XXXXXXXXXXXXXXXXXXXXXXXX" # @circlechek_bot
+
+WARN = ("Предупреждение! Кружочек может быть с некорректными метаданными, в этом случае программа выдаст ошибку "
+ "либо произведёт видео с браком! Обязательно перепроверяйте получившиеся видео!\n\n")
diff --git a/code/handlers.py b/code/handlers.py
new file mode 100644
index 0000000..9108e25
--- /dev/null
+++ b/code/handlers.py
@@ -0,0 +1,122 @@
+from aiogram import types, F, Router
+from aiogram.types import Message, CallbackQuery, ContentType, InlineKeyboardButton, InlineKeyboardMarkup, FSInputFile
+from aiogram.filters import Command
+
+import shutil
+
+from scripts import *
+from config import WARN
+
+router = Router()
+
+
+# СТАРТОВАЯ КОМАНДА
+@router.message(Command("start", "help"))
+async def helps(msg: Message) -> None:
+ buttons = [[InlineKeyboardButton(text="ФУНКЦИИ", callback_data="fun"),
+ InlineKeyboardButton(text="АВТОР", callback_data="auth")]]
+ keyboard = InlineKeyboardMarkup(inline_keyboard=buttons, row_width=2)
+
+ await msg.answer(text="Кружочичек — бот для обработки видео и кружочков в Телеграме. Для начала работы "
+ "вам достаточно скинуть квадратное видео не дольше минуты в чат, чтобы получить кружок. "
+ "Или скинуть кружок, выбрать формат обработки углов и получить готовый видеоролик! "
+ "НО у Телеграмма бывают кружочки с некорректными метаданными, из-за чего его "
+ "обработка становится невозможной, или в итоге видео будет с браком, поэтому "
+ "обязательно проверяйте полученный результат!", reply_markup=keyboard)
+
+
+@router.callback_query(F.data == "auth")
+async def author(call: CallbackQuery) -> None:
+ await call.message.answer('| АВТОР |\n\n>> Этот телеграм бот, крайне прост и примитивен. В его '
+ 'распоряжении есть всего лишь две функции, а именно: превращение квадратных '
+ 'видеороликов в кружочки и скачивание кружочков с последующей обработкой краёв в '
+ 'двух предложенных вариантах.'
+
+ '\n\nЯ же пишу подобные небольшие проекты, о которых вы можете узнать '
+ 'больше на моём GitHub.')
+
+
+@router.callback_query(F.data == "fun")
+async def function(call: CallbackQuery) -> None:
+ await call.message.answer('| ФУНКЦИИ |\n\n1. Обработка кружочка с градиентным или размытым фоном на '
+ 'выбор по бокам\n2. Получение из квадратного видео длиною не больше минуты кружочек')
+
+
+# ОБРАБОТЧИК ВИДЕО
+@router.message(F.content_type == ContentType.VIDEO)
+async def video_to_circle(msg: Message) -> None:
+ video = "../data/circles/" + str(msg.chat.id) + ".mp4"
+
+ await msg.reply("Началась обработка видео! Оно должно быть квадратным и не дольше одной минуты, в ином "
+ "случае бот в ответ вернёт вам изначальное видео, а не кружочек!")
+ await msg.bot.download(file=msg.video.file_id, destination=video)
+ await msg.answer_video_note(video_note=FSInputFile(video))
+ os.remove(video)
+
+
+# ОБРАБОТЧИК КРУЖОЧКОВ
+@router.message(F.content_type == ContentType.VIDEO_NOTE)
+async def video_note(msg: Message) -> None:
+ buttons = [[InlineKeyboardButton(text="Градиент", callback_data="grad"),
+ InlineKeyboardButton(text="Блюр", callback_data="blur")]]
+ keyboard = types.InlineKeyboardMarkup(inline_keyboard=buttons, row_width=2)
+
+ msg_answer = await msg.reply("Кружочек загружается...")
+ await msg.bot.download(file=msg.video_note.file_id, destination="../data/video_notes/" + str(msg.chat.id) + ".mp4")
+ await msg_answer.edit_text(text=WARN + "Какой тип фона в углах вы выберите?", reply_markup=keyboard)
+
+
+@router.callback_query(lambda call: call.data == "grad" or call.data == "blur")
+async def work_part(call: CallbackQuery) -> None:
+ msg = await call.message.edit_text(WARN + "Начало обработки!")
+
+ video_name = str(msg.chat.id)
+ video_file = video_name + ".mp4"
+
+ path = f"../data/videos/{video_name}"
+ os.mkdir(path)
+
+ path_video = path + "/" + video_file
+ os.replace("../data/video_notes/" + video_file, path_video)
+
+ path_frames = path + f"/frames"
+ os.mkdir(path_frames)
+
+ path_background = path + f"/background"
+ os.mkdir(path_background)
+
+ msg = await msg.edit_text(WARN + "Этап: 1 - Обработка видео.")
+ video = Movie(path_video, video_name, path)
+ procces = video.split_into_frames()
+
+ if not procces:
+ await msg.edit_text("Возникла ошибка! Кружочек невозможно обработать!")
+ shutil.rmtree(path)
+ return
+
+ msg = await msg.edit_text(WARN + "Этап: 2 - Обработка кадров.")
+ frames = list(sorted(os.listdir(path_frames)))
+
+ for frame in frames:
+ img = Frame(path_frames + "/" + frame, path_background + "/" + f'{frame[:-5]}-g.jpeg')
+ width, height = img.size()
+
+ if call.data == "blur":
+ img.blur(width, height)
+ else:
+ r, g, b = img.medium_color(); nearly = 10
+ img.gradient(width, height, (r - nearly, g - nearly, b - nearly),
+ (r + nearly, g + nearly, b + nearly), (True, False, False))
+
+ img.unity_image()
+
+ msg = await msg.edit_text(WARN + "Этап: 3 - Объединение кадров.")
+ video.unity_into_video(frames)
+
+ msg_final = await msg.edit_text(WARN + "Готово! Видео отправляется...")
+
+ await msg.answer_video(video=FSInputFile(path + "/acs-" + video_file), caption=WARN,
+ reply_to_message_id=call.message.reply_to_message.message_id)
+ await msg_final.delete()
+
+ shutil.rmtree(path)
diff --git a/code/init.py b/code/init.py
new file mode 100644
index 0000000..5154444
--- /dev/null
+++ b/code/init.py
@@ -0,0 +1,32 @@
+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 config import botToken
+
+bot = Bot(token=botToken, default=DefaultBotProperties(parse_mode=ParseMode.HTML))
+dp = Dispatcher(storage=MemoryStorage())
+
+
+import logging, functools, sys
+
+# logging.basicConfig(level=logging.INFO, filename='../data/info.log',filemode="w", format="%(asctime)s %(levelname)s %(message)s")
+
+def bug_report(func):
+ @functools.wraps(func)
+
+ def wrapper(*args, **kwargs):
+
+ try:
+ result = func(*args, **kwargs)
+ logging.info(f"Successful result")
+ return result
+ except Exception as err:
+ logging.error("Ошибка", exc_info=True)
+ """with open('../data/log.txt', "a") as f:
+ f.write(repr(e))"""
+ sys.exit()
+
+ return wrapper
+
diff --git a/code/scripts.py b/code/scripts.py
index 0b51146..f1a87f4 100644
--- a/code/scripts.py
+++ b/code/scripts.py
@@ -1,7 +1,9 @@
from PIL import Image, ImageDraw, ImageFilter
-from moviepy.editor import *
+from moviepy import *
import numpy, os
+from init import bug_report
+
class Movie:
def __init__(self, video_file, video_name, path):
@@ -13,7 +15,7 @@ class Movie:
def split_into_frames(self):
video_clip = VideoFileClip(self.video_file)
- video_clip.audio.write_audiofile(self.path + f"/{self.video_name}-audio.mp3", verbose=False, logger=None)
+ video_clip.audio.write_audiofile(self.path + f"/{self.video_name}-audio.mp3", logger=None)
self.path_frames = self.path + "/frames"
step = 1 / 30.0 if video_clip.fps > 60.0 else 1 / video_clip.fps
@@ -32,6 +34,7 @@ class Movie:
video_clip.close()
return True
+ @bug_report
def unity_into_video(self, frames):
video_clip = VideoFileClip(self.video_file)
fps = 30.0 if video_clip.fps > 60.0 else video_clip.fps
@@ -39,14 +42,14 @@ class Movie:
os.remove(self.video_file)
clip = ImageSequenceClip(list(map(lambda x: self.path_frames + "/" + x, frames)), fps=fps)
- clip.write_videofile(self.video_file, verbose=False, logger=None)
+ clip.write_videofile(self.video_file, logger=None)
clip.close()
video_clip = VideoFileClip(self.video_file)
audio_clip = AudioFileClip(self.path + f"/{self.video_name}-audio.mp3")
- video_clip_with_audio = video_clip.set_audio(audio_clip)
- video_clip_with_audio.write_videofile(self.path + "/acs-" + self.video_name + ".mp4", verbose=False, logger=None)
+ video_clip_with_audio = video_clip.with_audio(audio_clip)
+ video_clip_with_audio.write_videofile(self.path + "/acs-" + self.video_name + ".mp4", logger=None)
video_clip.close()
audio_clip.close()
diff --git a/data/circles/.gitkeep b/data/circles/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/data/video_notes/.gitkeep b/data/video_notes/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/data/videos/.gitkeep b/data/videos/.gitkeep
new file mode 100644
index 0000000..e69de29