Files
AeroMc-Launcher/src/streamdeckplugin.js
T
2026-10-30 05:54:28 +00:00

83 lines
3.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use strict';
/*
* streamdeckplugin.js – das AeroMC-Plugin in die Stream-Deck-Software kopieren
* -----------------------------------------------------------------------------
* Das Plugin (Ordner streamdeck-plugin/com.aeromc.launcher.sdPlugin) liegt im
* Launcher mit dabei. Schaltet jemand "Stream Deck erlauben" ein – und bei jedem
* Start, solange es an ist – legt AeroMC es in den Plugin-Ordner der Stream-Deck-
* Software, falls es dort fehlt oder von einer anderen Fassung stammt. Nach dem
* Kopieren muss die Stream-Deck-Software einmal neu gestartet werden, damit sie
* das Plugin lädt.
*/
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const PLUGIN_NAME = 'com.aeromc.launcher.sdPlugin';
// Ordner mit dem mitgelieferten Plugin; null, wenn er in dieser Fassung fehlt
function quelle(istPaketiert, ressourcenOrdner) {
const kandidat = istPaketiert
? path.join(ressourcenOrdner, 'streamdeck-plugin', PLUGIN_NAME)
: path.join(__dirname, '..', 'streamdeck-plugin', PLUGIN_NAME);
return fs.existsSync(path.join(kandidat, 'manifest.json')) ? kandidat : null;
}
// Plugin-Ordner der Stream-Deck-Software; null, wenn sie nie installiert war
function pluginOrdner() {
const appdata = process.env.APPDATA;
if (!appdata) return null;
const ordner = path.join(appdata, 'Elgato', 'StreamDeck', 'Plugins');
return fs.existsSync(ordner) ? ordner : null;
}
// Was die Stream-Deck-Software selbst im Plugin-Ordner anlegt (Protokolle), zählt nicht mit
const IGNORIERT = new Set(['logs']);
function dateien(basis, rel = '') {
const ergebnis = [];
for (const e of fs.readdirSync(path.join(basis, rel), { withFileTypes: true })) {
if (!rel && IGNORIERT.has(e.name)) continue;
const r = rel ? rel + '/' + e.name : e.name;
if (e.isDirectory()) ergebnis.push(...dateien(basis, r));
else ergebnis.push(r);
}
return ergebnis.sort();
}
// Prüfsumme über Dateinamen und -inhalt - gleiche Prüfsumme = gleicher Stand
function fingerabdruck(ordner) {
const h = crypto.createHash('sha1');
for (const rel of dateien(ordner)) {
h.update(rel + '\0');
h.update(fs.readFileSync(path.join(ordner, ...rel.split('/'))));
}
return h.digest('hex');
}
/*
* -> { ok: true, status: 'installiert' | 'aktualisiert' | 'aktuell', neustart }
* { ok: false, grund: 'quelle-fehlt' | 'kein-streamdeck' | 'kopieren', message }
*/
function installiere(opt) {
const o = opt || {};
if (!o.quelle) return { ok: false, grund: 'quelle-fehlt', message: 'Das Plugin ist in dieser Fassung nicht enthalten.' };
const plugins = o.pluginOrdner !== undefined ? o.pluginOrdner : pluginOrdner();
if (!plugins || !fs.existsSync(plugins)) {
return { ok: false, grund: 'kein-streamdeck', message: 'Die Stream-Deck-Software wurde nicht gefunden.' };
}
const ziel = path.join(plugins, PLUGIN_NAME);
try {
const vorhanden = fs.existsSync(ziel);
if (vorhanden && fingerabdruck(ziel) === fingerabdruck(o.quelle)) return { ok: true, status: 'aktuell', neustart: false };
fs.cpSync(o.quelle, ziel, { recursive: true, force: true, filter: (src) => !IGNORIERT.has(path.basename(src)) || src === o.quelle });
return { ok: true, status: vorhanden ? 'aktualisiert' : 'installiert', neustart: true };
} catch (err) {
return { ok: false, grund: 'kopieren', message: 'Das Plugin konnte nicht kopiert werden (' + err.message + '). Bitte die Stream-Deck-Software beenden und es erneut versuchen.' };
}
}
module.exports = { PLUGIN_NAME, quelle, pluginOrdner, installiere, fingerabdruck };