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
- 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.
157 lines
4.6 KiB
JavaScript
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);
|
|
}
|
|
}
|