Files
xsh-assistant-next/composables/useVideoSubtitleEmbedding.ts
2025-02-10 20:39:18 +08:00

80 lines
1.8 KiB
TypeScript

import {
Combinator,
EmbedSubtitlesClip,
MP4Clip,
OffscreenSprite,
} from "@webav/av-cliper";
export interface SubtitleEmbeddingOptions {
color?: string;
textBgColor?: string | null;
type?: "srt";
fontFamily?: string;
fontSize?: number;
letterSpacing?: string | null;
bottomOffset?: number;
strokeStyle?: string;
lineWidth?: number | null;
lineCap?: CanvasLineCap | null;
lineJoin?: CanvasLineJoin | null;
textShadow?: {
offsetX: number;
offsetY: number;
blur: number;
color: string;
};
videoWidth?: number;
videoHeight?: number;
}
export const useVideoSubtitleEmbedding = async (
videoUrl: string,
srtUrl: string,
options?: SubtitleEmbeddingOptions
) => {
if (!options) {
options = {
videoWidth: 1920,
videoHeight: 1080,
};
}
const videoClip = new MP4Clip((await fetch(videoUrl)).body!)
const videoSprite = new OffscreenSprite(videoClip)
videoSprite.time = { duration: videoClip.meta.duration, offset: 0 }
await videoSprite.ready;
const srtSprite = new OffscreenSprite(
new EmbedSubtitlesClip(await(await fetch(srtUrl)).text(), {
videoWidth: 1920,
videoHeight: 1080,
fontSize: 36,
fontFamily: 'Noto Sans SC',
strokeStyle: 'none',
textShadow: {
offsetX: 2,
offsetY: 2,
blur: 6,
color: 'rgba(0, 0, 0, 0.35)',
},
...options,
})
)
await srtSprite.ready;
srtSprite.time = { duration: videoClip.meta.duration, offset: 0 }
const combinator = new Combinator({
width: 1920,
height: 1080,
});
await combinator.addSprite(videoSprite);
await combinator.addSprite(srtSprite);
const srcBlob = URL.createObjectURL(
await new Response(combinator.output()).blob()
);
return srcBlob;
};