Spaces:
No application file
No application file
import asyncio | |
import logging | |
import os | |
from datetime import datetime | |
from aiogram import Bot, Dispatcher, types | |
from aiogram.contrib.fsm_storage.memory import MemoryStorage | |
from aiogram.dispatcher import FSMContext | |
from aiogram.dispatcher.filters.state import State, StatesGroup | |
from aiogram.utils import executor | |
from apscheduler.schedulers.asyncio import AsyncIOScheduler | |
from apscheduler.triggers.cron import CronTrigger | |
# Настройки | |
BOT_TOKEN = "7903604359:AAFRZc1r8zqIQiX1N-VJJadRfmDf5ljf1Jg" # Замените на токен вашего бота | |
INSTAGRAM_APP_ID = "YOUR_INSTAGRAM_APP_ID" # Замените на ID вашего приложения Instagram | |
INSTAGRAM_APP_SECRET = "YOUR_INSTAGRAM_APP_SECRET" # Замените на секрет вашего приложения Instagram | |
INSTAGRAM_REDIRECT_URI = "YOUR_INSTAGRAM_REDIRECT_URI" # Замените на URI перенаправления | |
# Временное хранилище (для простоты) | |
user_data = {} | |
scheduled_posts = {} | |
# Временное хранилище для видео и описаний | |
video_data = {} | |
# Состояния для FSM | |
class ConnectAccount(StatesGroup): | |
platform = State() | |
class UploadVideo(StatesGroup): | |
video = State() | |
description = State() | |
publish_time = State() | |
logging.basicConfig(level=logging.INFO) | |
bot = Bot(token=BOT_TOKEN) | |
storage = MemoryStorage() | |
dp = Dispatcher(bot, storage=storage) | |
scheduler = AsyncIOScheduler() | |
# --- Хэндлеры --- | |
async def send_welcome(message: types.Message): | |
await message.reply("Привет! Этот бот поможет тебе планировать публикации в TikTok, Instagram и YouTube.") | |
async def connect_command(message: types.Message): | |
keyboard = types.ReplyKeyboardMarkup(resize_keyboard=True, selective=True) | |
keyboard.add("Instagram (тест)") # Пока добавим только Instagram для упрощения | |
# keyboard.add("TikTok (скоро)") | |
# keyboard.add("YouTube (скоро)") | |
await message.reply("Выберите платформу для подключения:", reply_markup=keyboard) | |
await ConnectAccount.platform.set() | |
async def process_connect_instagram(message: types.Message, state: FSMContext): | |
# TODO: Реализовать OAuth 2.0 flow для Instagram | |
auth_url = f"https://api.instagram.com/oauth/authorize?client_id={INSTAGRAM_APP_ID}&redirect_uri={INSTAGRAM_REDIRECT_URI}&scope=user_profile,user_media&response_type=code" | |
await message.reply(f"Для подключения Instagram перейдите по ссылке:\n{auth_url}\n\nПосле авторизации вы будете перенаправлены на страницу с кодом. Скопируйте этот код и отправьте его мне.") | |
await state.finish() # Временный финиш, обработка кода будет в отдельном хэндлере | |
async def upload_command(message: types.Message): | |
await message.reply("Пожалуйста, отправьте видео для публикации.") | |
await UploadVideo.video.set() | |
async def process_video(message: types.Message, state: FSMContext): | |
async with state.proxy() as data: | |
data['video'] = message.video.file_id | |
await message.reply("Отлично! Теперь, пожалуйста, напишите описание к видео (или отправьте '-' если описания нет).") | |
await UploadVideo.description.set() | |
async def process_description(message: types.Message, state: FSMContext): | |
async with state.proxy() as data: | |
data['description'] = message.text if message.text != '-' else "" | |
keyboard = types.ReplyKeyboardMarkup(resize_keyboard=True, selective=True) | |
keyboard.add("Сейчас") | |
keyboard.add("Указать время") | |
await message.reply("Когда вы хотите опубликовать видео?", reply_markup=keyboard) | |
await UploadVideo.publish_time.set() | |
async def process_publish_now(message: types.Message, state: FSMContext): | |
async with state.proxy() as data: | |
video_file = await bot.get_file(data['video']) | |
video_path = video_file.file_path | |
description = data['description'] | |
# TODO: Реализовать немедленную публикацию в выбранные соцсети | |
await message.reply(f"Видео будет опубликовано прямо сейчас с описанием: {description}") | |
# Временная имитация публикации | |
await asyncio.sleep(2) | |
await message.reply("Видео успешно опубликовано (имитация).") | |
await state.finish() | |
async def process_set_publish_time(message: types.Message): | |
await message.reply("Пожалуйста, укажите желаемое время публикации в формате ГГГГ-ММ-ДД ЧЧ:ММ (например, 2025-03-22 15:00).") | |
await dp.current_state().set_state(UploadVideo.publish_time) # Остаемся в этом состоянии для обработки времени | |
async def process_publish_time_input(message: types.Message, state: FSMContext): | |
try: | |
publish_at = datetime.strptime(message.text, '%Y-%m-%d %H:%M') | |
if publish_at <= datetime.now(): | |
await message.reply("Указанное время уже прошло. Пожалуйста, выберите будущее время.") | |
return | |
async with state.proxy() as data: | |
video_file = await bot.get_file(data['video']) | |
video_path = video_file.file_path | |
description = data['description'] | |
user_id = message.from_user.id | |
post_id = f"{user_id}_{datetime.now().timestamp()}" | |
scheduled_posts[post_id] = { | |
'user_id': user_id, | |
'video_path': video_path, | |
'description': description, | |
'publish_at': publish_at, | |
'platforms': ['instagram'] # Пока только одна платформа | |
} | |
scheduler.add_job(publish_scheduled_post, 'date', run_date=publish_at, args=[bot, post_id, scheduled_posts]) | |
await message.reply(f"Видео запланировано к публикации на {publish_at.strftime('%Y-%m-%d %H:%M')} с описанием: {description}") | |
except ValueError: | |
await message.reply("Неверный формат времени. Пожалуйста, используйте формат ГГГГ-ММ-ДД ЧЧ:ММ.") | |
return | |
await state.finish() | |
async def publish_scheduled_post(bot: Bot, post_id: str, scheduled_posts: dict): | |
post_data = scheduled_posts.get(post_id) | |
if post_data: | |
user_id = post_data['user_id'] | |
video_path = post_data['video_path'] | |
description = post_data['description'] | |
platforms = post_data['platforms'] | |
# TODO: Реализовать фактическую публикацию в Instagram API | |
# Вам потребуется получить токен доступа пользователя | |
await bot.send_message(user_id, f"Начинаю публикацию запланированного видео с описанием: {description} в {platforms}") | |
# Временная имитация публикации | |
await asyncio.sleep(5) | |
await bot.send_message(user_id, f"Видео успешно опубликовано (имитация) в {platforms}.") | |
del scheduled_posts[post_id] | |
else: | |
logging.warning(f"Запланированный пост с ID {post_id} не найден.") | |
async def main(): | |
scheduler.start() | |
await dp.start_polling() | |
if __name__ == '__main__': | |
asyncio.run(main()) | |