feat(worker): conform — queue proxy build for the conformed output
ProRes / DNxHR conformed outputs are unplayable in the browser
(HTML5 video: MEDIA_ERR_SRC_NOT_SUPPORTED). The library was
referencing the ProRes original as the only source.
After the asset row is inserted, queue an H.264 proxy build the same
way services/mam-api/src/routes/assets.js does on ingest:
proxyQueue.add('generate', {
assetId,
inputKey: outputKey, // the conformed mov / mp4
outputKey: `proxies/${id}.mp4`,
});
The proxy worker writes the H.264 mp4, updates assets.proxy_s3_key,
and from then on /assets/:id/stream prefers the proxy over the
original. The library player can decode it natively.
Failure to enqueue is logged but doesn't fail the conform job — the
asset still exists and can have a proxy re-queued later.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
446a563647
commit
6bc6478270
1 changed files with 37 additions and 3 deletions
|
|
@ -1,6 +1,7 @@
|
|||
import { join } from 'path';
|
||||
import { unlink, writeFile, mkdir, rm } from 'fs/promises';
|
||||
import { tmpdir } from 'os';
|
||||
import { Queue } from 'bullmq';
|
||||
import { query } from '../db/client.js';
|
||||
import { downloadFromS3, uploadToS3 } from '../s3/client.js';
|
||||
import { trimSegment, concatSegments, runFFmpeg, getMediaInfo } from '../ffmpeg/executor.js';
|
||||
|
|
@ -9,6 +10,19 @@ import { XMLParser } from 'fast-xml-parser';
|
|||
|
||||
const S3_BUCKET = process.env.S3_BUCKET || 'wild-dragon';
|
||||
|
||||
// Used to queue a proxy build for the conformed output so the library /
|
||||
// asset viewer has a browser-playable H.264 preview. Without this the
|
||||
// browser hits MEDIA_ERR_SRC_NOT_SUPPORTED on ProRes / DNxHR outputs.
|
||||
const parseRedisUrl = (url) => {
|
||||
try {
|
||||
const parsed = new URL(url);
|
||||
return { host: parsed.hostname, port: parseInt(parsed.port, 10) || 6379 };
|
||||
} catch { return { host: 'localhost', port: 6379 }; }
|
||||
};
|
||||
const proxyQueue = new Queue('proxy', {
|
||||
connection: parseRedisUrl(process.env.REDIS_URL || 'redis://queue:6379'),
|
||||
});
|
||||
|
||||
const xmlParser = new XMLParser({
|
||||
ignoreAttributes: false,
|
||||
attributeNamePrefix: '@_',
|
||||
|
|
@ -353,10 +367,30 @@ export const conformWorker = async (job) => {
|
|||
]
|
||||
);
|
||||
|
||||
await job.updateProgress(100);
|
||||
console.log(`[conform] Job ${jobId} complete → asset ${assetRes.rows[0].id}`);
|
||||
const newAssetId = assetRes.rows[0].id;
|
||||
|
||||
return { jobId, outputKey, assetId: assetRes.rows[0].id };
|
||||
// Queue a proxy build so the library has a browser-playable H.264 file.
|
||||
// ProRes / DNxHR masters don't decode in HTML5 video; without this step
|
||||
// the asset shows MEDIA_ERR_SRC_NOT_SUPPORTED in the player. Mirror the
|
||||
// ingest pipeline's pattern (services/mam-api/src/routes/assets.js).
|
||||
try {
|
||||
const generatedProxyKey = `proxies/${newAssetId}.mp4`;
|
||||
await proxyQueue.add('generate', {
|
||||
assetId: newAssetId,
|
||||
inputKey: outputKey,
|
||||
outputKey: generatedProxyKey,
|
||||
});
|
||||
console.log(`[conform] queued proxy build for ${newAssetId}`);
|
||||
} catch (e) {
|
||||
// Don't fail the conform job if the proxy queue is unreachable —
|
||||
// the asset still exists, an operator can retrigger the proxy.
|
||||
console.warn(`[conform] failed to queue proxy for ${newAssetId}: ${e.message}`);
|
||||
}
|
||||
|
||||
await job.updateProgress(100);
|
||||
console.log(`[conform] Job ${jobId} complete → asset ${newAssetId}`);
|
||||
|
||||
return { jobId, outputKey, assetId: newAssetId };
|
||||
|
||||
} catch (error) {
|
||||
console.error(`[conform] Error in job ${jobId}:`, error);
|
||||
|
|
|
|||
Loading…
Reference in a new issue