231 lines
5.1 KiB
Python
231 lines
5.1 KiB
Python
import os
|
|
import time
|
|
import logging
|
|
import subprocess
|
|
import json
|
|
from dotenv import load_dotenv
|
|
from pyrogram import Client, filters
|
|
from pyrogram.errors import FloodWait
|
|
import asyncio
|
|
|
|
from utils import (
|
|
get_local_videos,
|
|
process_local_thumbnail,
|
|
get_batch_directories,
|
|
get_batch_videos
|
|
)
|
|
|
|
load_dotenv()
|
|
|
|
BOT_TOKEN = os.getenv("BOT_TOKEN")
|
|
API_ID = int(os.getenv("API_ID"))
|
|
API_HASH = os.getenv("API_HASH")
|
|
|
|
if not BOT_TOKEN or not API_ID or not API_HASH:
|
|
raise ValueError("Please configure BOT_TOKEN, API_ID and API_HASH in .env")
|
|
|
|
USER_SESSION = "user_session"
|
|
|
|
SESSION_DIR = os.path.join(os.path.dirname(__file__), "sessions")
|
|
os.makedirs(SESSION_DIR, exist_ok=True)
|
|
|
|
TEMP_DIR = os.path.join(os.path.dirname(__file__), "temp")
|
|
os.makedirs(TEMP_DIR, exist_ok=True)
|
|
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format="%(asctime)s - %(levelname)s - %(message)s"
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
Bot = Client(
|
|
os.path.join(SESSION_DIR, "Thumb-Bot"),
|
|
bot_token=BOT_TOKEN,
|
|
api_id=API_ID,
|
|
api_hash=API_HASH
|
|
)
|
|
|
|
User = Client(
|
|
os.path.join(SESSION_DIR, USER_SESSION),
|
|
api_id=API_ID,
|
|
api_hash=API_HASH
|
|
)
|
|
|
|
|
|
def remove_extension(name: str) -> str:
|
|
return os.path.splitext(name)[0]
|
|
|
|
|
|
def get_video_dimensions(path: str):
|
|
cmd = [
|
|
"ffprobe", "-v", "error",
|
|
"-select_streams", "v:0",
|
|
"-show_entries", "stream=width,height",
|
|
"-of", "json",
|
|
path
|
|
]
|
|
|
|
try:
|
|
result = subprocess.run(
|
|
cmd,
|
|
capture_output=True,
|
|
text=True,
|
|
check=False
|
|
)
|
|
|
|
if not result.stdout:
|
|
return 1280, 720
|
|
|
|
data = json.loads(result.stdout)
|
|
streams = data.get("streams")
|
|
|
|
if not streams:
|
|
return 1280, 720
|
|
|
|
width = streams[0].get("width", 1280)
|
|
height = streams[0].get("height", 720)
|
|
|
|
return int(width), int(height)
|
|
|
|
except Exception:
|
|
return 1280, 720
|
|
|
|
|
|
def get_video_duration(path: str):
|
|
cmd = [
|
|
"ffprobe", "-v", "error",
|
|
"-show_entries", "format=duration",
|
|
"-of", "default=noprint_wrappers=1:nokey=1",
|
|
path
|
|
]
|
|
|
|
try:
|
|
result = subprocess.run(cmd, capture_output=True, text=True)
|
|
return int(float(result.stdout.strip()))
|
|
except:
|
|
return 0
|
|
|
|
async def send_video_safe(
|
|
client,
|
|
chat_id,
|
|
video_path,
|
|
caption=None,
|
|
thumb=None
|
|
):
|
|
width, height = get_video_dimensions(video_path)
|
|
duration = get_video_duration(video_path)
|
|
|
|
while True:
|
|
try:
|
|
await client.send_video(
|
|
chat_id=chat_id,
|
|
video=video_path,
|
|
caption=caption,
|
|
thumb=thumb,
|
|
width=width,
|
|
height=height,
|
|
duration=duration,
|
|
supports_streaming=True
|
|
)
|
|
break
|
|
|
|
except FloodWait as e:
|
|
logger.warning(
|
|
f"FloodWait while uploading {os.path.basename(video_path)}. "
|
|
f"Sleeping {e.value + 1} seconds..."
|
|
)
|
|
await asyncio.sleep(e.value + 1)
|
|
|
|
@Bot.on_message(filters.command("start"))
|
|
async def start(_, m):
|
|
await m.reply(
|
|
"Video uploader bot ready.\n\n"
|
|
"Commands:\n"
|
|
"/send_video - Upload videos from single folder\n"
|
|
"/batch - Upload videos from batch folders"
|
|
)
|
|
|
|
|
|
@Bot.on_message(filters.command("send_video"))
|
|
async def send_local(_, m):
|
|
|
|
status = await m.reply("Scanning local videos...")
|
|
|
|
videos, _ = get_local_videos()
|
|
|
|
if not videos:
|
|
await status.edit("No videos found.")
|
|
return
|
|
|
|
for v in videos:
|
|
|
|
msg = await m.reply(f"Uploading {v['filename']}...")
|
|
|
|
thumb = None
|
|
if v["thumb_path"]:
|
|
thumb = process_local_thumbnail(v["thumb_path"])
|
|
|
|
await send_video_safe(
|
|
User,
|
|
m.chat.id,
|
|
v["video_path"],
|
|
caption=remove_extension(v["filename"]),
|
|
thumb=thumb
|
|
)
|
|
|
|
await msg.delete()
|
|
|
|
if thumb and os.path.exists(thumb):
|
|
os.remove(thumb)
|
|
|
|
await status.edit("All videos uploaded.")
|
|
|
|
|
|
@Bot.on_message(filters.command("batch"))
|
|
async def batch(_, m):
|
|
|
|
status = await m.reply("Scanning batch folders...")
|
|
|
|
batches = get_batch_directories()
|
|
|
|
if not batches:
|
|
await status.edit("No batch folders found.")
|
|
return
|
|
|
|
for batch_dir in batches:
|
|
|
|
videos = get_batch_videos(batch_dir)
|
|
|
|
if not videos:
|
|
continue
|
|
|
|
thumb = None
|
|
|
|
if videos[0]["thumb_path"]:
|
|
thumb = process_local_thumbnail(videos[0]["thumb_path"])
|
|
|
|
for v in videos:
|
|
|
|
msg = await m.reply(f"Uploading {v['filename']}...")
|
|
|
|
await send_video_safe(
|
|
User,
|
|
m.chat.id,
|
|
v["video_path"],
|
|
caption=remove_extension(v["filename"]),
|
|
thumb=thumb
|
|
)
|
|
|
|
await msg.delete()
|
|
|
|
if thumb and os.path.exists(thumb):
|
|
os.remove(thumb)
|
|
|
|
await status.edit("Batch upload complete.")
|
|
|
|
|
|
print("Bot started successfully")
|
|
|
|
with User:
|
|
Bot.run() |