Files
Max Litruv Boonzaayer 07feddd44b
Some checks failed
Build / increment-version (push) Successful in 8s
Build / build-linux (push) Successful in 2m26s
Build Paarrot Windows / build (push) Has been cancelled
Build Paarrot Windows / start-vm (push) Has been cancelled
Build / build-windows (push) Successful in 4m28s
Build / create-release (push) Successful in 30s
Add Paarrot Stream Deck Plugin with core functionality
- Implemented main plugin structure including manifest, HTML, and JavaScript files.
- Added actions for toggling mute, toggling deafen, changing channels, sending messages, and getting status.
- Created property inspector for changing channels and sending messages.
- Developed SVG icons for actions and status display.
- Established WebSocket connection for communication with the Stream Deck.
- Implemented API calls to interact with the Paarrot voice chat application.
- Added validation script to ensure proper plugin structure and manifest compliance.
- Included test Electron application for window creation and loading content.
2026-03-23 20:34:26 +11:00

157 lines
4.6 KiB
JavaScript

/**
* Validation script for Paarrot Stream Deck Plugin
* Checks plugin structure and manifest
*/
const fs = require('fs');
const path = require('path');
const PLUGIN_DIR = 'com.paarrot.streamdeck.sdPlugin';
let errors = 0;
let warnings = 0;
function error(message) {
console.error(`❌ ERROR: ${message}`);
errors++;
}
function warn(message) {
console.warn(`⚠️ WARNING: ${message}`);
warnings++;
}
function success(message) {
console.log(`${message}`);
}
console.log('Validating Paarrot Stream Deck Plugin...\n');
// Check plugin directory exists
if (!fs.existsSync(PLUGIN_DIR)) {
error(`Plugin directory '${PLUGIN_DIR}' not found`);
process.exit(1);
}
// Check manifest.json
const manifestPath = path.join(PLUGIN_DIR, 'manifest.json');
if (!fs.existsSync(manifestPath)) {
error('manifest.json not found');
} else {
success('manifest.json exists');
try {
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
// Validate required fields
const requiredFields = ['Actions', 'Author', 'CodePath', 'Description', 'Name', 'Version', 'SDKVersion'];
requiredFields.forEach(field => {
if (!manifest[field]) {
error(`manifest.json missing required field: ${field}`);
}
});
if (manifest.Actions && Array.isArray(manifest.Actions)) {
success(`Found ${manifest.Actions.length} actions`);
// Validate each action
manifest.Actions.forEach((action, index) => {
const actionName = action.Name || `Action ${index}`;
if (!action.UUID) {
error(`${actionName}: Missing UUID`);
}
if (!action.Icon) {
error(`${actionName}: Missing Icon`);
} else {
// Check if icon file exists
const iconPath = path.join(PLUGIN_DIR, `${action.Icon}.svg`);
const iconPathPng = path.join(PLUGIN_DIR, `${action.Icon}.png`);
if (!fs.existsSync(iconPath) && !fs.existsSync(iconPathPng)) {
warn(`${actionName}: Icon file not found: ${action.Icon}`);
}
}
if (!action.States || !Array.isArray(action.States) || action.States.length === 0) {
error(`${actionName}: Missing or invalid States`);
} else {
action.States.forEach((state, stateIndex) => {
if (!state.Image) {
warn(`${actionName} State ${stateIndex}: Missing Image`);
} else {
const imagePath = path.join(PLUGIN_DIR, `${state.Image}.svg`);
const imagePathPng = path.join(PLUGIN_DIR, `${state.Image}.png`);
if (!fs.existsSync(imagePath) && !fs.existsSync(imagePathPng)) {
warn(`${actionName} State ${stateIndex}: Image file not found: ${state.Image}`);
}
}
});
}
if (action.PropertyInspectorPath) {
const piPath = path.join(PLUGIN_DIR, action.PropertyInspectorPath);
if (!fs.existsSync(piPath)) {
error(`${actionName}: PropertyInspector file not found: ${action.PropertyInspectorPath}`);
}
}
});
}
} catch (e) {
error(`manifest.json parse error: ${e.message}`);
}
}
// Check plugin files
const pluginPath = path.join(PLUGIN_DIR, 'plugin', 'index.html');
if (!fs.existsSync(pluginPath)) {
error('plugin/index.html not found');
} else {
success('plugin/index.html exists');
}
const pluginJsPath = path.join(PLUGIN_DIR, 'plugin', 'index.js');
if (!fs.existsSync(pluginJsPath)) {
error('plugin/index.js not found');
} else {
success('plugin/index.js exists');
}
// Check property inspectors
const piDir = path.join(PLUGIN_DIR, 'propertyinspector');
if (fs.existsSync(piDir)) {
const piFiles = fs.readdirSync(piDir);
success(`Found ${piFiles.length} property inspector file(s)`);
} else {
warn('propertyinspector directory not found');
}
// Check images directory
const imagesDir = path.join(PLUGIN_DIR, 'images');
if (fs.existsSync(imagesDir)) {
const imageFiles = fs.readdirSync(imagesDir);
success(`Found ${imageFiles.length} image file(s)`);
if (imageFiles.length === 0) {
warn('images directory is empty');
}
} else {
error('images directory not found');
}
// Summary
console.log('\n' + '='.repeat(50));
if (errors === 0 && warnings === 0) {
console.log('✓ Plugin validation passed!');
process.exit(0);
} else {
console.log(`Found ${errors} error(s) and ${warnings} warning(s)`);
if (errors > 0) {
console.log('\nPlease fix errors before building the plugin.');
process.exit(1);
} else {
console.log('\nPlugin can be built, but consider fixing warnings.');
process.exit(0);
}
}