// article.js // Copyright (C) 2022 DTP Technologies, LLC // License: Apache-2.0 'use strict'; const util = require('util'); const execFile = util.promisify(require('child_process').execFile); const { SiteService } = require('../../lib/site-lib'); class MediaService extends SiteService { constructor (dtp) { super(dtp, module.exports); } async ffmpeg (ffmpegArgs) { try { await execFile(process.env.DTP_FFMPEG_PATH, ffmpegArgs, { cwd: this.dtp.config.root, encoding: 'utf8', }); } catch (error) { this.log.error('failed to execute ffprobe', { ffmpegArgs, error }); throw error; } } 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; } } } module.exports = { slug: 'media', name: 'media', create: (dtp) => { return new MediaService(dtp); }, };