ytDownloader / Youtube-tool /src /pages /api /transcript-fetch.ts
Anshishere's picture
Upload 16532 files
494fa67 verified
Raw
History Blame Contribute Delete
3.04 kB
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 });
}
};