Add Paarrot Stream Deck Plugin with core functionality
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
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.
This commit is contained in:
156
streamdeck-plugin/validate.js
Normal file
156
streamdeck-plugin/validate.js
Normal file
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user