Files
UHD_Media_Tool/apps/server/src/modules/subtitles/index.ts
T

67 lines
2.7 KiB
TypeScript

import { Api, type SubtitleApplyRequest, type SubtitleFetchRequest, type SubtitleSource } from "@umt/contracts";
import { ApiException } from "../../http/errors.ts";
import { route } from "../agent/http.ts";
import { sourcesIdentityModule } from "../sources-identity/index.ts";
import type { ServerModule } from "../types.ts";
import { downloadOnline, SubtitleSiteError, searchOnline, subtitleSearchQuery } from "./online/index.ts";
import { applySubtitles, parseSubtitles, subtitleTargets, subtitleWrites, undoSubtitleWrite } from "./service.ts";
/** 补字幕(docs/plan/subtitles.md):上传 / 在线下载的字幕解析、配对、写入、历史与撤销 */
export function createSubtitlesModule(): ServerModule {
return {
name: "subtitles",
registerRoutes(app, ctx) {
const tag = { tag: "subtitles" };
const rt = () => sourcesIdentityModule.runtime(ctx);
const siteErr = async <T>(fn: () => Promise<T>): Promise<T> => {
try {
return await fn();
} catch (e) {
if (e instanceof SubtitleSiteError) throw new ApiException("upstream_unavailable", e.message);
throw e;
}
};
route(app, Api.subtitles.targets, ({ query }) => subtitleTargets(ctx, query.entityId), tag);
route(app, Api.subtitles.parse, ({ body }) => parseSubtitles(ctx, body.files, body.entityId), tag);
route(
app,
Api.subtitles.search,
({ body }) => siteErr(async () => searchOnline(ctx, rt(), await subtitleSearchQuery(ctx, body.entityId, body))),
tag,
);
route(
app,
Api.subtitles.fetch,
({ body }) =>
siteErr(async () => {
const b = body as SubtitleFetchRequest;
const f = await downloadOnline(ctx, rt(), b.siteId, b.ref);
const parsed = await parseSubtitles(ctx, [{ name: f.name, base64: f.base64 }], b.entityId);
// 在线来源:每项带上字幕站与条目地址,写入时记进历史
return {
...parsed,
items: parsed.items.map((it) => ({ ...it, source: f.siteKey as SubtitleSource, sourceRef: f.pageUrl })),
};
}),
tag,
);
route(
app,
Api.subtitles.apply,
({ body, actorId }) => applySubtitles(ctx, body as SubtitleApplyRequest, actorId),
tag,
);
route(
app,
Api.subtitles.writes,
async ({ query }) => ({ items: await subtitleWrites(ctx, query.entityId) }),
tag,
);
route(app, Api.subtitles.undo, ({ params }) => undoSubtitleWrite(ctx, params.id), tag);
},
registerTasks() {},
};
}
export const subtitlesModule = createSubtitlesModule();