feat: implement downloading and processing of Kick and Twitch URLs
This commit is contained in:
+4
-4
@@ -473,7 +473,7 @@ def download_youtube_video(url, output_dir="."):
|
||||
import time
|
||||
import sys
|
||||
|
||||
print("📥 Downloading video from YouTube using custom solver...")
|
||||
print("📥 Downloading video using custom solver...")
|
||||
step_start_time = time.time()
|
||||
|
||||
# Ensure output_dir is absolute path
|
||||
@@ -492,14 +492,14 @@ def download_youtube_video(url, output_dir="."):
|
||||
result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||
|
||||
if result.returncode != 0:
|
||||
print("🚨 YOUTUBE DOWNLOAD ERROR 🚨", file=sys.stderr)
|
||||
print("🚨 DOWNLOAD ERROR 🚨", file=sys.stderr)
|
||||
print(result.stderr, file=sys.stderr)
|
||||
raise Exception(f"YouTube download failed: {result.stderr}")
|
||||
raise Exception(f"Video download failed: {result.stderr}")
|
||||
|
||||
try:
|
||||
output_data = json.loads(result.stdout.strip())
|
||||
downloaded_file = output_data['filepath']
|
||||
video_title = output_data.get('title', 'youtube_video')
|
||||
video_title = output_data.get('title', 'video')
|
||||
sanitized_title = sanitize_filename(video_title)
|
||||
except Exception as e:
|
||||
print(f"⚠️ JSON parsing failed, trying fallback detection. Error: {e}")
|
||||
|
||||
+37
-10
@@ -113,7 +113,7 @@ async def status(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
elif qsize > 0:
|
||||
await update.message.reply_text(f"⏳ {qsize} videos en cola, iniciando pronto...")
|
||||
else:
|
||||
await update.message.reply_text("💤 Sin actividad. Mandame un link de YouTube.")
|
||||
await update.message.reply_text("💤 Sin actividad. Mandame un link de YouTube, Twitch o Kick.")
|
||||
|
||||
|
||||
async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
@@ -125,9 +125,9 @@ async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
log.warning(f" Ignoring unauthorized chat_id={chat_id}")
|
||||
return
|
||||
|
||||
if not re.search(r"(youtube\.com|youtu\.be)", text):
|
||||
log.info(" Not a YouTube URL, ignoring.")
|
||||
await update.message.reply_text("❌ Mandame un link de YouTube (youtube.com o youtu.be).")
|
||||
if not re.search(r"(youtube\.com|youtu\.be|twitch\.tv|kick\.com)", text):
|
||||
log.info(" Not a YouTube, Twitch or Kick URL, ignoring.")
|
||||
await update.message.reply_text("❌ Mandame un link de YouTube, Twitch o Kick.")
|
||||
return
|
||||
|
||||
qsize = queue.qsize()
|
||||
@@ -206,10 +206,37 @@ async def process_queue(bot):
|
||||
log.info(f"[queue] Job done. Queue size now: {queue.qsize()}")
|
||||
|
||||
|
||||
def get_yt_id(url: str) -> str:
|
||||
"""Extract YouTube video ID from URL."""
|
||||
match = re.search(r"(?:v=|\/shorts\/|\/embed\/|\/v\/|youtu\.be\/)([a-zA-Z0-9_-]{11})", url)
|
||||
return match.group(1) if match else "unknown"
|
||||
def get_video_id(url: str) -> str:
|
||||
"""Extract unique video ID from YouTube, Twitch, or Kick URL."""
|
||||
# 1. YouTube
|
||||
yt_match = re.search(r"(?:v=|\/shorts\/|\/embed\/|\/v\/|youtu\.be\/)([a-zA-Z0-9_-]{11})", url)
|
||||
if yt_match:
|
||||
return yt_match.group(1)
|
||||
|
||||
# 2. Twitch VODs
|
||||
twitch_vod_match = re.search(r"twitch\.tv\/videos\/(\d+)", url)
|
||||
if twitch_vod_match:
|
||||
return f"twitch_vod_{twitch_vod_match.group(1)}"
|
||||
|
||||
# 3. Twitch Clips
|
||||
twitch_clip_match = re.search(r"(?:clips\.twitch\.tv\/|twitch\.tv\/\w+\/clip\/)([a-zA-Z0-9_-]+)", url)
|
||||
if twitch_clip_match:
|
||||
return f"twitch_clip_{twitch_clip_match.group(1)}"
|
||||
|
||||
# 4. Kick VODs (contains UUID)
|
||||
kick_vod_match = re.search(r"kick\.com\/(?:video\/|(?:\w+\/videos\/))([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})", url)
|
||||
if kick_vod_match:
|
||||
return f"kick_vod_{kick_vod_match.group(1)}"
|
||||
|
||||
# 5. Kick Clips
|
||||
kick_clip_match = re.search(r"kick\.com\/\w+\/clips\/([a-zA-Z0-9_-]+)", url)
|
||||
if kick_clip_match:
|
||||
return f"kick_clip_{kick_clip_match.group(1)}"
|
||||
|
||||
# Fallback to md5 hash of URL to ensure uniqueness
|
||||
import hashlib
|
||||
url_hash = hashlib.md5(url.encode('utf-8')).hexdigest()[:10]
|
||||
return f"video_{url_hash}"
|
||||
|
||||
|
||||
# ─── Main video processor ─────────────────────────────────────────────────────
|
||||
@@ -218,7 +245,7 @@ async def process_video(bot, url: str):
|
||||
log.info(f"[process] URL: {url}")
|
||||
|
||||
# 1. Extract video ID and Get title
|
||||
yt_id = get_yt_id(url)
|
||||
yt_id = get_video_id(url)
|
||||
title = await get_video_title(url)
|
||||
log.info(f"[process] Video ID: {yt_id}, Title: {title!r}")
|
||||
|
||||
@@ -298,7 +325,7 @@ async def process_video(bot, url: str):
|
||||
log.debug(f"[main.py] {line[:200]}")
|
||||
|
||||
# Parse progress markers from main.py output
|
||||
if "Downloading video from YouTube" in line:
|
||||
if "Downloading video" in line:
|
||||
await edit_msg(
|
||||
f"🎬 *{title[:50] or 'Video'}*\n\n"
|
||||
f"📥 Descargando..."
|
||||
|
||||
Reference in New Issue
Block a user