MCPcopy
hub / github.com/mruniquehacker/Knightbot-MD / convertBufferToStickerWebp

Function convertBufferToStickerWebp

commands/igs.js:11–138  ·  view source on GitHub ↗
(inputBuffer, isAnimated, cropSquare)

Source from the content-addressed store, hash-verified

9const { stickercropFromBuffer } = require('./stickercrop');
10
11async function convertBufferToStickerWebp(inputBuffer, isAnimated, cropSquare) {
12 const tmpDir = path.join(process.cwd(), 'tmp');
13 if (!fs.existsSync(tmpDir)) fs.mkdirSync(tmpDir, { recursive: true });
14
15 const tempInputBase = path.join(tmpDir, `igs_${Date.now()}_${Math.random().toString(36).slice(2)}`);
16 const tempInput = isAnimated ? `${tempInputBase}.mp4` : `${tempInputBase}.jpg`;
17 const tempOutput = path.join(tmpDir, `igs_out_${Date.now()}_${Math.random().toString(36).slice(2)}.webp`);
18
19 fs.writeFileSync(tempInput, inputBuffer);
20
21 // Deferred cleanup to avoid race with WhatsApp download
22 const filesToDelete = [];
23 const scheduleDelete = (p) => {
24 if (!p) return;
25 filesToDelete.push(p);
26 setTimeout(() => {
27 try { fs.unlinkSync(p); } catch {}
28 }, 5000);
29 };
30
31 // Image filters
32 const vfCropSquareImg = "crop=min(iw\\,ih):min(iw\\,ih),scale=512:512";
33 const vfPadSquareImg = "scale=512:512:force_original_aspect_ratio=decrease,pad=512:512:(ow-iw)/2:(oh-ih)/2:color=#00000000";
34
35 let ffmpegCommand;
36 if (isAnimated) {
37 // For videos/GIFs
38 const isLargeVideo = inputBuffer.length > (5 * 1024 * 1024); // >5MB
39 const maxDuration = isLargeVideo ? 2 : 3;
40 // Match stickercrop.js style compression
41 if (cropSquare) {
42 if (isLargeVideo) {
43 ffmpegCommand = `ffmpeg -y -i "${tempInput}" -t 2 -vf "crop=min(iw\\,ih):min(iw\\,ih),scale=512:512,fps=8" -c:v libwebp -preset default -loop 0 -vsync 0 -pix_fmt yuva420p -quality 30 -compression_level 6 -b:v 100k -max_muxing_queue_size 1024 "${tempOutput}"`;
44 } else {
45 ffmpegCommand = `ffmpeg -y -i "${tempInput}" -t 3 -vf "crop=min(iw\\,ih):min(iw\\,ih),scale=512:512,fps=12" -c:v libwebp -preset default -loop 0 -vsync 0 -pix_fmt yuva420p -quality 50 -compression_level 6 -b:v 150k -max_muxing_queue_size 1024 "${tempOutput}"`;
46 }
47 } else {
48 if (isLargeVideo) {
49 ffmpegCommand = `ffmpeg -y -i "${tempInput}" -t 2 -vf "scale=512:512:force_original_aspect_ratio=decrease,pad=512:512:(ow-iw)/2:(oh-ih)/2:color=#00000000,fps=8" -c:v libwebp -preset default -loop 0 -vsync 0 -pix_fmt yuva420p -quality 35 -compression_level 6 -b:v 100k -max_muxing_queue_size 1024 "${tempOutput}"`;
50 } else {
51 ffmpegCommand = `ffmpeg -y -i "${tempInput}" -t 3 -vf "scale=512:512:force_original_aspect_ratio=decrease,pad=512:512:(ow-iw)/2:(oh-ih)/2:color=#00000000,fps=12" -c:v libwebp -preset default -loop 0 -vsync 0 -pix_fmt yuva420p -quality 45 -compression_level 6 -b:v 150k -max_muxing_queue_size 1024 "${tempOutput}"`;
52 }
53 }
54 } else {
55 // For images
56 const vf = `${cropSquare ? vfCropSquareImg : vfPadSquareImg},format=rgba`;
57 ffmpegCommand = `ffmpeg -y -i "${tempInput}" -vf "${vf}" -c:v libwebp -preset default -loop 0 -vsync 0 -pix_fmt yuva420p -quality 75 -compression_level 6 "${tempOutput}"`;
58 }
59
60 await new Promise((resolve, reject) => {
61 exec(ffmpegCommand, (error, _stdout, _stderr) => {
62 if (error) return reject(error);
63 resolve();
64 });
65 });
66
67 // If output is too large (> ~1MB), do a harsher second pass for videos
68 let webpBuffer = fs.readFileSync(tempOutput);

Callers 1

igsCommandFunction · 0.85

Calls 2

execFunction · 0.85
scheduleDeleteFunction · 0.85

Tested by

no test coverage detected