68 lines
2.5 KiB
TypeScript
68 lines
2.5 KiB
TypeScript
/**
|
|
* Server-side MinIO presign helper.
|
|
* Calls the scraper API to get presigned URLs, then optionally rewrites
|
|
* the MinIO host to the public-facing URL for browser use.
|
|
*
|
|
* Never import this from client-side code.
|
|
*/
|
|
|
|
import { env } from '$env/dynamic/private';
|
|
import { env as pubEnv } from '$env/dynamic/public';
|
|
|
|
const SCRAPER_URL = env.SCRAPER_API_URL ?? 'http://localhost:8080';
|
|
// Public MinIO URL — used to rewrite presigned URLs so the browser can reach MinIO directly.
|
|
// In docker-compose this would differ from the internal endpoint.
|
|
const MINIO_PUBLIC_URL = pubEnv.PUBLIC_MINIO_PUBLIC_URL ?? 'http://localhost:9000';
|
|
|
|
/**
|
|
* Rewrites the MinIO host in a presigned URL to the public-facing URL.
|
|
* The presigned URL is signed against the internal endpoint (e.g. minio:9000),
|
|
* but the browser needs the public URL (e.g. localhost:9000 in dev, or a CDN in prod).
|
|
* Rewriting the host preserves all query params (signature, expiry, etc).
|
|
*/
|
|
function rewriteHost(presignedUrl: string): string {
|
|
try {
|
|
const u = new URL(presignedUrl);
|
|
const pub = new URL(MINIO_PUBLIC_URL);
|
|
u.protocol = pub.protocol;
|
|
u.hostname = pub.hostname;
|
|
u.port = pub.port;
|
|
return u.toString();
|
|
} catch {
|
|
return presignedUrl;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns a presigned URL for a chapter markdown file.
|
|
* URL is valid for ~15 minutes (set by the scraper).
|
|
* The returned URL points to the public MinIO endpoint and can be used
|
|
* server-side (in a +page.server.ts load function) to fetch the markdown content.
|
|
*/
|
|
export async function presignChapter(slug: string, n: number): Promise<string> {
|
|
const res = await fetch(`${SCRAPER_URL}/api/presign/chapter/${slug}/${n}`);
|
|
if (!res.ok) throw new Error(`presign chapter ${slug}/${n}: ${res.status}`);
|
|
const data = (await res.json()) as { url: string };
|
|
return rewriteHost(data.url);
|
|
}
|
|
|
|
/**
|
|
* Returns a presigned URL for an audio file.
|
|
* URL is valid for ~1 hour. The URL is returned to the browser for direct streaming.
|
|
*/
|
|
export async function presignAudio(
|
|
slug: string,
|
|
n: number,
|
|
voice?: string,
|
|
speed?: number
|
|
): Promise<string> {
|
|
const params = new URLSearchParams();
|
|
if (voice) params.set('voice', voice);
|
|
if (speed) params.set('speed', String(speed));
|
|
const qs = params.toString() ? `?${params.toString()}` : '';
|
|
const res = await fetch(`${SCRAPER_URL}/api/presign/audio/${slug}/${n}${qs}`);
|
|
if (!res.ok) throw new Error(`presign audio ${slug}/${n}: ${res.status}`);
|
|
const data = (await res.json()) as { url: string };
|
|
return rewriteHost(data.url);
|
|
}
|