есть скрипт, бот на Python, который конвертирует видео в кружочки, на одном пк (на котором был сделан) все работает, а на другом выдает ошибку. Что делать? Выдает такую ошибку, использовал moviepy.editor Error: 'VideoFileClip' object has no attribute 'resize' from moviepy.editor import * from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup, ReplyKeyboardMarkup from telegram.ext import ContextTypes from config import CHANNEL_ID, CHANNEL_URL from database import create_user, get_user, update_user_subscription, create_order, update_order_status, get_order import datetime from crypto import create_invoice, check_invoice async def check_user_subscription(update: Update, context: ContextTypes.DEFAULT_TYPE) -> bool: try: user = await context.bot.get_chat_member(chat_id=CHANNEL_ID, user_id=update.effective_user.id) return user.status in ['member', 'administrator', 'creator'] except: return False async def start(update: Update, context: ContextTypes.DEFAULT_TYPE): user_id = update.effective_user.id create_user(user_id) if await check_user_subscription(update, context): keyboard = ReplyKeyboardMarkup([ [' Подписка', ' Тарифы'] ], resize_keyboard=True) await update.message.reply_text( " Здравствуйте! Это бот для преобразования видео в видеокружок.\n\n" "Отправьте мне видео, и я преобразую его в видеокружок.", reply_markup=keyboard ) else: keyboard = InlineKeyboardMarkup([ [InlineKeyboardButton("Подписаться на канал", url=CHANNEL_URL)], [InlineKeyboardButton("Проверить подписку", callback_data="check_subscription")] ]) await update.message.reply_text( "Для использования бота необходимо подписаться на канал!", reply_markup=keyboard ) async def handle_text(update: Update, context: ContextTypes.DEFAULT_TYPE): text = update.message.text user_id = update.effective_user.id print(f"Получено текстовое сообщение: {text}") # Для отладки if not await check_user_subscription(update, context): keyboard = InlineKeyboardMarkup([ [InlineKeyboardButton("Подписаться на канал", url=CHANNEL_URL)], [InlineKeyboardButton("Проверить подписку", callback_data="check_subscription")] ]) await update.message.reply_text( "❌ Для использования бота необходимо подписаться на канал!", reply_markup=keyboard ) return if text == " Подписка": print("Показываем статус подписки") # Для отладки await show_subscription_status(update, context) elif text == " Тарифы": print("Показываем тарифы") # Для отладки await show_tariffs(update, context) else: print(f"Неизвестная команда: {text}") # Для отладки await update.message.reply_text("Используйте кнопки меню для навигации") async def callback_handler(update: Update, context: ContextTypes.DEFAULT_TYPE): query = update.callback_query await query.answer() try: if query.data == "check_subscription": if await check_user_subscription(update, context): keyboard = ReplyKeyboardMarkup([ [' Подписка', ' Тарифы'] ], resize_keyboard=True) await query.message.edit_text( "✅ Спасибо за подписку!\n\n" "Отправьте мне видео, и я преобразую его в видеокружок.", reply_markup=keyboard ) else: keyboard = InlineKeyboardMarkup([ [InlineKeyboardButton("Подписаться на канал", url=CHANNEL_URL)], [InlineKeyboardButton("Проверить подписку", callback_data="check_subscription")] ]) await query.message.edit_text( "❌ Вы все еще не подписаны на канал!", reply_markup=keyboard ) elif query.data == "back_to_main": keyboard = ReplyKeyboardMarkup([ [' Подписка', ' Тарифы'] ], resize_keyboard=True) await query.message.reply_text( " Главное меню", reply_markup=keyboard ) await query.message.delete() elif query.data == "back_to_tariffs": keyboard = InlineKeyboardMarkup([ [InlineKeyboardButton("7 дней - 500 руб.", callback_data="tariff_7")], [InlineKeyboardButton("14 дней - 900 руб.", callback_data="tariff_14")], [InlineKeyboardButton("30 дней - 1500 руб.", callback_data="tariff_30")], [InlineKeyboardButton("◀ Назад", callback_data="back_to_main")] ]) await query.message.edit_text( " Выберите тариф:\n\n" "• 7 дней - 500 руб.\n" "• 14 дней - 900 руб.\n" "• 30 дней - 1500 руб.", reply_markup=keyboard ) elif query.data.startswith("tariff_"): days = query.data.split("_")[1] price = { "7": "500", "14": "900", "30": "1500" }[days] keyboard = InlineKeyboardMarkup([ [InlineKeyboardButton(" Оплатить", callback_data=f"pay_{days}")], [InlineKeyboardButton("◀ Назад", callback_data="back_to_tariffs")] ]) await query.message.edit_text( f" Товар: Подписка на {days} дней\n" f" Цена: {price} ₽\n" f" Описание:\n" f"Доступ к боту на {days} дней\n" f"Неограниченное количество конвертаций", reply_markup=keyboard ) elif query.data.startswith("pay_"): days = query.data.split("_")[1] keyboard = InlineKeyboardMarkup([ [InlineKeyboardButton(" CryptoBot - USDT", callback_data=f"crypto_usdt_{days}")], [InlineKeyboardButton(" CryptoBot - TON", callback_data=f"crypto_ton_{days}")], [InlineKeyboardButton("◀ Назад", callback_data=f"tariff_{days}")] ]) await query.message.edit_text( " Выберите способ оплаты:", reply_markup=keyboard ) elif query.data.startswith("crypto_"): _, crypto_type, days = query.data.split("_") price_rub = { "7": 500, "14": 900, "30": 1500 }[days] # Создаем заказ в базе данных order_id = create_order(query.from_user.id, price_rub, crypto_type, int(days)) # Создаем инвойс в CryptoBot asset = "USDT" if crypto_type == "usdt" else "TON" invoice_data = create_invoice(price_rub, asset) if invoice_data.get('ok'): invoice_id = invoice_data['result']['invoice_id'] pay_url = invoice_data['result']['pay_url'] amount_crypto = invoice_data['result']['amount_crypto'] # Обновляем заказ с invoice_id update_order_status(order_id, 'waiting', invoice_id) # Время создания и окончания now = datetime.datetime.now() expires = now + datetime.timedelta(minutes=15) keyboard = InlineKeyboardMarkup([ [InlineKeyboardButton(" Перейти к оплате", url=pay_url)], [InlineKeyboardButton(" Проверить оплату", callback_data=f"check_{order_id}")], [InlineKeyboardButton("❌ Отменить оплату", callback_data=f"cancel_{order_id}")] ]) await query.message.edit_text( "➖➖➖➖➖➖➖➖➖➖➖➖\n" f" Товар: Подписка на {days} дней\n" f" Цена: {price_rub} ₽ ({amount_crypto:.2f} {asset})\n" f" Кол-во: 1 шт.\n" f" Заказ: {order_id}\n" f" Время заказа: {now.strftime('%Y-%m-%d %H:%M')}\n" f" Способ оплаты: CryptoBot ({asset})\n" "➖➖➖➖➖➖➖➖➖➖➖➖\n" "Для оплаты перейдите по ссылке!\n" "⏰ Время на оплату: 15 минут\n" f" Необходимо оплатить до {expires.strftime('%H:%M')}\n" "➖➖➖➖➖➖➖➖➖➖➖➖", reply_markup=keyboard ) else: error_message = invoice_data.get('error', 'Неизвестная ошибка') await query.message.edit_text( f"❌ Ошибка при создании платежа: {error_message}\n" "Пожалуйста, попробуйте позже или выберите другой способ оплаты.", reply_markup=InlineKeyboardMarkup([[ InlineKeyboardButton("◀ Назад", callback_data=f"pay_{days}") ]]) ) elif query.data.startswith("check_"): try: order_id = int(query.data.split("_")[1]) order = get_order(order_id) if not order: await query.message.edit_text( "❌ Заказ не найден", reply_markup=InlineKeyboardMarkup([[ InlineKeyboardButton("◀ Назад к тарифам", callback_data="back_to_tariffs") ]]) ) return invoice_id = order[7] # Получаем invoice_id из заказа status = check_invoice(invoice_id) print(f"Payment status for order {order_id}: {status}") # Для отладки if status == 'paid': # Обновляем статус заказа и добавляем подписку пользователю update_order_status(order_id, 'completed') days = order[4] # Получаем количество дней подписки из заказа update_user_subscription(order[1], days) # Добавляем подписку пользователю await query.message.edit_text( "✅ Оплата успешно получена!\n\n" f"Подписка на {order[4]} дней активирована.\n" "Спасибо за покупку!", reply_markup=InlineKeyboardMarkup([[ InlineKeyboardButton(" Вернуться в главное меню", callback_data="back_to_main") ]]) ) elif status == 'expired': await query.message.edit_text( "❌ Срок действия платежа истек.\n" "Пожалуйста, создайте новый заказ.", reply_markup=InlineKeyboardMarkup([[ InlineKeyboardButton("◀ Назад к тарифам", callback_data="back_to_tariffs") ]]) ) elif status == 'error': await query.answer( "❌ Ошибка при проверке платежа. Попробуйте позже.", show_alert=True ) else: # pending # Сохраняем текущую клавиатуру current_keyboard = query.message.reply_markup await query.answer( "⏳ Оплата еще не получена. Пожалуйста, завершите оплату или попробуйте позже.", show_alert=True ) except Exception as e: print(f"Error checking payment: {str(e)}") await query.answer( "❌ Произошла ошибка при проверке оплаты. Попробуйте позже.", show_alert=True ) elif query.data.startswith("cancel_"): order_id = int(query.data.split("_")[1]) order = get_order(order_id) if order and order[5] != 'completed': # Проверяем, что заказ не выполнен update_order_status(order_id, 'cancelled') await query.message.edit_text( "❌ Заказ отменен", reply_markup=InlineKeyboardMarkup([[ InlineKeyboardButton("◀ Назад к тарифам", callback_data="back_to_tariffs") ]]) ) else: await query.answer("Этот заказ нельзя отменить", show_alert=True) except Exception as e: print(f"Error in callback_handler: {e}") await query.message.edit_text( "❌ Произошла ошибка. Пожалуйста, попробуйте позже или обратитесь в поддержку.", reply_markup=InlineKeyboardMarkup([[ InlineKeyboardButton("◀ Вернуться в главное меню", callback_data="back_to_main") ]]) ) async def check_subscription(update: Update, context: ContextTypes.DEFAULT_TYPE): query = update.callback_query await query.answer() if await check_user_subscription(update, context): keyboard = ReplyKeyboardMarkup([ [' Подписка', ' Тарифы'] ], resize_keyboard=True) await query.edit_message_text( "✅ Спасибо за подписку!\n\n" "Отправьте мне видео, и я преобразую его в видеокружок.", reply_markup=keyboard ) else: keyboard = InlineKeyboardMarkup([ [InlineKeyboardButton("Подписаться на канал", url=CHANNEL_URL)], [InlineKeyboardButton("Проверить подписку", callback_data="check_subscription")] ]) await query.edit_message_text( "❌ Вы все еще не подписаны на канал!", reply_markup=keyboard ) async def show_subscription_status(update: Update, context: ContextTypes.DEFAULT_TYPE): user_id = update.effective_user.id user_data = get_user(user_id) if user_data: subscription_end_date_str = user_data[2] if subscription_end_date_str: subscription_end_date = datetime.datetime.strptime(subscription_end_date_str, "%Y-%m-%d").date() today = datetime.date.today() if subscription_end_date >= today: days_left = (subscription_end_date - today).days await update.message.reply_text( f"✅ Ваша подписка активна до {subscription_end_date.strftime('%d.%m.%Y')}.\n" f"Осталось дней: {days_left}." ) else: await update.message.reply_text( "❌ Ваша подписка истекла.\n" "Пожалуйста, приобретите новый тариф." ) else: await update.message.reply_text( "✅ У вас активна пробная версия на 7 дней\n" "Вы можете конвертировать видео в видеокружок." ) else: await update.message.reply_text( "❌ Не удалось получить данные о пользователе.\n" "Пожалуйста, перезапустите бота командой /start." ) async def show_tariffs(update: Update, context: ContextTypes.DEFAULT_TYPE): keyboard = InlineKeyboardMarkup([ [InlineKeyboardButton("7 дней - 500 руб.", callback_data="tariff_7")], [InlineKeyboardButton("14 дней - 900 руб.", callback_data="tariff_14")], [InlineKeyboardButton("30 дней - 1500 руб.", callback_data="tariff_30")], [InlineKeyboardButton("◀ Назад", callback_data="back_to_main")] ]) await update.message.reply_text( " Выберите тариф:\n\n" "• 7 дней - 500 руб.\n" "• 14 дней - 900 руб.\n" "• 30 дней - 1500 руб.", reply_markup=keyboard ) async def process_video(update: Update, context: ContextTypes.DEFAULT_TYPE): if not await check_user_subscription(update, context): keyboard = InlineKeyboardMarkup([ [InlineKeyboardButton("Подписаться на канал", url=CHANNEL_URL)], [InlineKeyboardButton("Проверить подписку", callback_data="check_subscription")] ]) await update.message.reply_text( "❌ Для использования бота необходимо подписаться на канал!", reply_markup=keyboard ) return user_id = update.effective_user.id user_data = get_user(user_id) if user_data: subscription_end_date_str = user_data[2] if subscription_end_date_str: subscription_end_date = datetime.datetime.strptime(subscription_end_date_str, "%Y-%m-%d").date() if subscription_end_date < datetime.date.today(): await update.message.reply_text( "❌ Ваша подписка истекла.\n" "Пожалуйста, приобретите новый тариф." ) return else: await update.message.reply_text( "✅ У вас активна пробная версия на 7 дней\n" "Вы можете конвертировать видео в видеокружок." ) else: await update.message.reply_text( "❌ Не удалось получить данные о пользователе.\n" "Пожалуйста, перезапустите бота командой /start." ) return await update.message.reply_text("⏳ Начинаю конвертацию видео...") try: video_file = await context.bot.getFile(update.message.video.file_id) await video_file.download_to_drive("input_video.mp4") # Преобразование видео в видеокружок input_video = VideoFileClip("input_video.mp4") w, h = input_video.size circle_size = 360 aspect_ratio = float(w) / float(h) if w > h: new_w = int(circle_size * aspect_ratio) new_h = circle_size else: new_w = circle_size new_h = int(circle_size / aspect_ratio) resized_video = input_video.resize((new_w, new_h)) output_video = resized_video.crop(x_center=resized_video.w/2, y_center=resized_video.h/2, width=circle_size, height=circle_size) output_video.write_videofile("output_video.mp4", codec="libx264", audio_codec="aac", bitrate="5M") # Отправка видеокружка в чат with open("output_video.mp4", "rb") as video: await context.bot.send_video_note( chat_id=update.message.chat_id, video_note=video, duration=int(output_video.duration), length=circle_size ) await update.message.reply_text( "✅ Видео успешно конвертировано!" ) except Exception as e: await update.message.reply_text( "❌ Произошла ошибка при конвертации видео. Попробуйте другое видео." ) print(f"Error: {e}") finally: # Очистка временных файлов if 'input_video' in locals(): input_video.close() if 'output_video' in locals(): output_video.close() import os if os.path.exists("input_video.mp4"): os.remove("input_video.mp4") if os.path.exists("output_video.mp4"): os.remove("output_video.mp4") Python from moviepy.editor import * from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup, ReplyKeyboardMarkup from telegram.ext import ContextTypes from config import CHANNEL_ID, CHANNEL_URL from database import create_user, get_user, update_user_subscription, create_order, update_order_status, get_order import datetime from crypto import create_invoice, check_invoice async def check_user_subscription(update: Update, context: ContextTypes.DEFAULT_TYPE) -> bool: try: user = await context.bot.get_chat_member(chat_id=CHANNEL_ID, user_id=update.effective_user.id) return user.status in ['member', 'administrator', 'creator'] except: return False async def start(update: Update, context: ContextTypes.DEFAULT_TYPE): user_id = update.effective_user.id create_user(user_id) if await check_user_subscription(update, context): keyboard = ReplyKeyboardMarkup([ [' Подписка', ' Тарифы'] ], resize_keyboard=True) await update.message.reply_text( " Здравствуйте! Это бот для преобразования видео в видеокружок.\n\n" "Отправьте мне видео, и я преобразую его в видеокружок.", reply_markup=keyboard ) else: keyboard = InlineKeyboardMarkup([ [InlineKeyboardButton("Подписаться на канал", url=CHANNEL_URL)], [InlineKeyboardButton("Проверить подписку", callback_data="check_subscription")] ]) await update.message.reply_text( "Для использования бота необходимо подписаться на канал!", reply_markup=keyboard ) async def handle_text(update: Update, context: ContextTypes.DEFAULT_TYPE): text = update.message.text user_id = update.effective_user.id print(f"Получено текстовое сообщение: {text}") # Для отладки if not await check_user_subscription(update, context): keyboard = InlineKeyboardMarkup([ [InlineKeyboardButton("Подписаться на канал", url=CHANNEL_URL)], [InlineKeyboardButton("Проверить подписку", callback_data="check_subscription")] ]) await update.message.reply_text( "❌ Для использования бота необходимо подписаться на канал!", reply_markup=keyboard ) return if text == " Подписка": print("Показываем статус подписки") # Для отладки await show_subscription_status(update, context) elif text == " Тарифы": print("Показываем тарифы") # Для отладки await show_tariffs(update, context) else: print(f"Неизвестная команда: {text}") # Для отладки await update.message.reply_text("Используйте кнопки меню для навигации") async def callback_handler(update: Update, context: ContextTypes.DEFAULT_TYPE): query = update.callback_query await query.answer() try: if query.data == "check_subscription": if await check_user_subscription(update, context): keyboard = ReplyKeyboardMarkup([ [' Подписка', ' Тарифы'] ], resize_keyboard=True) await query.message.edit_text( "✅ Спасибо за подписку!\n\n" "Отправьте мне видео, и я преобразую его в видеокружок.", reply_markup=keyboard ) else: keyboard = InlineKeyboardMarkup([ [InlineKeyboardButton("Подписаться на канал", url=CHANNEL_URL)], [InlineKeyboardButton("Проверить подписку", callback_data="check_subscription")] ]) await query.message.edit_text( "❌ Вы все еще не подписаны на канал!", reply_markup=keyboard ) elif query.data == "back_to_main": keyboard = ReplyKeyboardMarkup([ [' Подписка', ' Тарифы'] ], resize_keyboard=True) await query.message.reply_text( " Главное меню", reply_markup=keyboard ) await query.message.delete() elif query.data == "back_to_tariffs": keyboard = InlineKeyboardMarkup([ [InlineKeyboardButton("7 дней - 500 руб.", callback_data="tariff_7")], [InlineKeyboardButton("14 дней - 900 руб.", callback_data="tariff_14")], [InlineKeyboardButton("30 дней - 1500 руб.", callback_data="tariff_30")], [InlineKeyboardButton("◀ Назад", callback_data="back_to_main")] ]) await query.message.edit_text( " Выберите тариф:\n\n" "• 7 дней - 500 руб.\n" "• 14 дней - 900 руб.\n" "• 30 дней - 1500 руб.", reply_markup=keyboard ) elif query.data.startswith("tariff_"): days = query.data.split("_")[1] price = { "7": "500", "14": "900", "30": "1500" }[days] keyboard = InlineKeyboardMarkup([ [InlineKeyboardButton(" Оплатить", callback_data=f"pay_{days}")], [InlineKeyboardButton("◀ Назад", callback_data="back_to_tariffs")] ]) await query.message.edit_text( f" Товар: Подписка на {days} дней\n" f" Цена: {price} ₽\n" f" Описание:\n" f"Доступ к боту на {days} дней\n" f"Неограниченное количество конвертаций", reply_markup=keyboard ) elif query.data.startswith("pay_"): days = query.data.split("_")[1] keyboard = InlineKeyboardMarkup([ [InlineKeyboardButton(" CryptoBot - USDT", callback_data=f"crypto_usdt_{days}")], [InlineKeyboardButton(" CryptoBot - TON", callback_data=f"crypto_ton_{days}")], [InlineKeyboardButton("◀ Назад", callback_data=f"tariff_{days}")] ]) await query.message.edit_text( " Выберите способ оплаты:", reply_markup=keyboard ) elif query.data.startswith("crypto_"): _, crypto_type, days = query.data.split("_") price_rub = { "7": 500, "14": 900, "30": 1500 }[days] # Создаем заказ в базе данных order_id = create_order(query.from_user.id, price_rub, crypto_type, int(days)) # Создаем инвойс в CryptoBot asset = "USDT" if crypto_type == "usdt" else "TON" invoice_data = create_invoice(price_rub, asset) if invoice_data.get('ok'): invoice_id = invoice_data['result']['invoice_id'] pay_url = invoice_data['result']['pay_url'] amount_crypto = invoice_data['result']['amount_crypto'] # Обновляем заказ с invoice_id update_order_status(order_id, 'waiting', invoice_id) # Время создания и окончания now = datetime.datetime.now() expires = now + datetime.timedelta(minutes=15) keyboard = InlineKeyboardMarkup([ [InlineKeyboardButton(" Перейти к оплате", url=pay_url)], [InlineKeyboardButton(" Проверить оплату", callback_data=f"check_{order_id}")], [InlineKeyboardButton("❌ Отменить оплату", callback_data=f"cancel_{order_id}")] ]) await query.message.edit_text( "➖➖➖➖➖➖➖➖➖➖➖➖\n" f" Товар: Подписка на {days} дней\n" f" Цена: {price_rub} ₽ ({amount_crypto:.2f} {asset})\n" f" Кол-во: 1 шт.\n" f" Заказ: {order_id}\n" f" Время заказа: {now.strftime('%Y-%m-%d %H:%M')}\n" f" Способ оплаты: CryptoBot ({asset})\n" "➖➖➖➖➖➖➖➖➖➖➖➖\n" "Для оплаты перейдите по ссылке!\n" "⏰ Время на оплату: 15 минут\n" f" Необходимо оплатить до {expires.strftime('%H:%M')}\n" "➖➖➖➖➖➖➖➖➖➖➖➖", reply_markup=keyboard ) else: error_message = invoice_data.get('error', 'Неизвестная ошибка') await query.message.edit_text( f"❌ Ошибка при создании платежа: {error_message}\n" "Пожалуйста, попробуйте позже или выберите другой способ оплаты.", reply_markup=InlineKeyboardMarkup([[ InlineKeyboardButton("◀ Назад", callback_data=f"pay_{days}") ]]) ) elif query.data.startswith("check_"): try: order_id = int(query.data.split("_")[1]) order = get_order(order_id) if not order: await query.message.edit_text( "❌ Заказ не найден", reply_markup=InlineKeyboardMarkup([[ InlineKeyboardButton("◀ Назад к тарифам", callback_data="back_to_tariffs") ]]) ) return invoice_id = order[7] # Получаем invoice_id из заказа status = check_invoice(invoice_id) print(f"Payment status for order {order_id}: {status}") # Для отладки if status == 'paid': # Обновляем статус заказа и добавляем подписку пользователю update_order_status(order_id, 'completed') days = order[4] # Получаем количество дней подписки из заказа update_user_subscription(order[1], days) # Добавляем подписку пользователю await query.message.edit_text( "✅ Оплата успешно получена!\n\n" f"Подписка на {order[4]} дней активирована.\n" "Спасибо за покупку!", reply_markup=InlineKeyboardMarkup([[ InlineKeyboardButton(" Вернуться в главное меню", callback_data="back_to_main") ]]) ) elif status == 'expired': await query.message.edit_text( "❌ Срок действия платежа истек.\n" "Пожалуйста, создайте новый заказ.", reply_markup=InlineKeyboardMarkup([[ InlineKeyboardButton("◀ Назад к тарифам", callback_data="back_to_tariffs") ]]) ) elif status == 'error': await query.answer( "❌ Ошибка при проверке платежа. Попробуйте позже.", show_alert=True ) else: # pending # Сохраняем текущую клавиатуру current_keyboard = query.message.reply_markup await query.answer( "⏳ Оплата еще не получена. Пожалуйста, завершите оплату или попробуйте позже.", show_alert=True ) except Exception as e: print(f"Error checking payment: {str(e)}") await query.answer( "❌ Произошла ошибка при проверке оплаты. Попробуйте позже.", show_alert=True ) elif query.data.startswith("cancel_"): order_id = int(query.data.split("_")[1]) order = get_order(order_id) if order and order[5] != 'completed': # Проверяем, что заказ не выполнен update_order_status(order_id, 'cancelled') await query.message.edit_text( "❌ Заказ отменен", reply_markup=InlineKeyboardMarkup([[ InlineKeyboardButton("◀ Назад к тарифам", callback_data="back_to_tariffs") ]]) ) else: await query.answer("Этот заказ нельзя отменить", show_alert=True) except Exception as e: print(f"Error in callback_handler: {e}") await query.message.edit_text( "❌ Произошла ошибка. Пожалуйста, попробуйте позже или обратитесь в поддержку.", reply_markup=InlineKeyboardMarkup([[ InlineKeyboardButton("◀ Вернуться в главное меню", callback_data="back_to_main") ]]) ) async def check_subscription(update: Update, context: ContextTypes.DEFAULT_TYPE): query = update.callback_query await query.answer() if await check_user_subscription(update, context): keyboard = ReplyKeyboardMarkup([ [' Подписка', ' Тарифы'] ], resize_keyboard=True) await query.edit_message_text( "✅ Спасибо за подписку!\n\n" "Отправьте мне видео, и я преобразую его в видеокружок.", reply_markup=keyboard ) else: keyboard = InlineKeyboardMarkup([ [InlineKeyboardButton("Подписаться на канал", url=CHANNEL_URL)], [InlineKeyboardButton("Проверить подписку", callback_data="check_subscription")] ]) await query.edit_message_text( "❌ Вы все еще не подписаны на канал!", reply_markup=keyboard ) async def show_subscription_status(update: Update, context: ContextTypes.DEFAULT_TYPE): user_id = update.effective_user.id user_data = get_user(user_id) if user_data: subscription_end_date_str = user_data[2] if subscription_end_date_str: subscription_end_date = datetime.datetime.strptime(subscription_end_date_str, "%Y-%m-%d").date() today = datetime.date.today() if subscription_end_date >= today: days_left = (subscription_end_date - today).days await update.message.reply_text( f"✅ Ваша подписка активна до {subscription_end_date.strftime('%d.%m.%Y')}.\n" f"Осталось дней: {days_left}." ) else: await update.message.reply_text( "❌ Ваша подписка истекла.\n" "Пожалуйста, приобретите новый тариф." ) else: await update.message.reply_text( "✅ У вас активна пробная версия на 7 дней\n" "Вы можете конвертировать видео в видеокружок." ) else: await update.message.reply_text( "❌ Не удалось получить данные о пользователе.\n" "Пожалуйста, перезапустите бота командой /start." ) async def show_tariffs(update: Update, context: ContextTypes.DEFAULT_TYPE): keyboard = InlineKeyboardMarkup([ [InlineKeyboardButton("7 дней - 500 руб.", callback_data="tariff_7")], [InlineKeyboardButton("14 дней - 900 руб.", callback_data="tariff_14")], [InlineKeyboardButton("30 дней - 1500 руб.", callback_data="tariff_30")], [InlineKeyboardButton("◀ Назад", callback_data="back_to_main")] ]) await update.message.reply_text( " Выберите тариф:\n\n" "• 7 дней - 500 руб.\n" "• 14 дней - 900 руб.\n" "• 30 дней - 1500 руб.", reply_markup=keyboard ) async def process_video(update: Update, context: ContextTypes.DEFAULT_TYPE): if not await check_user_subscription(update, context): keyboard = InlineKeyboardMarkup([ [InlineKeyboardButton("Подписаться на канал", url=CHANNEL_URL)], [InlineKeyboardButton("Проверить подписку", callback_data="check_subscription")] ]) await update.message.reply_text( "❌ Для использования бота необходимо подписаться на канал!", reply_markup=keyboard ) return user_id = update.effective_user.id user_data = get_user(user_id) if user_data: subscription_end_date_str = user_data[2] if subscription_end_date_str: subscription_end_date = datetime.datetime.strptime(subscription_end_date_str, "%Y-%m-%d").date() if subscription_end_date < datetime.date.today(): await update.message.reply_text( "❌ Ваша подписка истекла.\n" "Пожалуйста, приобретите новый тариф." ) return else: await update.message.reply_text( "✅ У вас активна пробная версия на 7 дней\n" "Вы можете конвертировать видео в видеокружок." ) else: await update.message.reply_text( "❌ Не удалось получить данные о пользователе.\n" "Пожалуйста, перезапустите бота командой /start." ) return await update.message.reply_text("⏳ Начинаю конвертацию видео...") try: video_file = await context.bot.getFile(update.message.video.file_id) await video_file.download_to_drive("input_video.mp4") # Преобразование видео в видеокружок input_video = VideoFileClip("input_video.mp4") w, h = input_video.size circle_size = 360 aspect_ratio = float(w) / float(h) if w > h: new_w = int(circle_size * aspect_ratio) new_h = circle_size else: new_w = circle_size new_h = int(circle_size / aspect_ratio) resized_video = input_video.resize((new_w, new_h)) output_video = resized_video.crop(x_center=resized_video.w/2, y_center=resized_video.h/2, width=circle_size, height=circle_size) output_video.write_videofile("output_video.mp4", codec="libx264", audio_codec="aac", bitrate="5M") # Отправка видеокружка в чат with open("output_video.mp4", "rb") as video: await context.bot.send_video_note( chat_id=update.message.chat_id, video_note=video, duration=int(output_video.duration), length=circle_size ) await update.message.reply_text( "✅ Видео успешно конвертировано!" ) except Exception as e: await update.message.reply_text( "❌ Произошла ошибка при конвертации видео. Попробуйте другое видео." ) print(f"Error: {e}") finally: # Очистка временных файлов if 'input_video' in locals(): input_video.close() if 'output_video' in locals(): output_video.close() import os if os.path.exists("input_video.mp4"): os.remove("input_video.mp4") if os.path.exists("output_video.mp4"): os.remove("output_video.mp4")