From 382d3b18dd24879782cd27dd367fc2fc2a895cb4 Mon Sep 17 00:00:00 2001
From: ghostboats <106226990+ghostboats@users.noreply.github.com>
Date: Mon, 22 Jul 2024 08:29:44 -0500
Subject: [PATCH] convewr vdoe added
---
commands/convertVideoToGif.js | 143 ++++++++++++++++++++++++++++++++++
extension.js | 3 +
package-lock.json | 119 ++++++++++++++++++++++++++++
package.json | 2 +
4 files changed, 267 insertions(+)
create mode 100644 commands/convertVideoToGif.js
diff --git a/commands/convertVideoToGif.js b/commands/convertVideoToGif.js
new file mode 100644
index 00000000..37acb059
--- /dev/null
+++ b/commands/convertVideoToGif.js
@@ -0,0 +1,143 @@
+const vscode = require('vscode');
+const fs = require('fs');
+const path = require('path');
+const ffmpeg = require('fluent-ffmpeg');
+const ffmpegPath = require('ffmpeg-static');
+
+const { getConfig } = require('../support_files/config');
+const { rootModPath } = getConfig();
+
+console.log("FFmpeg Path:", ffmpegPath);
+console.log("Type of FFmpeg Path:", typeof ffmpegPath);
+
+if (typeof ffmpegPath === 'string') {
+ ffmpeg.setFfmpegPath(ffmpegPath);
+} else {
+ console.error("FFmpeg Path is not a string");
+}
+
+// Command to open the video conversion webview
+const convertVideoToGifCommand = vscode.commands.registerCommand('bg3-mod-helper.convertVideoToGif', async function () {
+ const panel = vscode.window.createWebviewPanel(
+ 'videoConversion',
+ 'Video Conversion',
+ vscode.ViewColumn.One,
+ { enableScripts: true }
+ );
+
+ const videoFiles = await getAllVideoFiles(rootModPath);
+
+ panel.webview.html = getWebviewContent(videoFiles);
+
+ // Handle messages from the webview
+ panel.webview.onDidReceiveMessage(async message => {
+ switch (message.command) {
+ case 'convert':
+ await convertVideoToGifFile(message.videoPath, message.gifPath);
+ break;
+ case 'convertAll':
+ for (const video of videoFiles) {
+ const gifPath = video.replace(path.extname(video), '.gif');
+ await convertVideoToGifFile(video, gifPath);
+ }
+ break;
+ case 'selectFile':
+ const options = {
+ canSelectMany: false,
+ openLabel: 'Select a video file',
+ filters: { 'Video files': ['mp4', 'mkv', 'avi', 'mov'] }
+ };
+ const fileUri = await vscode.window.showOpenDialog(options);
+ if (fileUri && fileUri[0]) {
+ const videoPath = fileUri[0].fsPath;
+ const gifPath = videoPath.replace(path.extname(videoPath), '.gif');
+ await convertVideoToGifFile(videoPath, gifPath);
+ }
+ break;
+ }
+ });
+});
+
+async function getAllVideoFiles(dir) {
+ let files = [];
+ const items = await fs.promises.readdir(dir, { withFileTypes: true });
+ for (const item of items) {
+ const fullPath = path.join(dir, item.name);
+ if (item.isDirectory()) {
+ files = files.concat(await getAllVideoFiles(fullPath));
+ } else if (/\.(mp4|mkv|avi|mov)$/i.test(item.name)) {
+ files.push(fullPath);
+ }
+ }
+ return files;
+}
+
+function getWebviewContent(videoFiles) {
+ const videoFileItems = videoFiles.map(file => `
+
+ ${path.basename(file)} |
+ ${file} |
+ |
+
+ `).join('');
+
+ return `
+
+
+ Video Conversion
+
+
+ Name |
+ Path |
+ Action |
+
+ ${videoFileItems}
+
+
+
+
+
+
+ `;
+}
+
+async function convertVideoToGifFile(inputPath, outputPath) {
+ return new Promise((resolve, reject) => {
+ const normalizedInput = path.normalize(inputPath);
+ const normalizedOutput = path.normalize(outputPath);
+
+ console.log("Normalized Input Path:", normalizedInput);
+ console.log("Normalized Output Path:", normalizedOutput);
+
+ ffmpeg(normalizedInput)
+ .outputOptions([
+ '-vf', 'fps=24', // Increase fps for smoother animation
+ '-gifflags', 'transdiff',
+ '-y', // Overwrite output files without asking
+ '-q:v', '5' // Set quality level (lower is better, 0 is the best quality)
+ ])
+ .save(normalizedOutput)
+ .on('end', () => {
+ vscode.window.showInformationMessage(`GIF created: ${normalizedOutput}`);
+ resolve();
+ })
+ .on('error', (err) => {
+ vscode.window.showErrorMessage(`Error: ${err.message}`);
+ reject(err);
+ });
+ });
+}
+
+
+module.exports = { convertVideoToGifCommand };
diff --git a/extension.js b/extension.js
index 939289b6..aee2baff 100644
--- a/extension.js
+++ b/extension.js
@@ -39,6 +39,7 @@ let packModImport,
xmlMergerCommand,
symlinkerCommand,
indentXmlFilesCommand,
+ convertVideoToGifCommand,
debugCommand,
debug2Command,
unpackGameDataCommand,
@@ -108,6 +109,7 @@ function setCommands() {
organizeDataFilesCommand = require('./commands/organizeDataFiles');
symlinkerCommand = require('./commands/symlinker');
indentXmlFilesCommand = require('./commands/indentXmlFiles');
+ convertVideoToGifCommand = require('./commands/convertVideoToGif');
// debug commands
debugCommand = require('./commands/debug');
@@ -226,6 +228,7 @@ function aSimpleDataProvider() {
{ label: 'Generate Folder Structure', command: 'bg3-mod-helper.createModTemplate' },
{ label: 'Atlas Generator (Supply a folder of icons to make an atlas and its corresponding .dds with those icons, as well as its merged.lsx)', command: 'bg3-mod-helper.createAtlas' },
{ label: 'BBCode/Markdown Editor ', command: 'bg3-mod-helper.textEditorTool'},
+ { label: 'Convert Video to GIF', command: 'bg3-mod-helper.convertVideoToGif' },
{ label: 'Version Generator', command: 'bg3-mod-helper.versionGenerator' },
{ label: 'Merge Xmls', command: 'bg3-mod-helper.xmlMerger' },
{ label: 'Add/Remove Symlink (in development)', command: 'bg3-mod-helper.symlinker' },
diff --git a/package-lock.json b/package-lock.json
index face3d44..5bae7f0a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,6 +9,8 @@
"version": "2.2.53",
"license": "LGPL-3.0-or-later",
"dependencies": {
+ "ffmpeg-static": "^5.2.0",
+ "fluent-ffmpeg": "^2.1.3",
"jszip": "^3.10.1",
"log4js": "^6.9.1",
"magickwand.js": "^1.1.0",
@@ -23,6 +25,20 @@
"vscode": "^1.86.0"
}
},
+ "node_modules/@derhuerst/http-basic": {
+ "version": "8.2.4",
+ "resolved": "https://registry.npmjs.org/@derhuerst/http-basic/-/http-basic-8.2.4.tgz",
+ "integrity": "sha512-F9rL9k9Xjf5blCz8HsJRO4diy111cayL2vkY2XE4r4t3n0yPXVYy3KD3nJ1qbrSn9743UWSXH4IwuCa/HWlGFw==",
+ "dependencies": {
+ "caseless": "^0.12.0",
+ "concat-stream": "^2.0.0",
+ "http-response-object": "^3.0.1",
+ "parse-cache-control": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
"node_modules/@emnapi/runtime": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.2.0.tgz",
@@ -200,6 +216,11 @@
"node": ">=14"
}
},
+ "node_modules/@types/node": {
+ "version": "10.17.60",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz",
+ "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw=="
+ },
"node_modules/abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
@@ -269,6 +290,11 @@
"node": ">=10"
}
},
+ "node_modules/async": {
+ "version": "0.2.10",
+ "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz",
+ "integrity": "sha512-eAkdoKxU6/LkKDBzLpT+t6Ff5EtfSF4wx1WfJiPEEV7WNLnDaRXk0oVysiEPm262roaachGexwUv94WhSgN5TQ=="
+ },
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -284,6 +310,11 @@
"concat-map": "0.0.1"
}
},
+ "node_modules/buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
+ },
"node_modules/cacache": {
"version": "18.0.2",
"resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.2.tgz",
@@ -376,6 +407,11 @@
"node": ">=16 || 14 >=14.17"
}
},
+ "node_modules/caseless": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw=="
+ },
"node_modules/chalk": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz",
@@ -435,6 +471,20 @@
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"license": "MIT"
},
+ "node_modules/concat-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
+ "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
+ "engines": [
+ "node >= 6.0"
+ ],
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.0.2",
+ "typedarray": "^0.0.6"
+ }
+ },
"node_modules/console-control-strings": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
@@ -598,11 +648,54 @@
"node": "^12.20 || >= 14.13"
}
},
+ "node_modules/ffmpeg-static": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/ffmpeg-static/-/ffmpeg-static-5.2.0.tgz",
+ "integrity": "sha512-WrM7kLW+do9HLr+H6tk7LzQ7kPqbAgLjdzNE32+u3Ff11gXt9Kkkd2nusGFrlWMIe+XaA97t+I8JS7sZIrvRgA==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "@derhuerst/http-basic": "^8.2.0",
+ "env-paths": "^2.2.0",
+ "https-proxy-agent": "^5.0.0",
+ "progress": "^2.0.3"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
"node_modules/flatted": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz",
"integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw=="
},
+ "node_modules/fluent-ffmpeg": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/fluent-ffmpeg/-/fluent-ffmpeg-2.1.3.tgz",
+ "integrity": "sha512-Be3narBNt2s6bsaqP6Jzq91heDgOEaDCJAXcE3qcma/EJBSy5FB4cvO31XBInuAuKBx8Kptf8dkhjK0IOru39Q==",
+ "dependencies": {
+ "async": "^0.2.9",
+ "which": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/fluent-ffmpeg/node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
+ },
+ "node_modules/fluent-ffmpeg/node_modules/which": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "which": "bin/which"
+ }
+ },
"node_modules/foreground-child": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
@@ -762,6 +855,14 @@
"node": ">= 14"
}
},
+ "node_modules/http-response-object": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz",
+ "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==",
+ "dependencies": {
+ "@types/node": "^10.0.3"
+ }
+ },
"node_modules/https-proxy-agent": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
@@ -1431,6 +1532,11 @@
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
},
+ "node_modules/parse-cache-control": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz",
+ "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg=="
+ },
"node_modules/path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
@@ -1484,6 +1590,14 @@
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
+ "node_modules/progress": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
"node_modules/promise-retry": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz",
@@ -1785,6 +1899,11 @@
"integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==",
"license": "0BSD"
},
+ "node_modules/typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
+ },
"node_modules/unique-filename": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz",
diff --git a/package.json b/package.json
index b1fd7259..ad027731 100644
--- a/package.json
+++ b/package.json
@@ -494,6 +494,8 @@
"dependencies": "npm install"
},
"dependencies": {
+ "ffmpeg-static": "^5.2.0",
+ "fluent-ffmpeg": "^2.1.3",
"jszip": "^3.10.1",
"log4js": "^6.9.1",
"magickwand.js": "^1.1.0",