Add video.mjs

This commit is contained in:
Lisa 2025-04-11 20:51:13 +02:00
commit 3d41bc9345

103
video.mjs Normal file
View File

@ -0,0 +1,103 @@
import ffmpeg from 'fluent-ffmpeg';
import sharp from 'sharp';
import chalk from 'chalk';
import { exec } from 'child_process';
import fs from 'fs';
const args = process.argv.slice(2);
const videoPathIndex = args.indexOf('--path');
if (videoPathIndex === -1 || !args[videoPathIndex + 1]) {
console.error('Please provide the video path using --path');
process.exit(1);
}
const fpsIndex = args.indexOf('--fps');
const resolutionIndex = args.indexOf('--resolution');
const videoPath = args[videoPathIndex + 1];
const frameRate = fpsIndex !== -1 ? parseInt(args[fpsIndex + 1]) || 10 : 10;
const resolutionSetting = resolutionIndex !== -1 ? args[resolutionIndex + 1] : 'current';
console.log(`Made with <3 by Lisa Honkay (lisahonkay@gmail.com)`);
console.log(`Processing video: ${videoPath}`);
console.log(`Using FPS: ${frameRate}`);
console.log(`Resolution: ${resolutionSetting}`);
const resolutionFilter = resolutionSetting === 'current' ? 'scale=iw:ih' : `scale=${resolutionSetting}`;
const framePathPattern = 'frames_%04d.png';
ffmpeg(videoPath)
.outputOptions('-vf', `fps=${frameRate},${resolutionFilter}`)
.outputOptions('-q:v', '2')
.saveToFile(framePathPattern)
.on('end', () => {
console.log('All frames processed.');
processFrames();
});
let frameQueue = [];
function processFrames() {
exec(`ls ${framePathPattern.replace('%04d', '*')} | sort`, (error, stdout) => {
if (error) {
console.error('Error listing frames:', error);
return;
}
frameQueue = stdout.split('\n').filter(file => file);
console.log(`Loaded ${frameQueue.length} frames.`);
playFrames();
});
}
function playFrames() {
let index = 0;
function renderFrame() {
if (index >= frameQueue.length) {
console.log('Playback finished.');
return;
}
console.time('FrameRender');
sharp(frameQueue[index])
.toBuffer()
.then(imageBuffer => sharp(imageBuffer).raw().toBuffer({ resolveWithObject: true }))
.then(({ data, info }) => {
console.timeEnd('FrameRender');
const terminalWidth = process.stdout.columns || 80;
const terminalHeight = process.stdout.rows || 24;
const aspectRatio = info.width / info.height;
const targetWidth = Math.max(20, terminalWidth - 2);
const targetHeight = Math.min(Math.floor(targetWidth / aspectRatio), terminalHeight - 2);
let output = '';
for (let y = 0; y < targetHeight; y++) {
for (let x = 0; x < targetWidth; x++) {
const idx = (Math.floor(y * info.height / targetHeight) * info.width + Math.floor(x * info.width / targetWidth)) * 3;
const r = data[idx];
const g = data[idx + 1];
const b = data[idx + 2];
output += chalk.rgb(r, g, b)('█');
}
output += '\n';
}
process.stdout.cursorTo(0, 0);
process.stdout.write(output);
fs.unlink(frameQueue[index], err => {
if (err) console.error('Error deleting frame:', err);
});
index++;
process.nextTick(renderFrame);
})
.catch(error => console.error('Error processing frame:', error));
}
setTimeout(renderFrame, 4000);
}
console.log('Extracting frames, this may take a moment...');