canina/frontend/application/lib/media.ts
parsa aghaei fa1a35c835
Some checks failed
Deploy Canina / deploy (push) Successful in 1m34s
E2E Playwright Tests / Run Full E2E & Security Suites (push) Failing after 6s
feat(media): implement nextjs media proxy API routes (/api/uploads & /api/media) with server-side caching and streaming
2026-08-29 12:13:16 +03:30

52 lines
1.8 KiB
TypeScript

/**
* Normalizes any media/upload URL to use the local frontend Next.js media proxy (/api/uploads/...)
* instead of directly exposing or calling backend domains (api.canina.ir, etc.).
*
* Benefits:
* 1. Leverages Next.js server caching and optimization.
* 2. Hides internal backend URLs and avoids ugly direct backend domain calls.
* 3. Supports HTTP Range requests for seamless video/audio seeking and streaming.
*/
export function getMediaUrl(url?: string | null): string {
if (!url) return '';
const trimmed = url.trim();
if (!trimmed) return '';
// Data URLs or blob URLs stay as-is
if (trimmed.startsWith('data:') || trimmed.startsWith('blob:')) {
return trimmed;
}
// If already proxied via /api/uploads/ or /api/media/
if (trimmed.startsWith('/api/uploads/') || trimmed.startsWith('/api/media/')) {
return trimmed;
}
// If relative path starting with /uploads/
if (trimmed.startsWith('/uploads/')) {
return `/api/uploads/${trimmed.replace(/^\/uploads\//, '')}`;
}
// If relative path starting with uploads/
if (trimmed.startsWith('uploads/')) {
return `/api/uploads/${trimmed.replace(/^uploads\//, '')}`;
}
// If relative path starting with /media/ or media/
if (trimmed.startsWith('/media/')) {
return `/api/uploads/${trimmed.replace(/^\/media\//, '')}`;
}
if (trimmed.startsWith('media/')) {
return `/api/uploads/${trimmed.replace(/^media\//, '')}`;
}
// If full backend URL containing /uploads/ (e.g. http://localhost:4001/uploads/..., https://api.canina.ir/uploads/...)
const uploadsMatch = trimmed.match(/^https?:\/\/[^/]+\/uploads\/(.+)$/i);
if (uploadsMatch && uploadsMatch[1]) {
return `/api/uploads/${uploadsMatch[1]}`;
}
// External URLs (like unsplash, cdn, youtube, aparat) stay as-is
return trimmed;
}