fp/services/factory/src/tasks/generate_thumbnail.ts
CJ_Clippy 140883a69c
Some checks failed
ci / build (push) Failing after 1s
dec 2024 progress
2024-12-11 23:23:46 -08:00

92 lines
3.0 KiB
TypeScript

import type { Task, Helpers } from "graphile-worker";
import getVod from "@futureporn/fetchers/getVod.ts";
import { getStoryboard } from '@futureporn/utils/image.ts'
import { getCdnUrl, uploadFile, type S3FileArgs } from '@futureporn/storage/s3.ts'
import patchVodInDatabase from "@futureporn/fetchers/patchVodInDatabase.ts";
import { configs } from "../config";
interface Payload {
vod_id?: string;
video_url?: string;
}
function assertPayload(payload: any): asserts payload is Payload {
if (typeof payload !== "object" || !payload) throw new Error("invalid payload (it must be an object)");
if (typeof payload.vod_id !== "string" && typeof payload.video_url !== "string") throw new Error("payload requires either vod_id or video_url, however both were not a string.");
}
async function doIntegratedRequest(vodId: string): Promise<void> {
const vod = await getVod(vodId)
const s3_file = vod?.s3_file
if (!s3_file) throw new Error(`vod ${vodId} was missing a s3_file.`);
// we need to get a CDN url to the vod so we can download chunks of the file in order for Prevvy to create the storyboard image.
const cdnUrl = getCdnUrl(configs.s3MainBucket, s3_file.s3_key)
const thumbnailCdnUrl = await getThumbnailCdnUrl(cdnUrl)
await patchVodInDatabase(vodId, { thumbnail: thumbnailCdnUrl })
}
async function getThumbnailCdnUrl(videoUrl: string): Promise<string> {
const tmpImagePath = await getStoryboard(videoUrl)
// we need to upload the image to S3
const uploadArgs: S3FileArgs = {
filePath: tmpImagePath,
s3AccessKeyId: configs.s3AccessKeyId,
s3SecretAccessKey: configs.s3SecretAccessKey,
s3BucketName: configs.s3MainBucket,
s3Endpoint: configs.s3Region,
s3Region: configs.s3Region
}
const upload = await uploadFile(uploadArgs)
if (!upload) throw new Error(`failed to upload ${tmpImagePath} to S3`);
if (!upload.Key) throw new Error(`failed to upload ${tmpImagePath} to S3 (upload.Key was missing)`);
// we need to create a S3 file in the db
const thumbnail = getCdnUrl(configs.s3MainBucket, upload.Key)
return thumbnail
}
async function doSoloRequest(videoUrl: string): Promise<string> {
await getThumbnailCdnUrl(videoUrl)
}
export const generate_thumbnail: Task = async function (payload: unknown, helpers: Helpers) {
assertPayload(payload)
const { vod_id, video_url } = payload
helpers.logger.info(`🏗️ generate_thumbnail started with vod_id=${vod_id}, video_url=${video_url}`);
// Determine what kind of request is being made.
// It could be one of two scenarios
// * Here is a VOD record in the database, please update it's thumbnail. (integratedRequest)
// * Here is a video URL, please give us a thumbnail URL. (soloRequest)
//
const integratedRequest = (!!vod_id && !video_url)
const soloRequest = (!!video_url && !vod_id)
if (integratedRequest) {
await doIntegratedRequest(vod_id)
} else if (soloRequest) {
await getThumbnailCdnUrl(video_url)
} else {
throw new Error(`unsupported ambiguous request!`)
}
}
export default generate_thumbnail