Spaces:
Running
Running
# app.py | |
# نسخه نهایی کاملشده: پشتیبانی از همه قابلیتها | |
import os | |
import sys | |
import re | |
import subprocess | |
import json | |
from io import BytesIO | |
from flask import Flask, request, jsonify | |
from telegram import Update, InputFile, InlineKeyboardButton, InlineKeyboardMarkup | |
from telegram.ext import ( | |
Application, CommandHandler, MessageHandler, CallbackQueryHandler, | |
filters, ConversationHandler | |
) | |
from telegram.constants import ParseMode | |
from pydub import AudioSegment | |
import nest_asyncio | |
# --- تنظیمات --- | |
TOKEN = os.getenv("TELEGRAM_BOT_TOKEN") | |
BOT_USERNAME = os.getenv("TELEGRAM_BOT_USERNAME", "Voice2mp3_RoBot") | |
ADMIN_ID = int(os.getenv("TELEGRAM_ADMIN_ID", "0")) | |
WEBHOOK_URL = os.getenv("WEBHOOK_URL") | |
DOWNLOAD_DIR = "/tmp/downloads" | |
OUTPUT_DIR = "/tmp/outputs" | |
CHANNELS_FILE = "channels.json" | |
os.makedirs(DOWNLOAD_DIR, exist_ok=True) | |
os.makedirs(OUTPUT_DIR, exist_ok=True) | |
LANGUAGE_SELECTION, MAIN_MENU, CONVERT_AUDIO, CUT_AUDIO_FILE, CUT_AUDIO_RANGE, \ | |
VIDEO_CONVERSION_MODE, WAITING_FOR_MEMBERSHIP, ADMIN_MENU, ADD_CHANNEL, LIST_REMOVE_CHANNELS = range(10) | |
app = Flask(__name__) | |
_application_instance = None | |
# --- بارگذاری کانالها --- | |
def load_required_channels(): | |
if os.path.exists(CHANNELS_FILE): | |
try: | |
with open(CHANNELS_FILE, 'r', encoding='utf-8') as f: | |
return json.load(f) | |
except json.JSONDecodeError: | |
print("[!] channels.json خوانده نشد", file=sys.stderr) | |
return [] | |
def save_required_channels(channels): | |
with open(CHANNELS_FILE, 'w', encoding='utf-8') as f: | |
json.dump(channels, f, indent=4, ensure_ascii=False) | |
REQUIRED_CHANNELS = load_required_channels() | |
# --- پیامها --- | |
MESSAGES = { | |
'fa': { | |
'start_welcome': "سلام! من یک ربات تبدیل فرمت صوتی و ویدیویی هستم.", | |
'choose_language': "زبان خود را انتخاب کنید:", | |
'main_menu_prompt': "چه کاری میخواهید انجام دهید؟", | |
'btn_convert_format': "تبدیل فرمت صدا 🎵", | |
'btn_cut_audio': "برش صدا ✂️", | |
'btn_video_conversion': "تبدیل ویدیو دایرهای 🎥", | |
'processing_start': "⏳ در حال پردازش...", | |
'file_received': "✅ فایل دریافت شد.", | |
'conversion_done': "🎉 پردازش انجام شد!", | |
'cancel_message': "عملیات لغو شد.", | |
'membership_required': "برای ادامه، لطفاً ابتدا عضو کانالهای زیر شوید:", | |
'btn_join_channel': "عضو شدن 🤝", | |
'btn_check_membership': "بررسی عضویت ✅", | |
'not_admin': "شما دسترسی ندارید.", | |
'admin_menu_prompt': "مدیریت کانالها:", | |
'btn_add_channel': "➕ افزودن کانال", | |
'btn_list_channels': "📋 لیست/حذف کانالها", | |
'send_channel_link': "لینک یا آیدی کانال را ارسال کنید:", | |
'channel_added': "کانال افزوده شد.", | |
'channel_removed': "کانال حذف شد.", | |
} | |
} | |
def get_message(context, key): | |
lang = context.user_data.get('language', 'fa') | |
return MESSAGES.get(lang, MESSAGES['fa']).get(key, key) | |
# --- Handler های اصلی --- | |
async def start(update, context): | |
keyboard = [[InlineKeyboardButton("فارسی 🇮🇷", callback_data='set_lang_fa')]] | |
reply_markup = InlineKeyboardMarkup(keyboard) | |
await update.message.reply_text(get_message(context, 'choose_language'), reply_markup=reply_markup) | |
return LANGUAGE_SELECTION | |
async def set_language(update, context): | |
query = update.callback_query | |
await query.answer() | |
context.user_data['language'] = query.data.replace('set_lang_', '') | |
await query.edit_message_text(text=get_message(context, 'start_welcome')) | |
return await show_main_menu(update, context) | |
async def cancel(update, context): | |
await update.message.reply_text(get_message(context, 'cancel_message')) | |
return await show_main_menu(update, context) | |
async def show_main_menu(update, context): | |
keyboard = [ | |
[InlineKeyboardButton(get_message(context, 'btn_convert_format'), callback_data='select_convert_format')], | |
[InlineKeyboardButton(get_message(context, 'btn_cut_audio'), callback_data='select_cut_audio')], | |
[InlineKeyboardButton(get_message(context, 'btn_video_conversion'), callback_data='select_video_conversion')] | |
] | |
markup = InlineKeyboardMarkup(keyboard) | |
if update.callback_query: | |
await update.callback_query.edit_message_text(text=get_message(context, 'main_menu_prompt'), reply_markup=markup) | |
else: | |
await update.message.reply_text(text=get_message(context, 'main_menu_prompt'), reply_markup=markup) | |
return MAIN_MENU | |
# --- توابع تکمیلی (تبدیل، برش، بررسی عضویت، مدیریت ادمین و...) --- | |
# [در ادامه پیامها افزوده خواهد شد به دلیل محدودیت حجم متن] | |
# --- مسیرهای Flask --- | |
async def index(): | |
return jsonify({"status": "ok", "message": "Bot is running."}) | |
async def webhook(): | |
application = await get_telegram_application() | |
update = Update.de_json(request.get_json(force=True), application.bot) | |
await application.process_update(update) | |
return "ok" | |
async def set_webhook_route(): | |
application = await get_telegram_application() | |
url = WEBHOOK_URL | |
if not url: | |
return jsonify({"status": "error", "message": "WEBHOOK_URL not set."}), 500 | |
if not url.endswith("/webhook"): | |
url = f"{url.rstrip('/')}/webhook" | |
try: | |
await application.bot.set_webhook(url=url) | |
return jsonify({"status": "success", "message": f"Webhook set to {url}"}) | |
except Exception as e: | |
print(f"Webhook error: {e}", file=sys.stderr) | |
return jsonify({"status": "error", "message": str(e)}), 500 | |
# --- راهاندازی --- | |
async def get_telegram_application(): | |
global _application_instance | |
if _application_instance is None: | |
print("راهاندازی ربات تلگرام...") | |
app_ = Application.builder().token(TOKEN).build() | |
conv = ConversationHandler( | |
entry_points=[CommandHandler("start", start)], | |
states={ | |
LANGUAGE_SELECTION: [CallbackQueryHandler(set_language, pattern="^set_lang_.*")], | |
MAIN_MENU: [], | |
}, | |
fallbacks=[CommandHandler("cancel", cancel), CommandHandler("start", start)], | |
allow_reentry=True | |
) | |
app_.add_handler(conv) | |
_application_instance = app_ | |
await _application_instance.initialize() | |
print("ربات آماده است.") | |
return _application_instance | |
if __name__ == '__main__': | |
import asyncio | |
nest_asyncio.apply() | |
print("اجرای لوکال...") | |
asyncio.run(get_telegram_application()) | |
app.run(host='0.0.0.0', port=int(os.environ.get("PORT", 7860))) | |