Spaces:
Sleeping
Sleeping
| import os | |
| import sys | |
| import time | |
| import requests | |
| from dotenv import load_dotenv | |
| # Load local environment settings | |
| load_dotenv() | |
| # Import helper functions and config from vod_backfiller | |
| sys.path.append(os.path.dirname(os.path.abspath(__file__))) | |
| from vod_backfiller import get_vod_details, download_vod_chat, headers, API_URL, TWITCH_CHANNEL | |
| def backfill_single_vod(vod_id): | |
| print(f"\n=========================================================") | |
| print(f" Начинаем обработку VOD: {vod_id}...") | |
| print(f"=========================================================") | |
| # 1. Fetch metadata | |
| print("[Sync] Получение метаданных VOD...") | |
| details = get_vod_details(vod_id) | |
| if not details: | |
| print(f"[Error] Не удалось получить информацию о VOD {vod_id}. Пропускаем.") | |
| return False | |
| title = details.get("title", "Архивный стрим") | |
| created_at_raw = details.get("createdAt") # e.g. "2026-06-09T17:15:30Z" | |
| length_seconds = details.get("lengthSeconds", 0) | |
| # timezone-safe calculation using datetime | |
| from datetime import datetime, timedelta | |
| created_at = created_at_raw.replace("+00:00", "").replace("Z", "") + "Z" | |
| dt_start = datetime.fromisoformat(created_at_raw.replace("Z", "+00:00")) | |
| dt_end = dt_start + timedelta(seconds=length_seconds) | |
| end_time = dt_end.strftime("%Y-%m-%dT%H:%M:%SZ") | |
| print(f"Название: {title}") | |
| print(f"Начало: {created_at}") | |
| print(f"Длительность: {length_seconds // 3600}ч {(length_seconds % 3600) // 60}м") | |
| # 2. Sync stream record in DB | |
| print("\n[Sync] Регистрация сессии стрима на бэкенде...") | |
| try: | |
| url = f"{API_URL}/api/streams/sync-vod-direct" | |
| payload = { | |
| "twitchStreamId": f"vod-{vod_id}", | |
| "title": title, | |
| "category": "Архив", | |
| "startTime": created_at, | |
| "endTime": end_time | |
| } | |
| res = requests.post(url, json=payload, headers=headers, timeout=5) | |
| if res.status_code != 200: | |
| print(f"[Error] Не удалось синхронизировать сессию стрима: {res.status_code} - {res.text}") | |
| return False | |
| print("-> Сессия стрима успешно зарегистрирована в базе!") | |
| except Exception as e: | |
| print(f"[Error] Ошибка сети при обращении к бэкенду: {e}") | |
| return False | |
| # 3. Check for existing backfill status | |
| chat_start_offset = 0 | |
| try: | |
| status_url = f"{API_URL}/api/streams/backfill-status?twitchStreamId=vod-{vod_id}" | |
| res = requests.get(status_url, headers=headers, timeout=5) | |
| if res.status_code == 200: | |
| status_data = res.json() | |
| msg_count = status_data.get("messageCount", 0) | |
| latest_msg_ts = status_data.get("latestMessageTimestamp") | |
| if msg_count > 0 and latest_msg_ts: | |
| from datetime import datetime | |
| clean_ts = latest_msg_ts.replace('Z', '+00:00') | |
| latest_epoch = datetime.fromisoformat(clean_ts).timestamp() | |
| clean_created = created_at.replace('Z', '+00:00') | |
| created_epoch = datetime.fromisoformat(clean_created).timestamp() | |
| diff = int(latest_epoch - created_epoch) | |
| if diff > 0: | |
| chat_start_offset = diff | |
| print(f"[Sync] Найден существующий чат в базе ({msg_count} сообщений). Возобновляем загрузку с секунды {chat_start_offset}...") | |
| except Exception as e: | |
| print(f"[Sync Warning] Не удалось получить статус дозаписи: {e}") | |
| # 4. Download and Upload Chat comments | |
| chat_comments = download_vod_chat(vod_id, start_offset=chat_start_offset) | |
| if chat_comments: | |
| print("\n[Sync] Отправка чата на сервер (пакетами по 100 сообщений)...") | |
| batch_size = 100 | |
| for i in range(0, len(chat_comments), batch_size): | |
| batch = chat_comments[i:i+batch_size] | |
| try: | |
| url = f"{API_URL}/api/log/messages" | |
| res = requests.post(url, json={"messages": batch}, headers=headers, timeout=5) | |
| if res.status_code == 200: | |
| print(f"-> Отправлено сообщений: {i + len(batch)} / {len(chat_comments)}", end="\r") | |
| else: | |
| print(f"\n-> Ошибка отправки пакета: {res.status_code}") | |
| except Exception as e: | |
| print(f"\n-> Ошибка сети при отправке пакета: {e}") | |
| print("\n-> Синхронизация чата успешно завершена!") | |
| else: | |
| print("\n-> Новых сообщений для загрузки не найдено.") | |
| # 5. Mark Completed on Server | |
| try: | |
| url_mark = f"{API_URL}/api/streams/mark-backfilled" | |
| requests.post(url_mark, json={"twitchStreamId": f"vod-{vod_id}"}, headers=headers, timeout=5) | |
| print("-> Статус импорта успешно обновлен на сервере!") | |
| except Exception as e: | |
| print(f"[Warning] Не удалось отметить стрим как импортированный: {e}") | |
| print(f"\n[Done] Обработка VOD {vod_id} завершена!") | |
| return True | |
| if __name__ == "__main__": | |
| vod_ids = ['2798809640'] | |
| print("=========================================================") | |
| print(" Автоматический импорт чатов для последних VOD ") | |
| print("=========================================================") | |
| print(f"Список VOD: {', '.join(vod_ids)}") | |
| print(f"Канал: {TWITCH_CHANNEL}") | |
| print(f"Бэкенд: {API_URL}") | |
| print("=========================================================") | |
| for vid in vod_ids: | |
| try: | |
| backfill_single_vod(vid) | |
| except Exception as e: | |
| print(f"[Error] Критическая ошибка при обработке VOD {vid}: {e}") | |
| print("\nВсе три VOD успешно обработаны!") | |