From abaf134c283f7e837761b473f24f52e0d85d2899 Mon Sep 17 00:00:00 2001 From: Quentin Roussel Date: Sun, 18 Aug 2024 14:26:06 +0800 Subject: [PATCH] video generation working --- .dockerignore | 2 ++ .gitignore | 3 ++- downloader.mjs | 15 +++++++-------- index.mjs | 5 +++++ video.js | 0 video.mjs | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 66 insertions(+), 9 deletions(-) create mode 100644 .dockerignore delete mode 100644 video.js create mode 100644 video.mjs diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..7ff5a9e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +node_modules/ +node_modules/* \ No newline at end of file diff --git a/.gitignore b/.gitignore index 6c49c3e..1d8ffcc 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -images/*.png \ No newline at end of file +images/**/*.png +**/*.mp4 \ No newline at end of file diff --git a/downloader.mjs b/downloader.mjs index bbacef0..f8192a6 100644 --- a/downloader.mjs +++ b/downloader.mjs @@ -30,7 +30,7 @@ function downloadImage(time_string, filepath) { "Sec-Fetch-Dest": "image", "Sec-Fetch-Mode": "no-cors", "Sec-Fetch-Site": "same-origin", - "Priority": "u=5, i", + "Priority": "i", "Pragma": "no-cache", "Cache-Control": "no-cache", "TE": "trailers", @@ -61,12 +61,12 @@ function downloadImage(time_string, filepath) { } export async function initImages(count) { - let files = fs.readdirSync('images/'); + let files = fs.readdirSync('images/raw'); let downloaded = 0; let i = 0; while(downloaded < count) { let time_string = getTimeString(i); - let filename = `images/${time_string}.png`; + let filename = `images/raw/${time_string}.png`; if (files.includes(`${time_string}.png`)) { downloaded++; i++; @@ -90,7 +90,7 @@ export async function updateImages(count) { for (let i = count; i >= 0; i--) { time_strings.push(getTimeString(i)); } - let files = fs.readdirSync('images/'); + let files = fs.readdirSync('images/raw'); let image_count = files.length; let updated = false; @@ -99,12 +99,11 @@ export async function updateImages(count) { for (let time_string of time_strings) { if (!files.includes(`${time_string}.png`)) { try { - await downloadImage(time_string, `images/${time_string}.png`); + await downloadImage(time_string, `images/raw/${time_string}.png`); updated = true; image_count++; } catch (error) { - console.log("No more images available"); - break; + console.log("Skipped image " + time_string); } } } @@ -112,7 +111,7 @@ export async function updateImages(count) { //Remove old files for (let file of files.sort().slice(0, image_count - count)) { console.log(`Deleting ${file}`); - fs.unlinkSync(`images/${file}`); + fs.unlinkSync(`images/raw/${file}`); } return updated; diff --git a/index.mjs b/index.mjs index a40cf7f..8157aea 100644 --- a/index.mjs +++ b/index.mjs @@ -1,9 +1,14 @@ import { initImages, updateImages } from './downloader.mjs'; +import { createVideo } from './video.mjs'; const IMAGE_COUNT = 5; initImages(IMAGE_COUNT).then(() => { console.log('Downloaded initial images successfully'); + createVideo().then(() => { + console.log('Generated final images successfully'); + }); + }); setInterval(() => { diff --git a/video.js b/video.js deleted file mode 100644 index e69de29..0000000 diff --git a/video.mjs b/video.mjs new file mode 100644 index 0000000..d7b8fa5 --- /dev/null +++ b/video.mjs @@ -0,0 +1,50 @@ +import { createCanvas, loadImage } from 'canvas'; +import fs from 'fs'; +import { exec } from 'child_process'; + +async function overlayImage(time_string) { + let ctx = createCanvas(853, 479).getContext('2d'); + + let bg = await loadImage('bg.png') + ctx.drawImage(bg, 0, 0, 853, 479) + + let overlay = await loadImage('images/raw/' + time_string + '.png') + ctx.drawImage(overlay, 0, 0, 853, 479) + + let text = time_string.substring(8, 10) + ':' + time_string.substring(10, 12); + ctx.font = 'bold 70px sans-serif'; + ctx.fillStyle = 'rgba(0,0,0,0.7)'; + ctx.fillText(text, 853 - 250, 479 - 40); + + return ctx.canvas.toBuffer("image/png"); +} + +async function generateFinalImages() { + //Clear out the final images directory + let final_files = fs.readdirSync('images/final'); + for (let file of final_files) { + fs.unlinkSync(`images/final/${file}`); + } + let files = fs.readdirSync('images/raw'); + let i = 0; + for (let file of files) { + let time_string = file.split('.')[0]; + let final_image = await overlayImage(time_string); + fs.writeFileSync(`images/final/${i}.png`, final_image); + i++; + } +} + +export async function createVideo() { + await generateFinalImages(); + //run the command ffmpeg -framerate 5 -i %d.png -c:v libx264 -r 30 output.mp4 + return new Promise((resolve, reject) => { + exec('ffmpeg -framerate 5 -i images/final/%d.png -c:v libx264 -r 30 images/output.mp4', (err, stdout, stderr) => { + if (err) { + reject(err); + return; + } + resolve(stdout); + }); + }); +} \ No newline at end of file