-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.js
More file actions
133 lines (113 loc) · 5.04 KB
/
index.js
File metadata and controls
133 lines (113 loc) · 5.04 KB
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
// Get-Content "C:\Users\LinuxPony\Desktop\transcode-script\ffmpeg.log" -wait
const fs = require("fs");
const path = require("path");
const { exec } = require("child_process");
const fsp = require("fs/promises");
const util = require("util");
const INPUT_DIR = "X:/Vanhoover 2024"; // Change this
const STAGING_DIR = "C:/TempVideos/IN"; // Change this
const TEMP_DIR = "C:/TempVideos/OUT"; // Change this
const OUTPUT_DIR = "X:/Vanhoover 2024 Transcoded"; // Change this
const CORRUPTED_LOG = "X:/CORRUPTED-DATA.txt";
const FFMPEG_LOG_FILE = path.join(__dirname, "ffmpeg.log"); // Stores it next to the script - Log file for FFmpeg output
const ffmpegCommands = {
mp4: (input, output) => `ffmpeg -y -hwaccel cuda -i ${input} -c:v hevc_nvenc -preset p4 -b:v 8M -c:a aac -b:a 320k -movflags +faststart -map_metadata 0 -gpu 0 -rc vbr_hq ${output}`,
wav: (input, output) => `ffmpeg -i ${input} -c:a aac -b:a 320k ${output}`
};
async function copyFile(src, dest) {
console.log(`Copying file: ${src} -> ${dest}`);
await fsp.mkdir(path.dirname(dest), { recursive: true });
await fsp.copyFile(src, dest);
console.log(`Finished copy: ${src} -> ${dest}`);
}
async function processFile(fullPath, relPath, ext) {
const stagingPath = path.join(STAGING_DIR, relPath);
const tempPath = path.join(TEMP_DIR, relPath);
const outputPath = path.join(OUTPUT_DIR, relPath);
const actualOutputPath = ext === ".wav" ? outputPath.replace(/\.wav$/i, ".m4a") : outputPath;
if (fs.existsSync(actualOutputPath)) {
console.log(`Output file already exists, skipping: ${actualOutputPath}`);
return;
}
if (path.basename(fullPath).startsWith("._") || (ext !== ".mp4" && ext !== ".wav")) {
console.log(`Copying file directly to output: ${fullPath} -> ${outputPath}`);
await copyFile(fullPath, outputPath);
return;
}
console.log(`Copying file to staging: ${fullPath} -> ${stagingPath}`);
await copyFile(fullPath, stagingPath);
if (ext === ".mp4" || ext === ".wav") {
const encodedTempPath = ext === ".wav" ? tempPath.replace(/\.wav$/i, ".m4a") : tempPath;
const encodedOutputPath = actualOutputPath;
console.log(`Encoding file: ${stagingPath}`);
await fsp.mkdir(path.dirname(encodedTempPath), { recursive: true });
console.log(`Ensuring output directory exists for: ${encodedTempPath}`);
await fsp.mkdir(path.dirname(encodedTempPath), { recursive: true });
const ffmpegCmd = ffmpegCommands[ext.slice(1)](`"${stagingPath}"`, `"${encodedTempPath}"`);
console.log(`Executing FFmpeg command: ${ffmpegCmd}`);
try {
await runFFmpeg(ffmpegCmd);
console.log(`Moving encoded file to output: ${encodedTempPath} -> ${encodedOutputPath}`);
await copyFile(encodedTempPath, encodedOutputPath);
console.log(`Deleting temp file: ${encodedTempPath}`);
await fsp.unlink(encodedTempPath);
console.log(`Deleted temp file: ${encodedTempPath}`);
} catch (err) {
console.error(`Failed to encode: ${stagingPath}. Logging to ${CORRUPTED_LOG}`);
fs.appendFileSync(CORRUPTED_LOG, fullPath + "\n");
try {
await fsp.unlink(stagingPath);
console.log(`Deleted failed staging file: ${stagingPath}`);
} catch (unlinkErr) {
console.error(`Failed to delete staging file: ${stagingPath}`, unlinkErr);
}
return; // Skip to next file
}
}
console.log(`Deleting staging file: ${stagingPath}`);
await fsp.unlink(stagingPath);
console.log(`Deleted staging file: ${stagingPath}`);
}
async function processFiles(dir) {
console.log(`Scanning directory: ${dir}`);
const entries = await fsp.readdir(dir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
const relPath = path.relative(INPUT_DIR, fullPath).replace(/\\/g, "/");
const ext = path.extname(entry.name).toLowerCase();
if (entry.isDirectory()) {
console.log(`Creating directory: ${path.join(OUTPUT_DIR, relPath)}`);
await fsp.mkdir(path.join(OUTPUT_DIR, relPath), { recursive: true });
await processFiles(fullPath);
} else if (entry.isFile()) {
await processFile(fullPath, relPath, ext);
}
}
}
async function runFFmpeg(command) {
return new Promise((resolve, reject) => {
console.log(`Executing FFmpeg command: ${command}`);
const logStream = fs.createWriteStream(FFMPEG_LOG_FILE, { flags: "a" });
const process = exec(command, { shell: true });
process.stdout.pipe(logStream);
process.stderr.pipe(logStream);
process.on("close", (code) => {
if (code !== 0) {
console.error(`FFmpeg process exited with code ${code}. Check ${FFMPEG_LOG_FILE} for details.`);
return reject(new Error(`FFmpeg failed with exit code ${code}`));
}
console.log(`FFmpeg process completed successfully.`);
resolve();
});
});
}
(async () => {
try {
console.log("Starting processing...");
await processFiles(INPUT_DIR);
console.log("Processing complete! Exiting script.");
process.exit(0);
} catch (error) {
console.error("Error processing files:", error);
}
})();