DTP Base provides a scalable and secure Node.js application development harness ready for production service.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

109 lines
2.9 KiB

// media.js
// Copyright (C) 2024 DTP Technologies, LLC
// All Rights Reserved
'use strict';
import util from 'node:util';
import { execFile, spawn } from 'node:child_process';
const ExecFile = util.promisify(execFile);
import { SiteService } from '../../lib/site-lib.js';
export default class MediaService extends SiteService {
static get name ( ) { return 'MediaService'; }
static get slug ( ) { return 'media'; }
constructor (dtp) {
super(dtp, MediaService);
}
ffmpeg (ffmpegArgs) {
return new Promise((resolve, reject) => {
const child = spawn(process.env.DTP_FFMPEG_PATH, ffmpegArgs, {
cwd: this.dtp.config.root,
stdio: [],
});
child.stdout.on('data', (data) => {
this.log.info(data.toString());
});
child.stderr.on('data', (data) => {
const message = data.toString();
this.log.info(message);
});
child.on('close', (code) => {
if (code !== 0) {
return reject(code);
}
return resolve();
});
});
}
async ffprobe (input, options) {
options = Object.assign({
streams: true,
format: true,
error: true,
}, options);
const ffprobeOpts = ['-print_format', 'json'];
if (options.streams) {
ffprobeOpts.push('-show_streams');
}
if (options.format) {
ffprobeOpts.push('-show_format');
}
if (options.error) {
ffprobeOpts.push('-show_error');
}
ffprobeOpts.push(input);
try {
const { stdout } = await ExecFile(process.env.DTP_FFPROBE_PATH, ffprobeOpts, {
cwd: this.dtp.config.root,
encoding: 'utf8',
});
const probe = JSON.parse(stdout);
if (probe.format && probe.format.tags) {
let keys = Object.keys(probe.format.tags);
keys.forEach((key) => {
probe.format.tags[key.replace(/\./g, '_')] = probe.format.tags[key];
delete probe.format.tags[key];
});
}
probe.duration = probe.format.duration;
probe.width = probe.format.width;
if (Array.isArray(probe.streams) && probe.streams.length) {
const stream = probe.streams
.find((stream) => stream.codec_type === 'video') || probe.streams[0];
if (stream.duration) {
probe.duration = parseFloat(stream.duration);
} else {
probe.duration = parseFloat(probe.format.duration);
}
probe.width = stream.width;
probe.height = stream.height;
const fpsFraction = stream.avg_frame_rate.split('/').map((value) => parseInt(value, 10));
if (Array.isArray(fpsFraction) && fpsFraction[1] !== 0) {
probe.fps = fpsFraction[0] / fpsFraction[1];
}
} else {
probe.duration = undefined;
probe.width = undefined;
probe.height = undefined;
}
return probe;
} catch (error) {
this.log.error('failed to execute ffprobe', { input, error });
throw error;
}
}
}