« get me outta code hell

hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/gen-thumbs.js65
-rw-r--r--src/util/node-utils.js9
2 files changed, 71 insertions, 3 deletions
diff --git a/src/gen-thumbs.js b/src/gen-thumbs.js
index e6dfeae7..839c1d42 100644
--- a/src/gen-thumbs.js
+++ b/src/gen-thumbs.js
@@ -100,6 +100,7 @@ import {
 } from './util/cli.js';
 
 import {
+    commandExists,
     isMain,
     promisifyProcess,
 } from './util/node-utils.js';
@@ -133,18 +134,62 @@ function readFileMD5(filePath) {
     });
 }
 
-function generateImageThumbnails(filePath) {
+async function getImageMagickVersion(spawnConvert) {
+    const proc = spawnConvert(['--version'], false);
+
+    let allData = '';
+    proc.stdout.on('data', data => {
+        allData += data.toString();
+    });
+
+    await promisifyProcess(proc, false);
+
+    if (!allData.match(/ImageMagick/i)) {
+        return null;
+    }
+
+    const match = allData.match(/Version: (.*)/i);
+    if (!match) {
+        return 'unknown version';
+    }
+
+    return match[1];
+}
+
+async function getSpawnConvert() {
+    let fn, description, version;
+    if (await commandExists('convert')) {
+        fn = args => spawn('convert', args);
+        description = 'convert';
+    } else if (await commandExists('magick')) {
+        fn = (args, prefix = true) => spawn('magick',
+            (prefix ? ['convert', ...args] : args));
+        description = 'magick convert';
+    } else {
+        return [`no convert or magick binary`, null];
+    }
+
+    version = await getImageMagickVersion(fn);
+
+    if (version === null) {
+        return [`binary --version output didn't indicate it's ImageMagick`];
+    }
+
+    return [`${description} (${version})`, fn];
+}
+
+function generateImageThumbnails(filePath, {spawnConvert}) {
     const dirname = path.dirname(filePath);
     const extname = path.extname(filePath);
     const basename = path.basename(filePath, extname);
     const output = name => path.join(dirname, basename + name + '.jpg');
 
-    const convert = (name, {size, quality}) => spawn('convert', [
+    const convert = (name, {size, quality}) => spawnConvert([
+        filePath,
         '-strip',
         '-resize', `${size}x${size}>`,
         '-interlace', 'Plane',
         '-quality', `${quality}%`,
-        filePath,
         output(name)
     ]);
 
@@ -192,6 +237,20 @@ export default async function genThumbs(mediaPath, {
         return true;
     };
 
+    const [convertInfo, spawnConvert] = await getSpawnConvert() ?? [];
+    if (!spawnConvert) {
+        logError`${`It looks like you don't have ImageMagick installed.`}`;
+        logError`ImageMagick is required to generate thumbnails for display on the wiki.`;
+        logError`(Error message: ${convertInfo})`;
+        logInfo`You can find info to help install ImageMagick on Linux, Windows, or macOS`;
+        logInfo`from its official website: ${`https://imagemagick.org/script/download.php`}`;
+        logInfo`If you have trouble working ImageMagick and would like some help, feel free`;
+        logInfo`to drop a message in the HSMusic Discord server! ${'https://hsmusic.wiki/discord/'}`;
+        return false;
+    } else {
+        logInfo`Found ImageMagick binary: ${convertInfo}`;
+    }
+
     let cache, firstRun = false, failedReadingCache = false;
     try {
         cache = JSON.parse(await readFile(path.join(mediaPath, CACHE_FILE)));
diff --git a/src/util/node-utils.js b/src/util/node-utils.js
index a46d6141..ad87cae3 100644
--- a/src/util/node-utils.js
+++ b/src/util/node-utils.js
@@ -2,6 +2,15 @@
 
 import { fileURLToPath } from 'url';
 
+import _commandExists from 'command-exists';
+
+// This package throws an error instead of returning false when the command
+// doesn't exist, for some reason. Yay for making logic more difficult!
+// Here's a straightforward workaround.
+export function commandExists(command) {
+    return _commandExists(command).then(() => true, () => false);
+}
+
 // Very cool function origin8ting in... http-music pro8a8ly!
 // Sorry if we happen to 8e violating past-us's copyright, lmao.
 export function promisifyProcess(proc, showLogging = true) {