-
Notifications
You must be signed in to change notification settings - Fork 33
/
video-concat.js
133 lines (114 loc) · 4.33 KB
/
video-concat.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
const fs = require('fs');
const fsAsync = require('fs').promises;
const path = require('path');
const childProcess = require("child_process");
const probeCheck = require('./probe-check');
module.exports.combineFilesInDirectory = async (directory, deleteOld = false) => {
console.log(`Combining video files in ${directory}...`);
const filenames = await makeListOfFilesInDir(directory);
const success = await runCombinationProcess(directory);
console.log(`Combination success: ${success}`);
if (deleteOld && success) await deleteFiles(directory, filenames);
}
function runCombinationProcess(directory, listName = 'files.txt') {
return new Promise((resolve, reject) => {
let commandArgs = [
'-hide_banner',
'-y',
'-loglevel', 'warning',
'-f', 'concat', '-safe', '0', '-i', `${path.join(directory, listName)}`, '-c', 'copy', `${path.join(directory, 'output.mkv')}`];
log('Running combination command...');
let ffmpegProcess = childProcess.spawn("ffmpeg", commandArgs, {});
ffmpegProcess.stdout.on('data', (data) => {
log('[STDOUT]', data.toString());
});
ffmpegProcess.stderr.on('data', (data) => {
log('[STDERR]', data.toString());
});
ffmpegProcess.on('exit', (code) => {
log(`[EXIT] code ${code}`);
return resolve(code == 0);
});
ffmpegProcess.on('error', (err) => {
log(`[ERROR]`, err);
return reject(err)
});
})
}
function log(message, ...optionalParams) {
console.log(`${new Date().toISOString()} ${message}`, ...optionalParams);
}
function makeListOfFilesInDir(dir, ext = '.mkv', listName = 'files.txt') {
return new Promise(async (resolve, reject) => {
let listOfFiles = getFilesInDir(dir, ext);
console.log('listOfFiles', listOfFiles);
listOfFiles = filterFilesBySize(dir, [...listOfFiles]);
console.log('filterFilesBySize', listOfFiles);
listOfFiles = await filterFilesByValid(dir, [...listOfFiles]);
console.log('filterFilesByValid', listOfFiles);
const listOfFilesFormatted = listOfFiles.map(x => `file '${x}'`);
console.log(`${listOfFilesFormatted.length} files to combine`);
const listFilepath = path.join(dir, listName);
console.log('saving file list', listFilepath)
const content = listOfFilesFormatted.join('\n');
fs.writeFile(listFilepath, content, (err) => {
if (err) {
console.log(err)
return reject(err)
} else {
console.log('file list saved')
return resolve(listOfFiles);
}
});
})
}
function getFilesInDir(dir, ext = '.mkv') {
let listOfFiles = fs.readdirSync(dir);
listOfFiles = listOfFiles.sort();
listOfFiles = listOfFiles.filter(x => x.endsWith(ext));
listOfFiles = listOfFiles.filter(x => x != 'output.mkv');
return listOfFiles;
}
function filterFilesBySize(dir, filenames, size = 500000) {
const results = [];
for (let i = filenames.length - 1; i >= 0; i--) {
const filename = filenames[i];
const filepath = path.join(dir, filename);
const stats = fs.statSync(filepath);
if (stats.size < size) {
console.log(`${filename} is too small (${stats.size})`);
} else {
results.push(filename)
}
}
return results;
}
async function filterFilesByValid(dir, filenames) {
const results = [];
for (let i = filenames.length - 1; i >= 0; i--) {
const filename = filenames[i];
const success = await probeCheck.probeSuccess(path.join(dir, filename))
if (success) {
results.push(filename);
}
}
return results;
}
async function deleteListOfFilesInDir(dir, listName = 'files.txt') {
return new Promise((resolve, reject) => {
const listFilepath = path.join(dir, listName);
fs.unlink(listFilepath, (err) => {
if (err) {
return reject(err)
} else {
return resolve();
}
});
})
}
async function deleteFiles(directory, filenames) {
for (let i = 0; i < filenames.length; i++) {
const filepath = path.join(directory, filenames[i]);
await fsAsync.unlink(filepath);
}
}