文件
tennis-training-hub/server/mediaService.ts
2026-03-15 17:30:19 +08:00

68 行
1.8 KiB
TypeScript

import { ENV } from "./_core/env";
import { fetchWithTimeout } from "./_core/fetch";
export type RemoteMediaSession = {
id: string;
userId: string;
title: string;
archiveStatus: "idle" | "queued" | "processing" | "completed" | "failed";
previewStatus?: "idle" | "processing" | "ready" | "failed";
previewSegments?: number;
markers?: Array<{
id: string;
type: string;
label: string;
timestampMs: number;
confidence?: number;
createdAt: string;
}>;
playback: {
webmUrl?: string;
mp4Url?: string;
webmSize?: number;
mp4Size?: number;
ready: boolean;
previewUrl?: string;
};
lastError?: string;
};
function getMediaBaseUrl() {
if (!ENV.mediaServiceUrl) {
throw new Error("MEDIA_SERVICE_URL is not configured");
}
return ENV.mediaServiceUrl.replace(/\/+$/, "");
}
function getMediaCandidateUrls(path: string) {
const baseUrl = getMediaBaseUrl();
if (baseUrl.endsWith("/media")) {
return [`${baseUrl}${path}`];
}
return [`${baseUrl}${path}`, `${baseUrl}/media${path}`];
}
export async function getRemoteMediaSession(sessionId: string) {
let lastError: Error | null = null;
for (const url of getMediaCandidateUrls(`/sessions/${encodeURIComponent(sessionId)}`)) {
const response = await fetchWithTimeout(url, undefined, {
timeoutMs: ENV.mediaFetchTimeoutMs,
retries: ENV.mediaFetchRetryCount,
retryMethods: ["GET"],
});
if (response.ok) {
const payload = await response.json() as { session: RemoteMediaSession };
return payload.session;
}
const message = await response.text().catch(() => response.statusText);
lastError = new Error(`Media service request failed (${response.status}): ${message}`);
if (response.status !== 404) {
break;
}
}
throw lastError ?? new Error("Media service request failed");
}