Spaces:
Running
Running
| import {copyFileSync, existsSync, readdirSync, unlinkSync} from 'fs'; | |
| import {join} from 'path'; | |
| import pkg from 'common-utils'; | |
| import {exec} from 'child_process'; | |
| import {dirname} from 'path'; | |
| import {fileURLToPath} from 'url'; | |
| import { platform } from 'os'; | |
| import { renderSSR } from './test-render.js'; | |
| import path from 'path'; | |
| const {UnzipFiles, Utils, ZipFiles} = pkg; | |
| const __filename = fileURLToPath(import.meta.url); | |
| const __dirname = dirname(__filename); | |
| export async function explodeUrl(fileUrl, jobId, dir, zipFile) { | |
| await Utils.downloadFile(fileUrl, zipFile, true); | |
| await UnzipFiles(zipFile, dir); | |
| } | |
| export async function listOutputFiles(jobId) { | |
| let outDir = join(__dirname, 'out'); | |
| let manuFile = join(__dirname, `public/original_manuscript.json`); | |
| copyFileSync(manuFile, join(__dirname, 'out', `original_manuscript.json`)); | |
| let outputFiles = readdirSync(outDir).map((fname) => { | |
| const filePath = join(outDir, fname); | |
| return filePath; | |
| }); | |
| return outputFiles; | |
| } | |
| export async function generateOutputBundle(jobId) { | |
| let outFile = join(__dirname, 'out', `output-${jobId}.zip`); | |
| let outputFiles = await listOutputFiles(jobId); | |
| if (existsSync(outFile)) { | |
| unlinkSync(outFile); | |
| } | |
| await ZipFiles(outputFiles, outFile); | |
| return outFile; | |
| } | |
| export function getNpmScript(mediaType) { | |
| if (mediaType === 'image') { | |
| return 'still'; | |
| } else if (!mediaType || mediaType === 'video') { | |
| return 'render'; | |
| } else { | |
| return mediaType; | |
| } | |
| } | |
| export async function doRender(jobId, composition, sendToObserver, target = 'render', ssrOptions) { | |
| let outFile = path.join(process.cwd(), `out`, `${jobId}-video.mp4`); | |
| if (ssrOptions) { | |
| await renderSSR(outFile, ssrOptions.frameRange, ssrOptions.durationOverride) | |
| sendToObserver(jobId, 'completed'); | |
| return outFile | |
| } | |
| const renderComposition = composition || 'SemibitComposition'; | |
| let script = 'render-build'; | |
| if (platform() == 'win32') { | |
| script = `render-build:win32` | |
| } | |
| let cmd = `npm run ${script} --target=${target} --composition=${renderComposition}`; | |
| const childProcess = exec(cmd); | |
| console.log('Starting video render. ' + cmd); | |
| let updateCounter = 0; | |
| childProcess.stdout.on('data', (data) => { | |
| sendToObserver(jobId, data); | |
| if (!process.env.is_pm2) console.log(data.toString()); | |
| if (updateCounter++ % 100 == 0 || updateCounter < 5) { | |
| console.log(data.split('\n')[0]); | |
| } | |
| }); | |
| childProcess.stderr.on('data', (data) => { | |
| sendToObserver(jobId, data); | |
| console.error(data.toString()); | |
| }); | |
| return new Promise((resolve, reject) => { | |
| childProcess.on('close', (code) => { | |
| console.log('Render video finished'); | |
| sendToObserver(jobId, code === 0 ? 'completed' : 'failed'); | |
| if (code === 0) { | |
| resolve(outFile); | |
| console.log(`'${target}' completed successfully.`); | |
| } else { | |
| reject({ | |
| message: `'${target}' failed with code ${code}.`, | |
| }); | |
| console.error(`'${target}' failed with code ${code}.`); | |
| } | |
| }); | |
| }); | |
| } | |
| export function clear(skipOutput, skipPublic, skipUploads) { | |
| try { | |
| const preserve = ['assets', 'mp3']; | |
| if (!skipPublic) Utils.clearFolder(join(__dirname, './public'), preserve); | |
| if (!skipOutput) Utils.clearFolder(join(__dirname, './out')); | |
| if (!skipUploads) Utils.clearFolder(join(__dirname, './uploads')); | |
| } catch (e) {} | |
| } | |