69 lines
1.6 KiB
JavaScript
69 lines
1.6 KiB
JavaScript
|
|
import { execa } from 'execa'
|
|
import { tmpdir } from 'os'
|
|
import path from 'node:path'
|
|
import fs from 'node:fs'
|
|
import os from 'node:os'
|
|
|
|
export class VideoConcatError extends Error {
|
|
constructor (msg) {
|
|
super(msg || 'Failed to concatenate video')
|
|
this.name = 'VideoConcatError'
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export default class Video {
|
|
constructor (opts) {
|
|
if (typeof opts.filePaths === 'undefined') throw new Error('Video must be called with opts.filePaths');
|
|
if (typeof opts.cwd === 'undefined') throw new Error('Video must be called with opts.cwd');
|
|
this.filePaths = opts.filePaths
|
|
this.cwd = opts.cwd
|
|
this.room = opts.room || 'projektmelody'
|
|
this.execa = opts.execa || execa
|
|
}
|
|
|
|
|
|
|
|
getFilesTxt () {
|
|
return this.filePaths
|
|
.sort((a, b) => a.timestamp - b.timestamp)
|
|
.map((d) => `file '${d.file}'`)
|
|
.join('\n')
|
|
.concat('\n')
|
|
}
|
|
|
|
|
|
getFilesFile () {
|
|
const p = path.join(this.cwd, 'files.txt')
|
|
fs.writeFileSync(
|
|
p,
|
|
this.getFilesTxt(this.filePaths),
|
|
{ encoding: 'utf-8' }
|
|
)
|
|
return p
|
|
}
|
|
|
|
async concat () {
|
|
const target = path.join(this.cwd, `${this.room}-chaturbate-${new Date().valueOf()}.mp4`)
|
|
|
|
const { exitCode, killed, stdout, stderr } = await this.execa('ffmpeg', [
|
|
'-y',
|
|
'-f', 'concat',
|
|
'-safe', '0',
|
|
'-i', this.getFilesFile(this.filePaths),
|
|
'-c', 'copy',
|
|
target
|
|
], {
|
|
cwd: this.cwd
|
|
});
|
|
|
|
if (exitCode !== 0 || killed !== false) {
|
|
throw new VideoConcatError(`exitCode:${exitCode}, killed:${killed}, stdout:${stdout}, stderr:${stderr}`);
|
|
}
|
|
|
|
return target
|
|
}
|
|
}
|