use custom logger
Some checks failed
ci / build (push) Failing after 15s
ci / Tests & Checks (push) Failing after 5s

This commit is contained in:
CJ_Clippy 2025-08-15 03:04:52 -08:00
parent f6db07fb97
commit 65b4e2f956
16 changed files with 113 additions and 97 deletions

View File

@ -17,6 +17,17 @@ services:
start_period: 10s start_period: 10s
timeout: 10s timeout: 10s
pgbackweb:
image: 'eduardolat/pgbackweb:latest'
ports:
- '8085:8085'
env_file: ./../../.env.development.local
volumes:
- ${HOME}/.local/share/futureporn/backups:/backups
depends_on:
postgres:
condition: service_healthy
volumes: volumes:
pgdata: pgdata:

View File

@ -1,7 +1,7 @@
{ {
"name": "futureporn", "name": "futureporn",
"private": true, "private": true,
"version": "2.4.5", "version": "2.4.6",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "concurrently npm:dev:serve npm:dev:build npm:dev:worker npm:dev:compose npm:dev:sftp", "dev": "concurrently npm:dev:serve npm:dev:build npm:dev:worker npm:dev:compose npm:dev:sftp",

View File

@ -1,10 +1,11 @@
import type { Task, Helpers } from "graphile-worker"; import type { Task, Helpers } from "graphile-worker";
import { cleanExpiredFiles } from "../utils/cache"; import { cleanExpiredFiles } from "../utils/cache";
import logger from "../utils/logger";
const cleanup: Task = async (_payload, helpers: Helpers) => { const cleanup: Task = async (_payload, helpers: Helpers) => {
helpers.logger.debug(`cleanup begin.`); logger.debug(`cleanup begin.`);
let count = await cleanExpiredFiles() let count = await cleanExpiredFiles()
if (count > 0) helpers.logger.info(`Deleted ${count} old files.`); if (count > 0) logger.info(`Deleted ${count} old files.`);
}; };
export default cleanup; export default cleanup;

View File

@ -226,7 +226,7 @@ async function updateTwitchChannelPointReward(user: User, reward: TwitchChannelP
export default async function consolidate_twitch_channel_rewards(payload: any, helpers: Helpers) { export default async function consolidate_twitch_channel_rewards(payload: any, helpers: Helpers) {
assertPayload(payload); assertPayload(payload);
const { userId } = payload; const { userId } = payload;
// helpers.logger.info(`Hello, ${name}`); // logger.info(`Hello, ${name}`);
const user = await prisma.user.findFirstOrThrow({ const user = await prisma.user.findFirstOrThrow({
where: { where: {
@ -278,8 +278,8 @@ export default async function consolidate_twitch_channel_rewards(payload: any, h
const costMismatched = twitchRewardsData const costMismatched = twitchRewardsData
.filter((r: TwitchChannelPointReward) => isWrongRedeemCost(r, user.redeemCost)); .filter((r: TwitchChannelPointReward) => isWrongRedeemCost(r, user.redeemCost));
helpers.logger.info(`There are ${outOfDate.length} out of date Channel Point Rewards. outOfDate=${JSON.stringify(outOfDate.map((ood) => ({ title: ood.title, cost: ood.cost, id: ood.id })))}`) logger.info(`There are ${outOfDate.length} out of date Channel Point Rewards. outOfDate=${JSON.stringify(outOfDate.map((ood) => ({ title: ood.title, cost: ood.cost, id: ood.id })))}`)
helpers.logger.info(`costMismatched=${JSON.stringify(costMismatched)}`) logger.info(`costMismatched=${JSON.stringify(costMismatched)}`)
// * make the REST request(s) to get the twitch channel point rewards up-to-date // * make the REST request(s) to get the twitch channel point rewards up-to-date
for (const reward of outOfDate) { for (const reward of outOfDate) {

View File

@ -69,37 +69,37 @@ async function preparePython(helpers) {
try { try {
pythonCmd = which.sync("python3"); pythonCmd = which.sync("python3");
} catch { } catch {
helpers.logger.error("Python is not installed or not in PATH."); logger.error("Python is not installed or not in PATH.");
throw new Error("Python not found in PATH."); throw new Error("Python not found in PATH.");
} }
// If venv doesn't exist, create it // If venv doesn't exist, create it
if (!existsSync(venvPath)) { if (!existsSync(venvPath)) {
helpers.logger.info("Python venv not found. Creating one..."); logger.info("Python venv not found. Creating one...");
try { try {
await spawn(pythonCmd, ["-m", "venv", "venv"], { await spawn(pythonCmd, ["-m", "venv", "venv"], {
cwd: env.VIBEUI_DIR, cwd: env.VIBEUI_DIR,
}); });
helpers.logger.info("Python venv successfully created."); logger.info("Python venv successfully created.");
} catch (err) { } catch (err) {
helpers.logger.error("Failed to create Python venv:", err); logger.error("Failed to create Python venv:", err);
// Clean up partially created venv if needed // Clean up partially created venv if needed
try { try {
if (existsSync(venvPath)) { if (existsSync(venvPath)) {
rmSync(venvPath, { recursive: true, force: true }); rmSync(venvPath, { recursive: true, force: true });
helpers.logger.warn("Removed broken venv directory."); logger.warn("Removed broken venv directory.");
} }
} catch (cleanupErr) { } catch (cleanupErr) {
helpers.logger.error("Error while cleaning up broken venv:", cleanupErr); logger.error("Error while cleaning up broken venv:", cleanupErr);
} }
throw new Error("Python venv creation failed. Check if python3 and python3-venv are installed."); throw new Error("Python venv creation failed. Check if python3 and python3-venv are installed.");
} }
} else { } else {
helpers.logger.info("Using existing Python venv."); logger.info("Using existing Python venv.");
} }
} }
@ -137,7 +137,7 @@ export async function buildFunscript(
const labelDir = join(predictionOutput, 'labels'); const labelDir = join(predictionOutput, 'labels');
const yamlPath = join(predictionOutput, 'data.yaml'); const yamlPath = join(predictionOutput, 'data.yaml');
const outputPath = join(process.env.CACHE_ROOT ?? '/tmp', `${nanoid()}.funscript`); const outputPath = join(process.env.CACHE_ROOT ?? '/tmp', `${nanoid()}.funscript`);
helpers.logger.info('Starting Funscript generation'); logger.info('Starting Funscript generation');
try { try {
@ -151,7 +151,7 @@ export async function buildFunscript(
return outputPath; return outputPath;
} catch (error) { } catch (error) {
helpers.logger.error(`Error generating Funscript: ${error instanceof Error ? error.message : 'Unknown error'}`); logger.error(`Error generating Funscript: ${error instanceof Error ? error.message : 'Unknown error'}`);
throw error; throw error;
} }
} }
@ -225,19 +225,19 @@ async function loadClassPositionMap(data: DataYaml, helpers: Helpers): Promise<C
const names = Object.values(data.names); const names = Object.values(data.names);
for (const name of names) { for (const name of names) {
if (typeof name !== 'string' || name.trim() === '') { if (typeof name !== 'string' || name.trim() === '') {
helpers.logger.info(`Skipping invalid class name: ${name}`); logger.info(`Skipping invalid class name: ${name}`);
continue; continue;
} }
if (!(name in positionMap)) { if (!(name in positionMap)) {
helpers.logger.info(`No position mapping for class "${name}", defaulting to 0`); logger.info(`No position mapping for class "${name}", defaulting to 0`);
positionMap[name] = 0; positionMap[name] = 0;
} }
} }
helpers.logger.info(`Loaded class position map: ${JSON.stringify(positionMap)}`); logger.info(`Loaded class position map: ${JSON.stringify(positionMap)}`);
return positionMap; return positionMap;
} catch (error) { } catch (error) {
helpers.logger.error(`Error loading data.yaml: ${error instanceof Error ? error.message : 'Unknown error'}`); logger.error(`Error loading data.yaml: ${error instanceof Error ? error.message : 'Unknown error'}`);
throw error; throw error;
} }
} }
@ -276,7 +276,7 @@ function generatePatternPositions(startMs: number, durationMs: number, className
async function loadVideoMetadata(videoPath: string, helpers: Helpers) { async function loadVideoMetadata(videoPath: string, helpers: Helpers) {
const { fps, frames: totalFrames } = await ffprobe(videoPath); const { fps, frames: totalFrames } = await ffprobe(videoPath);
helpers.logger.info(`Video metadata: fps=${fps}, frames=${totalFrames}`); logger.info(`Video metadata: fps=${fps}, frames=${totalFrames}`);
return { fps, totalFrames }; return { fps, totalFrames };
} }
@ -288,12 +288,12 @@ async function processLabelFiles(labelDir: string, helpers: Helpers, data: DataY
for (const file of labelFiles) { for (const file of labelFiles) {
const match = file.match(/(\d+)\.txt$/); const match = file.match(/(\d+)\.txt$/);
if (!match) { if (!match) {
helpers.logger.info(`Skipping invalid filename: ${file}`); logger.info(`Skipping invalid filename: ${file}`);
continue; continue;
} }
const frameIndex = parseInt(match[1], 10); const frameIndex = parseInt(match[1], 10);
if (isNaN(frameIndex)) { if (isNaN(frameIndex)) {
helpers.logger.info(`Skipping invalid frame index from filename: ${file}`); logger.info(`Skipping invalid frame index from filename: ${file}`);
continue; continue;
} }
@ -397,7 +397,7 @@ function generateActions(totalDurationMs: number, fps: number, detectionSegments
async function writeFunscript(outputPath: string, actions: FunscriptAction[], helpers: Helpers) { async function writeFunscript(outputPath: string, actions: FunscriptAction[], helpers: Helpers) {
const funscript: Funscript = { version: '1.0', actions }; const funscript: Funscript = { version: '1.0', actions };
await writeFile(outputPath, JSON.stringify(funscript, null, 2)); await writeFile(outputPath, JSON.stringify(funscript, null, 2));
helpers.logger.info(`Funscript generated: ${outputPath} (${actions.length} actions)`); logger.info(`Funscript generated: ${outputPath} (${actions.length} actions)`);
} }
@ -411,13 +411,13 @@ const createFunscript: Task = async (payload: any, helpers: Helpers) => {
await preparePython(helpers) await preparePython(helpers)
if (vod.funscript) { if (vod.funscript) {
helpers.logger.info(`Doing nothing-- vod ${vodId} already has a funscript.`); logger.info(`Doing nothing-- vod ${vodId} already has a funscript.`);
return; return;
} }
if (!vod.sourceVideo) { if (!vod.sourceVideo) {
const msg = `Cannot create funscript: Vod ${vodId} is missing a source video.`; const msg = `Cannot create funscript: Vod ${vodId} is missing a source video.`;
helpers.logger.warn(msg); logger.warn(msg);
throw new Error(msg); throw new Error(msg);
} }
@ -425,12 +425,12 @@ const createFunscript: Task = async (payload: any, helpers: Helpers) => {
const s3Client = getS3Client(); const s3Client = getS3Client();
const videoFilePath = await getOrDownloadAsset(s3Client, env.S3_BUCKET, vod.sourceVideo); const videoFilePath = await getOrDownloadAsset(s3Client, env.S3_BUCKET, vod.sourceVideo);
helpers.logger.info(`Downloaded video to ${videoFilePath}`); logger.info(`Downloaded video to ${videoFilePath}`);
helpers.logger.info(`Creating funscript for vod ${vodId}...`); logger.info(`Creating funscript for vod ${vodId}...`);
const predictionOutput = await inference(helpers, videoFilePath); const predictionOutput = await inference(helpers, videoFilePath);
helpers.logger.info(`prediction output ${predictionOutput}`); logger.info(`prediction output ${predictionOutput}`);
const funscriptFilePath = await buildFunscript(helpers, predictionOutput, videoFilePath) const funscriptFilePath = await buildFunscript(helpers, predictionOutput, videoFilePath)
@ -439,14 +439,14 @@ const createFunscript: Task = async (payload: any, helpers: Helpers) => {
const s3Key = `funscripts/${vodId}.funscript`; const s3Key = `funscripts/${vodId}.funscript`;
const s3Url = await uploadFile(s3Client, env.S3_BUCKET, s3Key, funscriptFilePath, "application/json"); const s3Url = await uploadFile(s3Client, env.S3_BUCKET, s3Key, funscriptFilePath, "application/json");
helpers.logger.info(`Uploaded funscript to S3: ${s3Url}`); logger.info(`Uploaded funscript to S3: ${s3Url}`);
await prisma.vod.update({ await prisma.vod.update({
where: { id: vodId }, where: { id: vodId },
data: { funscript: s3Key } data: { funscript: s3Key }
}); });
helpers.logger.info(`Funscript saved to database for vod ${vodId}`); logger.info(`Funscript saved to database for vod ${vodId}`);
}; };
export default createFunscript; export default createFunscript;

View File

@ -7,7 +7,7 @@ import { getS3Client, uploadFile } from "../utils/s3";
import { inference } from "../utils/vibeui"; import { inference } from "../utils/vibeui";
import { preparePython } from "../utils/python"; import { preparePython } from "../utils/python";
import { buildFunscript } from "../utils/funscripts"; import { buildFunscript } from "../utils/funscripts";
import logger from "../utils/logger";
interface Payload { interface Payload {
vodId: string; vodId: string;
@ -37,13 +37,13 @@ const createFunscript: Task = async (payload: any, helpers: Helpers) => {
await preparePython() await preparePython()
if (vod.funscript) { if (vod.funscript) {
helpers.logger.info(`Doing nothing-- vod ${vodId} already has a funscript.`); logger.info(`Doing nothing-- vod ${vodId} already has a funscript.`);
return; return;
} }
if (!vod.sourceVideo) { if (!vod.sourceVideo) {
const msg = `Cannot create funscript: Vod ${vodId} is missing a source video.`; const msg = `Cannot create funscript: Vod ${vodId} is missing a source video.`;
helpers.logger.warn(msg); logger.warn(msg);
throw new Error(msg); throw new Error(msg);
} }
@ -51,12 +51,12 @@ const createFunscript: Task = async (payload: any, helpers: Helpers) => {
const s3Client = getS3Client(); const s3Client = getS3Client();
const videoFilePath = await getOrDownloadAsset(s3Client, env.S3_BUCKET, vod.sourceVideo); const videoFilePath = await getOrDownloadAsset(s3Client, env.S3_BUCKET, vod.sourceVideo);
helpers.logger.info(`Downloaded video to ${videoFilePath}`); logger.info(`Downloaded video to ${videoFilePath}`);
helpers.logger.info(`Creating funscript for vod ${vodId}...`); logger.info(`Creating funscript for vod ${vodId}...`);
const predictionOutputPath = await inference(videoFilePath); const predictionOutputPath = await inference(videoFilePath);
helpers.logger.info(`prediction output ${predictionOutputPath}`); logger.info(`prediction output ${predictionOutputPath}`);
const funscriptFilePath = await buildFunscript(predictionOutputPath, videoFilePath) const funscriptFilePath = await buildFunscript(predictionOutputPath, videoFilePath)
@ -65,14 +65,14 @@ const createFunscript: Task = async (payload: any, helpers: Helpers) => {
const s3Key = `funscripts/${vodId}.funscript`; const s3Key = `funscripts/${vodId}.funscript`;
const s3Url = await uploadFile(s3Client, env.S3_BUCKET, s3Key, funscriptFilePath, "application/json"); const s3Url = await uploadFile(s3Client, env.S3_BUCKET, s3Key, funscriptFilePath, "application/json");
helpers.logger.info(`Uploaded funscript to S3: ${s3Url}`); logger.info(`Uploaded funscript to S3: ${s3Url}`);
await prisma.vod.update({ await prisma.vod.update({
where: { id: vodId }, where: { id: vodId },
data: { funscript: s3Key } data: { funscript: s3Key }
}); });
helpers.logger.info(`Funscript saved to database for vod ${vodId}`); logger.info(`Funscript saved to database for vod ${vodId}`);
}; };
export default createFunscript; export default createFunscript;

View File

@ -33,13 +33,13 @@ const createFunscript: Task = async (payload: any, helpers: Helpers) => {
const vod = await prisma.vod.findFirstOrThrow({ where: { id: vodId } }); const vod = await prisma.vod.findFirstOrThrow({ where: { id: vodId } });
if (vod.funscript) { if (vod.funscript) {
helpers.logger.info(`Doing nothing-- vod ${vodId} already has a funscript.`); logger.info(`Doing nothing-- vod ${vodId} already has a funscript.`);
return; return;
} }
if (!vod.sourceVideo) { if (!vod.sourceVideo) {
const msg = `Cannot create funscript: Vod ${vodId} is missing a source video.`; const msg = `Cannot create funscript: Vod ${vodId} is missing a source video.`;
helpers.logger.warn(msg); logger.warn(msg);
throw new Error(msg); throw new Error(msg);
} }
@ -47,13 +47,13 @@ const createFunscript: Task = async (payload: any, helpers: Helpers) => {
const s3Client = getS3Client(); const s3Client = getS3Client();
const videoFilePath = await getOrDownloadAsset(s3Client, env.S3_BUCKET, vod.sourceVideo); const videoFilePath = await getOrDownloadAsset(s3Client, env.S3_BUCKET, vod.sourceVideo);
helpers.logger.info(`Downloaded video to ${videoFilePath}`); logger.info(`Downloaded video to ${videoFilePath}`);
helpers.logger.info(`Creating funscript for vod ${vodId}...`); logger.info(`Creating funscript for vod ${vodId}...`);
const modelPath = join(env.VIBEUI_DIR, 'vibeui.onnx') const modelPath = join(env.VIBEUI_DIR, 'vibeui.onnx')
const predictionOutput = await vibeuiInference(modelPath, videoFilePath); const predictionOutput = await vibeuiInference(modelPath, videoFilePath);
helpers.logger.info(`prediction output ${predictionOutput}`); logger.info(`prediction output ${predictionOutput}`);
const classes = await getModelClasses(modelPath) const classes = await getModelClasses(modelPath)
const funscriptFilePath = await buildFunscript(classes, predictionOutput, videoFilePath) const funscriptFilePath = await buildFunscript(classes, predictionOutput, videoFilePath)
@ -62,14 +62,14 @@ const createFunscript: Task = async (payload: any, helpers: Helpers) => {
const s3Key = `funscripts/${vodId}.funscript`; const s3Key = `funscripts/${vodId}.funscript`;
const s3Url = await uploadFile(s3Client, env.S3_BUCKET, s3Key, funscriptFilePath, "application/json"); const s3Url = await uploadFile(s3Client, env.S3_BUCKET, s3Key, funscriptFilePath, "application/json");
helpers.logger.info(`Uploaded funscript to S3: ${s3Url}`); logger.info(`Uploaded funscript to S3: ${s3Url}`);
await prisma.vod.update({ await prisma.vod.update({
where: { id: vodId }, where: { id: vodId },
data: { funscript: s3Key } data: { funscript: s3Key }
}); });
helpers.logger.info(`Funscript saved to database for vod ${vodId}`); logger.info(`Funscript saved to database for vod ${vodId}`);
}; };
export default createFunscript; export default createFunscript;

View File

@ -11,6 +11,7 @@ import { mkdirp } from "fs-extra";
import { listFilesRecursive } from "../utils/filesystem"; import { listFilesRecursive } from "../utils/filesystem";
import { getMimeType } from "../utils/mimetype"; import { getMimeType } from "../utils/mimetype";
import { getNanoSpawn } from "../utils/nanoSpawn"; import { getNanoSpawn } from "../utils/nanoSpawn";
import logger from "../utils/logger";
const prisma = new PrismaClient().$extends(withAccelerate()); const prisma = new PrismaClient().$extends(withAccelerate());
@ -155,7 +156,7 @@ export default async function createHlsPlaylist(payload: any, helpers: Helpers)
// * [x] exit if video.hlsPlaylist already defined // * [x] exit if video.hlsPlaylist already defined
if (vod.hlsPlaylist) { if (vod.hlsPlaylist) {
helpers.logger.info(`Doing nothing-- vod ${vodId} already has a hlsPlaylist.`) logger.info(`Doing nothing-- vod ${vodId} already has a hlsPlaylist.`)
return; // Exit the function early return; // Exit the function early
} }
@ -163,32 +164,32 @@ export default async function createHlsPlaylist(payload: any, helpers: Helpers)
throw new Error(`Failed to create hlsPlaylist-- vod ${vodId} is missing a sourceVideo.`); throw new Error(`Failed to create hlsPlaylist-- vod ${vodId} is missing a sourceVideo.`);
} }
helpers.logger.info(`Creating HLS Playlist.`) logger.info(`Creating HLS Playlist.`)
const s3Client = getS3Client() const s3Client = getS3Client()
const taskId = nanoid() const taskId = nanoid()
const workDirPath = join(env.CACHE_ROOT, taskId) const workDirPath = join(env.CACHE_ROOT, taskId)
const packageDirPath = join(workDirPath, 'package', 'hls') const packageDirPath = join(workDirPath, 'package', 'hls')
await mkdirp(packageDirPath) await mkdirp(packageDirPath)
helpers.logger.info("download source video from pull-thru cache") logger.info("download source video from pull-thru cache")
const videoFilePath = await getOrDownloadAsset(s3Client, env.S3_BUCKET, vod.sourceVideo) const videoFilePath = await getOrDownloadAsset(s3Client, env.S3_BUCKET, vod.sourceVideo)
helpers.logger.info(`videoFilePath=${videoFilePath}`) logger.info(`videoFilePath=${videoFilePath}`)
helpers.logger.info("create ABR variants") logger.info("create ABR variants")
const variants = await createVariants(helpers, videoFilePath) const variants = await createVariants(helpers, videoFilePath)
helpers.logger.info('variants as follows') logger.info('variants as follows')
helpers.logger.info(JSON.stringify(variants)) logger.info(JSON.stringify(variants))
helpers.logger.info("run shaka packager") logger.info("run shaka packager")
const masterPlaylistPath = await packageHls(helpers, variants, packageDirPath) const masterPlaylistPath = await packageHls(helpers, variants, packageDirPath)
helpers.logger.debug(`masterPlaylistPath=${masterPlaylistPath}`) logger.debug(`masterPlaylistPath=${masterPlaylistPath}`)
helpers.logger.info('uploading assets') logger.info('uploading assets')
let assets = await listFilesRecursive(workDirPath) let assets = await listFilesRecursive(workDirPath)
helpers.logger.info('assets as follows') logger.info('assets as follows')
helpers.logger.info(JSON.stringify(assets)) logger.info(JSON.stringify(assets))
for (let i = 0; i < assets.length; i++) { for (let i = 0; i < assets.length; i++) {
const asset = assets[i] const asset = assets[i]
const s3Key = `package/${taskId}/hls/${basename(asset)}` const s3Key = `package/${taskId}/hls/${basename(asset)}`
@ -197,7 +198,7 @@ export default async function createHlsPlaylist(payload: any, helpers: Helpers)
}; };
helpers.logger.info("generate thumbnail s3 key") logger.info("generate thumbnail s3 key")
const s3Key = `package/${taskId}/hls/master.m3u8` const s3Key = `package/${taskId}/hls/master.m3u8`

View File

@ -7,6 +7,7 @@ import { S3Client } from "@aws-sdk/client-s3";
import { getS3Client, uploadFile } from "../utils/s3"; import { getS3Client, uploadFile } from "../utils/s3";
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import { getNanoSpawn } from "../utils/nanoSpawn"; import { getNanoSpawn } from "../utils/nanoSpawn";
import logger from "../utils/logger";
const prisma = new PrismaClient().$extends(withAccelerate()); const prisma = new PrismaClient().$extends(withAccelerate());
@ -23,7 +24,7 @@ function getCidFromStdout(output: string) {
} }
async function hash(helpers: Helpers, inputFilePath: string) { async function hash(helpers: Helpers, inputFilePath: string) {
helpers.logger.info(`createIpfsCid with inputFilePath=${inputFilePath}`) logger.info(`createIpfsCid with inputFilePath=${inputFilePath}`)
if (!inputFilePath) { if (!inputFilePath) {
@ -43,7 +44,7 @@ async function hash(helpers: Helpers, inputFilePath: string) {
// console.error(`vcsi failed with exit code ${exitCode}`); // console.error(`vcsi failed with exit code ${exitCode}`);
// process.exit(exitCode); // process.exit(exitCode);
// } // }
helpers.logger.info(JSON.stringify(result)) logger.info(JSON.stringify(result))
return getCidFromStdout(result.stdout) return getCidFromStdout(result.stdout)
} }
@ -67,7 +68,7 @@ export default async function createIpfsCid(payload: any, helpers: Helpers) {
// * [x] exit if video.thumbnail already defined // * [x] exit if video.thumbnail already defined
if (vod.cidv1) { if (vod.cidv1) {
helpers.logger.info(`Doing nothing-- vod ${vodId} already has a cidv1.`) logger.info(`Doing nothing-- vod ${vodId} already has a cidv1.`)
return; // Exit the function early return; // Exit the function early
} }
@ -76,19 +77,19 @@ export default async function createIpfsCid(payload: any, helpers: Helpers) {
} }
helpers.logger.info('Creating CID') logger.info('Creating CID')
const s3Client = getS3Client() const s3Client = getS3Client()
// * [x] download video segments from pull-thru cache // * [x] download video segments from pull-thru cache
const videoFilePath = await getOrDownloadAsset(s3Client, env.S3_BUCKET, vod.sourceVideo) const videoFilePath = await getOrDownloadAsset(s3Client, env.S3_BUCKET, vod.sourceVideo)
helpers.logger.info(`videoFilePath=${videoFilePath}`) logger.info(`videoFilePath=${videoFilePath}`)
// * [x] run ipfs to get a CID // * [x] run ipfs to get a CID
const cidv1 = await hash(helpers, videoFilePath) const cidv1 = await hash(helpers, videoFilePath)
if (!cidv1) throw new Error(`cidv1 ${cidv1} was falsy`); if (!cidv1) throw new Error(`cidv1 ${cidv1} was falsy`);
helpers.logger.info(`cidv1=${cidv1}`) logger.info(`cidv1=${cidv1}`)
// * [x] update vod record // * [x] update vod record
await prisma.vod.update({ await prisma.vod.update({

View File

@ -11,7 +11,6 @@ import logger from "../utils/logger";
import { basename, join } from "node:path"; import { basename, join } from "node:path";
import SftpClient from 'ssh2-sftp-client'; import SftpClient from 'ssh2-sftp-client';
const prisma = new PrismaClient().$extends(withAccelerate()); const prisma = new PrismaClient().$extends(withAccelerate());
@ -21,7 +20,7 @@ interface Payload {
// async function createTorrent(payload: any, helpers: Helpers) { // async function createTorrent(payload: any, helpers: Helpers) {
// helpers.logger.debug(`createTorrent`) // logger.debug(`createTorrent`)
// if (!inputFilePath) { // if (!inputFilePath) {
@ -33,16 +32,16 @@ interface Payload {
// const spawn = await getNanoSpawn(); // const spawn = await getNanoSpawn();
// helpers.logger.debug('result as follows') // logger.debug('result as follows')
// helpers.logger.debug(JSON.stringify(result, null, 2)) // logger.debug(JSON.stringify(result, null, 2))
// helpers.logger.info(`✅ Thumbnail saved to: ${outputFilePath}`); // logger.info(`✅ Thumbnail saved to: ${outputFilePath}`);
// return outputFilePath // return outputFilePath
// } // }
function assertPayload(payload: any): asserts payload is Payload { function assertPayload(payload: any): asserts payload is Payload {
if (typeof payload !== "object" || !payload) throw new Error("invalid payload-- was not an object."); if (typeof payload !== "object" || !payload) throw new Error("invalid payload-- was not an object.");
if (typeof payload.vodId !== "string") throw new Error("invalid payload-- was missing vodId"); if (typeof payload.vodId !== "string") throw new Error(`invalid payload-- ${JSON.stringify(payload)} was missing vodId`);
} }

View File

@ -8,6 +8,7 @@ import { nanoid } from "nanoid";
import { getNanoSpawn } from "../utils/nanoSpawn"; import { getNanoSpawn } from "../utils/nanoSpawn";
import { preparePython } from "../utils/python"; import { preparePython } from "../utils/python";
import { generateS3Path } from "../utils/formatters"; import { generateS3Path } from "../utils/formatters";
import logger from "../utils/logger";
const prisma = new PrismaClient().$extends(withAccelerate()); const prisma = new PrismaClient().$extends(withAccelerate());
@ -17,7 +18,7 @@ interface Payload {
} }
async function createThumbnail(helpers: Helpers, inputFilePath: string) { async function createThumbnail(helpers: Helpers, inputFilePath: string) {
helpers.logger.debug(`createThumbnail with inputFilePath=${inputFilePath}`) logger.debug(`createThumbnail with inputFilePath=${inputFilePath}`)
if (!inputFilePath) { if (!inputFilePath) {
@ -49,10 +50,10 @@ async function createThumbnail(helpers: Helpers, inputFilePath: string) {
cwd: env.APP_DIR, cwd: env.APP_DIR,
}); });
helpers.logger.debug('result as follows') logger.debug('result as follows')
helpers.logger.debug(JSON.stringify(result, null, 2)) logger.debug(JSON.stringify(result, null, 2))
helpers.logger.info(`✅ Thumbnail saved to: ${outputFilePath}`); logger.info(`✅ Thumbnail saved to: ${outputFilePath}`);
return outputFilePath return outputFilePath
} }
@ -84,7 +85,7 @@ export default async function createVideoThumbnail(payload: any, helpers: Helper
// * [x] exit if video.thumbnail already defined // * [x] exit if video.thumbnail already defined
if (vod.thumbnail) { if (vod.thumbnail) {
helpers.logger.info(`Doing nothing-- vod ${vodId} already has a thumbnail.`) logger.info(`Doing nothing-- vod ${vodId} already has a thumbnail.`)
return; // Exit the function early return; // Exit the function early
} }
@ -93,7 +94,7 @@ export default async function createVideoThumbnail(payload: any, helpers: Helper
} }
helpers.logger.info('Creating Video Thumbnail') logger.info('Creating Video Thumbnail')
const s3Client = getS3Client() const s3Client = getS3Client()
// * [x] download video segments from pull-thru cache // * [x] download video segments from pull-thru cache

View File

@ -1,11 +1,12 @@
import type { Task, Helpers } from "graphile-worker"; import type { Task, Helpers } from "graphile-worker";
import { PrismaClient } from "../../generated/prisma"; import { PrismaClient } from "../../generated/prisma";
import { withAccelerate } from "@prisma/extension-accelerate"; import { withAccelerate } from "@prisma/extension-accelerate";
import logger from "../utils/logger";
const prisma = new PrismaClient().$extends(withAccelerate()); const prisma = new PrismaClient().$extends(withAccelerate());
const findWork: Task = async (_payload, helpers: Helpers) => { const findWork: Task = async (_payload, helpers: Helpers) => {
helpers.logger.info(`findWork begin.`); logger.info(`findWork begin.`);
const approvedUploads = await prisma.vod.findMany({ const approvedUploads = await prisma.vod.findMany({
where: { where: {
@ -16,14 +17,14 @@ const findWork: Task = async (_payload, helpers: Helpers) => {
}, },
}); });
helpers.logger.info(`findWork found ${approvedUploads.length} uploads.`); logger.info(`findWork found ${approvedUploads.length} uploads.`);
for (let i = 0; i < approvedUploads.length; i++) { for (let i = 0; i < approvedUploads.length; i++) {
const vod = approvedUploads[i]; const vod = approvedUploads[i];
await helpers.addJob("scheduleVodProcessing", { vodId: vod.id }); await helpers.addJob("scheduleVodProcessing", { vodId: vod.id });
helpers.logger.info(`scheduleVodProcessing for vod ${vod.id}`); logger.info(`scheduleVodProcessing for vod ${vod.id}`);
} }
helpers.logger.info(`findWork finished.`); logger.info(`findWork finished.`);
}; };
export default findWork; export default findWork;

View File

@ -8,6 +8,7 @@ import { createReadStream } from "node:fs";
import { getOrDownloadAsset } from "../utils/cache"; import { getOrDownloadAsset } from "../utils/cache";
import { env } from "../config/env"; import { env } from "../config/env";
import { getS3Client } from "../utils/s3"; import { getS3Client } from "../utils/s3";
import logger from "../utils/logger";
const prisma = new PrismaClient(); const prisma = new PrismaClient();
@ -19,7 +20,7 @@ const client = getS3Client()
const generateVideoChecksum: Task = async (payload: unknown, helpers) => { const generateVideoChecksum: Task = async (payload: unknown, helpers) => {
const { vodId } = payload as Payload; const { vodId } = payload as Payload;
helpers.logger.info(`Generating checksum for VOD ${vodId}`); logger.info(`Generating checksum for VOD ${vodId}`);
// 1. Get VOD record with source video path // 1. Get VOD record with source video path
const vod = await prisma.vod.findUnique({ const vod = await prisma.vod.findUnique({
@ -33,7 +34,7 @@ const generateVideoChecksum: Task = async (payload: unknown, helpers) => {
// 2. Verify file exists // 2. Verify file exists
const videoPath = await getOrDownloadAsset(client, env.S3_BUCKET, vod.sourceVideo) const videoPath = await getOrDownloadAsset(client, env.S3_BUCKET, vod.sourceVideo)
helpers.logger.info(`videoPath=${videoPath}`) logger.info(`videoPath=${videoPath}`)
try { try {
await access(videoPath); await access(videoPath);
@ -52,7 +53,7 @@ const generateVideoChecksum: Task = async (payload: unknown, helpers) => {
); );
const checksum = hash.digest('hex'); const checksum = hash.digest('hex');
helpers.logger.info(`Generated checksum for ${path.basename(vod.sourceVideo)}: ${checksum}`); logger.info(`Generated checksum for ${path.basename(vod.sourceVideo)}: ${checksum}`);
// 4. Update VOD record // 4. Update VOD record
await prisma.vod.update({ await prisma.vod.update({
@ -61,7 +62,7 @@ const generateVideoChecksum: Task = async (payload: unknown, helpers) => {
}); });
} catch (err) { } catch (err) {
helpers.logger.error(`Failed to generate checksum: ${err.message}`); logger.error(`Failed to generate checksum: ${err.message}`);
throw err; // Will trigger retry if configured throw err; // Will trigger retry if configured
} }
}; };

View File

@ -1,7 +1,7 @@
// src/tasks/hello.ts // src/tasks/hello.ts
import type { Task, Helpers } from "graphile-worker"; import type { Task, Helpers } from "graphile-worker";
import logger from "../utils/logger";
interface Payload { interface Payload {
name: string; name: string;
@ -16,6 +16,6 @@ function assertPayload(payload: any): asserts payload is Payload {
export default async function hello(payload: any, helpers: Helpers) { export default async function hello(payload: any, helpers: Helpers) {
assertPayload(payload); assertPayload(payload);
const { name } = payload; const { name } = payload;
helpers.logger.info(`Helloooooo, ${name}`); logger.info(`Helloooooo, ${name}`);
}; };

View File

@ -1,7 +1,7 @@
import type { Task, Job } from "graphile-worker"; import type { Task, Job } from "graphile-worker";
import { PrismaClient } from "../../generated/prisma"; import { PrismaClient } from "../../generated/prisma";
import { withAccelerate } from "@prisma/extension-accelerate"; import { withAccelerate } from "@prisma/extension-accelerate";
import logger from '../utils/logger';
interface Payload { interface Payload {
vodId: string; vodId: string;
@ -27,11 +27,11 @@ const scheduleVodProcessing: Task = async (payload: unknown, helpers) => {
} }
const { vodId } = payload; const { vodId } = payload;
helpers.logger.info(`Starting processing for VOD ${vodId}`); logger.info(`Starting processing for VOD ${vodId}`);
const vod = await prisma.vod.findUnique({ where: { id: vodId } }); const vod = await prisma.vod.findUnique({ where: { id: vodId } });
if (!vod) { if (!vod) {
helpers.logger.error(`VOD not found: ${vodId}`); logger.error(`VOD not found: ${vodId}`);
return; return;
} }
@ -57,7 +57,7 @@ const scheduleVodProcessing: Task = async (payload: unknown, helpers) => {
data: { status: "processing" } data: { status: "processing" }
}); });
helpers.logger.info(`Scheduled ${changes} jobs for VOD ${vodId}`); logger.info(`Scheduled ${changes} jobs for VOD ${vodId}`);
// Schedule next check // Schedule next check
// @huh? @todo IDK what is up with this, but it seems to run right away even though it has the runAt defined. // @huh? @todo IDK what is up with this, but it seems to run right away even though it has the runAt defined.
@ -72,7 +72,7 @@ const scheduleVodProcessing: Task = async (payload: unknown, helpers) => {
where: { id: vodId }, where: { id: vodId },
data: { status: "processed" } data: { status: "processed" }
}); });
helpers.logger.info(`All processing complete for VOD ${vodId}`); logger.info(`All processing complete for VOD ${vodId}`);
} }
}; };

View File

@ -35,12 +35,6 @@
<td>✅</td> <td>✅</td>
<td>✅</td> <td>✅</td>
</tr> </tr>
<tr>
<td>API</td>
<td>✅</td>
<td>✅</td>
<td>✅</td>
</tr>
<tr> <tr>
<td>Torrent Downloads</td> <td>Torrent Downloads</td>
<td>✅</td> <td>✅</td>
@ -53,6 +47,12 @@
<td>✅</td> <td>✅</td>
<td>✅</td> <td>✅</td>
</tr> </tr>
<tr>
<td>API</td>
<td>❌</td>
<td>✅</td>
<td>✅</td>
</tr>
<tr> <tr>
<td>Ad-Free</td> <td>Ad-Free</td>
<td>❌</td> <td>❌</td>