import type { Helpers, Task } from "graphile-worker" import { configs } from "../config" import type { Stream } from '@futureporn/types' import createVod from "../fetchers/createVod" import getVod from "../fetchers/getVod" interface Payload { vod_id: 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") throw new Error("payload.vod_id was not a string"); } /** * * # process_video * * We just recorded a livestream. Now what? * process_video takes a /vods record and runs a bunch of processes to get it ready for publishing. * * The following are graphile-worker tasks which process_video is responsible for adding to the job queue. * Some of these tasks are run conditionally based on the structure of the /vods record. * For example, combine_video_segments is only useful on a vod recording which ended up with multiple segments. * * - combine_video_segments * - remux_video * - generate_thumbnail * - queue_moderator_review * - create_mux_asset * - create_torrent * * Some of the above Tasks are dependent on others. generate_thumbnail and everything following it depends on combine_video_segments. * graphile-worker doesn't have support for dependent tasks, * thus our solution is to invoke ALL the above jobs immediately, and build those jobs to fail if pre-conditions are unmet. * all listed jobs are also idempotent, which means if they don't need to run (previously already performed their tasks), they will exit without doing anything. * */ const process_video: Task = async function (payload: unknown, helpers: Helpers) { assertPayload(payload) const { vod_id } = payload helpers.logger.info(`process_video task has begun for vod_id=${vod_id}`) const vod = await getVod(vod_id, helpers) if (!vod) throw new Error(`failed to get vod from database.`); if (!vod.segments) throw new Error(`vod ${vod_id} fetched from database lacked any segments.`); const isCombinationNeeded = (vod.segments.length > 1) if (isCombinationNeeded) { const s3_manifest = vod.segments.map((segment) => ({ key: segment.s3_key, bytes: segment.bytes })) helpers.logger.info(`There are ${vod.segments.length} segments; Concatenation is needed.`) helpers.addJob('combine_video_segments', { s3_manifest, vod_id }) } else { helpers.addJob('remux_video', { vod_id }) } helpers.addJob('generate_thumbnail', { vod_id }) // helpers.addJob('queue_moderator_review', { }) // helpers.addJob('create_mux_asset', { }) // helpers.addJob('create_torrent', { }) // helpers.addJob('create_ipfs', { }) } export default process_video;