// Transcript fetching utility import fetch from "node-fetch"; export interface TranscriptFetchResult { success: boolean; content?: string; error?: string; } /** * Fetch transcript content from a URL * @param url The transcript URL * @param username Optional username for authentication * @param password Optional password for authentication * @returns Promise with fetch result */ export async function fetchTranscriptContent( url: string, username?: string, password?: string ): Promise { try { if (!url || !url.trim()) { return { success: false, error: "No transcript URL provided", }; } // Prepare authentication header if credentials provided const authHeader = username && password ? "Basic " + Buffer.from(`${username}:${password}`).toString("base64") : undefined; const headers: Record = { "User-Agent": "LiveDash-Transcript-Fetcher/1.0", }; if (authHeader) { headers.Authorization = authHeader; } // Fetch the transcript with timeout const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 30000); // 30 second timeout const response = await fetch(url, { method: "GET", headers, signal: controller.signal, }); clearTimeout(timeoutId); if (!response.ok) { return { success: false, error: `HTTP ${response.status}: ${response.statusText}`, }; } const content = await response.text(); if (!content || content.trim().length === 0) { return { success: false, error: "Empty transcript content", }; } return { success: true, content: content.trim(), }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); // Handle common network errors if (errorMessage.includes("ENOTFOUND")) { return { success: false, error: "Domain not found", }; } if (errorMessage.includes("ECONNREFUSED")) { return { success: false, error: "Connection refused", }; } if (errorMessage.includes("timeout")) { return { success: false, error: "Request timeout", }; } return { success: false, error: errorMessage, }; } } /** * Validate if a URL looks like a valid transcript URL * @param url The URL to validate * @returns boolean indicating if URL appears valid */ export function isValidTranscriptUrl(url: string): boolean { if (!url || typeof url !== "string") { return false; } try { const parsedUrl = new URL(url); return parsedUrl.protocol === "http:" || parsedUrl.protocol === "https:"; } catch { return false; } } /** * Extract session ID from transcript content if possible * This is a helper function that can be enhanced based on transcript format * @param content The transcript content * @returns Extracted session ID or null */ export function extractSessionIdFromTranscript(content: string): string | null { if (!content) return null; // Look for common session ID patterns const patterns = [ /session[_-]?id[:\s]*([a-zA-Z0-9-]+)/i, /id[:\s]*([a-zA-Z0-9-]{8,})/i, /^([a-zA-Z0-9-]{8,})/m, // First line might be session ID ]; for (const pattern of patterns) { const match = content.match(pattern); if (match && match[1]) { return match[1].trim(); } } return null; }