"use server"; import { auth } from "@/lib/auth"; import { headers } from "next/headers"; import { ShowcaseService } from "../services/showcase.service"; import { SocialIngestService } from "../../discovery/services/social-ingest.service"; export async function quickAddVideoAction(formData: FormData) { const session = await auth.api.getSession({ headers: await headers() }); // For public showcase, we allow anonymous ingestion const userId = session?.user?.id || null; const url = formData.get("url") as string; if (!url) return { success: false, error: "URL is required" }; const platform = SocialIngestService.detectPlatform(url); if (!platform) { return { success: false, error: "Unsupported platform. Supported: YouTube, TikTok, Instagram, Facebook" }; } let videoId: string | null = null; if (platform === 'youtube') { const videoIdMatch = url.match(/(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/); videoId = videoIdMatch ? videoIdMatch[1] : null; } else if (platform === 'tiktok') { const match = url.match(/\/video\/(\d+)/); const rawId = match ? match[1] : `${Date.now()}`; videoId = rawId.startsWith('tt-') ? rawId : `tt-${rawId}`; } else if (platform === 'instagram') { const match = url.match(/\/(?:p|reels|reel)\/([A-Za-z0-9_-]+)/); const rawId = match ? match[1] : `${Date.now()}`; videoId = rawId.startsWith('ig-') ? rawId : `ig-${rawId}`; } else if (platform === 'facebook') { const match = url.match(/[?&]v=([^&]+)/) || url.match(/\/share\/v\/([^/?]+)/) || url.match(/\/reel\/([^/?]+)/); const rawId = match ? match[1] : `${Date.now()}`; videoId = rawId.startsWith('fb-') ? rawId : `fb-${rawId}`; } else { videoId = `${platform}-${Date.now()}`; } if (!videoId) { return { success: false, error: `Could not parse video ID from ${platform} URL` }; } console.log(`[quickAddVideoAction] Ingesting: ${platform} | ID: ${videoId}`); try { const result = await ShowcaseService.ingestAndAnalyze(videoId, userId, { skipAnalysis: true, platform: platform, url: url, isInWorkbench: false // Preview mode: Don't add to dashboard yet }); if (result.success) { return { success: true, videoId }; } return { success: false, error: result.error || "Failed to process video. The link might be private or restricted." }; } catch (err) { console.error(`[quickAddVideoAction] Exception:`, err); return { success: false, error: "An unexpected error occurred. Please try again with a different link." }; } } export async function checkCommunityVaultsAction(url: string) { if (!url) return { success: false, error: "URL is required" }; const platform = SocialIngestService.detectPlatform(url); if (!platform) return { success: false, error: "Unsupported platform" }; let videoId: string | null = null; if (platform === 'youtube') { const videoIdMatch = url.match(/(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/); videoId = videoIdMatch ? videoIdMatch[1] : null; } else if (platform === 'tiktok') { const match = url.match(/\/video\/(\d+)/); const rawId = match ? match[1] : null; if (rawId) videoId = rawId.startsWith('tt-') ? rawId : `tt-${rawId}`; } else if (platform === 'instagram') { const match = url.match(/\/(?:p|reels|reel)\/([A-Za-z0-9_-]+)/); const rawId = match ? match[1] : null; if (rawId) videoId = rawId.startsWith('ig-') ? rawId : `ig-${rawId}`; } else if (platform === 'facebook') { const match = url.match(/[?&]v=([^&]+)/) || url.match(/\/share\/v\/([^/?]+)/) || url.match(/\/reel\/([^/?]+)/); const rawId = match ? match[1] : null; if (rawId) videoId = rawId.startsWith('fb-') ? rawId : `fb-${rawId}`; } if (!videoId) return { success: false, error: "Could not parse video ID" }; try { const vaults = await ShowcaseService.getCommunityVaults(videoId); return { success: true, vaults }; } catch (err) { console.error(`[checkCommunityVaultsAction] Error:`, err); return { success: false, error: "Failed to check community vaults" }; } } export async function requestAnalysisNotificationAction(videoId: string, email: string) { const trimmedEmail = email.toLowerCase().trim(); const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(trimmedEmail)) { return { success: false, error: "Invalid email format" }; } // Reuse encryption logic pattern const hash = crypto.createHash('sha256').update(trimmedEmail).digest('hex'); const encryptionKey = process.env.ENCRYPTION_KEY || ""; if (!encryptionKey || encryptionKey.length !== 64) { return { success: false, error: "Server configuration error" }; } const iv = crypto.randomBytes(16); const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(encryptionKey, 'hex'), iv); let encrypted = cipher.update(trimmedEmail, 'utf8', 'hex'); encrypted += cipher.final('hex'); const emailEncrypted = iv.toString('hex') + ':' + encrypted; try { // Find internal video ID const video = await db.query.youtubeVideos.findFirst({ where: eq(youtubeVideos.videoId, videoId) }); if (!video) return { success: false, error: "Video not found" }; await db.insert(analysisNotifications).values({ videoId: video.id, emailHash: hash, emailEncrypted: emailEncrypted, status: 'PENDING' }); return { success: true }; } catch (err) { console.error("[requestAnalysisNotificationAction] Error:", err); return { success: false, error: "Failed to register notification" }; } } import crypto from "crypto"; import { db } from "@/lib/db"; import { youtubeVideos, analysisNotifications } from "@/lib/db/schema"; import { eq } from "drizzle-orm";