import type { APIRoute } from 'astro'; import { extractionCache, CACHE_TTL } from '../../lib/cache'; const USER_AGENTS = [ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' ]; export const POST: APIRoute = async ({ request }) => { try { const { url, format } = await request.json(); if (!url) { return new Response(JSON.stringify({ error: 'Subtitle URL is required' }), { status: 400 }); } // Check cache const cacheKey = `transcript-content-${url}-${format}`; if (extractionCache.has(cacheKey)) { const cached = extractionCache.get(cacheKey); if (Date.now() - cached.timestamp < CACHE_TTL) { return new Response(JSON.stringify(cached.data), { status: 200, headers: { 'Content-Type': 'application/json', 'X-Cache': 'HIT' } }); } } const ua = USER_AGENTS[Math.floor(Math.random() * USER_AGENTS.length)]; const response = await fetch(url, { headers: { 'User-Agent': ua, 'Accept': '*/*', 'Accept-Language': 'en-US,en;q=0.9', 'Referer': 'https://www.youtube.com/', 'Origin': 'https://www.youtube.com' } }); if (response.status === 429) { return new Response(JSON.stringify({ error: 'YouTube is rate-limiting transcript extraction. Please try again in a few minutes or try a different video.' }), { status: 429 }); } if (!response.ok) { throw new Error(`Failed to fetch subtitle: ${response.statusText} (${response.status})`); } let content = await response.text(); if (format === 'plain') { try { const json = JSON.parse(content); if (json.events) { content = json.events .map((e: any) => e.segs ? e.segs.map((s: any) => s.utf8).join('') : '') .filter((t: string) => t.trim().length > 0) .join(' ') .replace(/\s+/g, ' '); } } catch (e) { // If it's not JSON (e.g. VTT/SRT), try a simple regex strip content = content .replace(/WEBVTT/g, '') .replace(/\d{2}:\d{2}:\d{2}\.\d{3} --> \d{2}:\d{2}:\d{2}\.\d{3}/g, '') .replace(/<[^>]*>/g, '') .replace(/^\d+$/gm, '') .replace(/\n+/g, ' ') .trim(); } } const responseData = { content }; extractionCache.set(cacheKey, { timestamp: Date.now(), data: responseData }); return new Response(JSON.stringify(responseData), { status: 200, headers: { 'Content-Type': 'application/json' } }); } catch (error: any) { return new Response(JSON.stringify({ error: error.message }), { status: 500 }); } };