mirror of
https://git.roussel.pro/public-website/singapore_rain_radar.git
synced 2026-02-09 02:20:17 +01:00
video generation working
This commit is contained in:
2
.dockerignore
Normal file
2
.dockerignore
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
node_modules/
|
||||||
|
node_modules/*
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
images/*.png
|
images/**/*.png
|
||||||
|
**/*.mp4
|
||||||
@@ -30,7 +30,7 @@ function downloadImage(time_string, filepath) {
|
|||||||
"Sec-Fetch-Dest": "image",
|
"Sec-Fetch-Dest": "image",
|
||||||
"Sec-Fetch-Mode": "no-cors",
|
"Sec-Fetch-Mode": "no-cors",
|
||||||
"Sec-Fetch-Site": "same-origin",
|
"Sec-Fetch-Site": "same-origin",
|
||||||
"Priority": "u=5, i",
|
"Priority": "i",
|
||||||
"Pragma": "no-cache",
|
"Pragma": "no-cache",
|
||||||
"Cache-Control": "no-cache",
|
"Cache-Control": "no-cache",
|
||||||
"TE": "trailers",
|
"TE": "trailers",
|
||||||
@@ -61,12 +61,12 @@ function downloadImage(time_string, filepath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function initImages(count) {
|
export async function initImages(count) {
|
||||||
let files = fs.readdirSync('images/');
|
let files = fs.readdirSync('images/raw');
|
||||||
let downloaded = 0;
|
let downloaded = 0;
|
||||||
let i = 0;
|
let i = 0;
|
||||||
while(downloaded < count) {
|
while(downloaded < count) {
|
||||||
let time_string = getTimeString(i);
|
let time_string = getTimeString(i);
|
||||||
let filename = `images/${time_string}.png`;
|
let filename = `images/raw/${time_string}.png`;
|
||||||
if (files.includes(`${time_string}.png`)) {
|
if (files.includes(`${time_string}.png`)) {
|
||||||
downloaded++;
|
downloaded++;
|
||||||
i++;
|
i++;
|
||||||
@@ -90,7 +90,7 @@ export async function updateImages(count) {
|
|||||||
for (let i = count; i >= 0; i--) {
|
for (let i = count; i >= 0; i--) {
|
||||||
time_strings.push(getTimeString(i));
|
time_strings.push(getTimeString(i));
|
||||||
}
|
}
|
||||||
let files = fs.readdirSync('images/');
|
let files = fs.readdirSync('images/raw');
|
||||||
let image_count = files.length;
|
let image_count = files.length;
|
||||||
|
|
||||||
let updated = false;
|
let updated = false;
|
||||||
@@ -99,12 +99,11 @@ export async function updateImages(count) {
|
|||||||
for (let time_string of time_strings) {
|
for (let time_string of time_strings) {
|
||||||
if (!files.includes(`${time_string}.png`)) {
|
if (!files.includes(`${time_string}.png`)) {
|
||||||
try {
|
try {
|
||||||
await downloadImage(time_string, `images/${time_string}.png`);
|
await downloadImage(time_string, `images/raw/${time_string}.png`);
|
||||||
updated = true;
|
updated = true;
|
||||||
image_count++;
|
image_count++;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("No more images available");
|
console.log("Skipped image " + time_string);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,7 +111,7 @@ export async function updateImages(count) {
|
|||||||
//Remove old files
|
//Remove old files
|
||||||
for (let file of files.sort().slice(0, image_count - count)) {
|
for (let file of files.sort().slice(0, image_count - count)) {
|
||||||
console.log(`Deleting ${file}`);
|
console.log(`Deleting ${file}`);
|
||||||
fs.unlinkSync(`images/${file}`);
|
fs.unlinkSync(`images/raw/${file}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return updated;
|
return updated;
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
import { initImages, updateImages } from './downloader.mjs';
|
import { initImages, updateImages } from './downloader.mjs';
|
||||||
|
import { createVideo } from './video.mjs';
|
||||||
|
|
||||||
const IMAGE_COUNT = 5;
|
const IMAGE_COUNT = 5;
|
||||||
|
|
||||||
initImages(IMAGE_COUNT).then(() => {
|
initImages(IMAGE_COUNT).then(() => {
|
||||||
console.log('Downloaded initial images successfully');
|
console.log('Downloaded initial images successfully');
|
||||||
|
createVideo().then(() => {
|
||||||
|
console.log('Generated final images successfully');
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
|
|||||||
50
video.mjs
Normal file
50
video.mjs
Normal file
@@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user