add some colour

satisfy the linter
This commit is contained in:
onyx-and-iris 2025-06-30 15:54:41 +01:00
parent 7ec73f8253
commit a97019b521
9 changed files with 4771 additions and 662 deletions

591
index.js
View File

@ -1,306 +1,301 @@
#!/usr/bin/env node #!/usr/bin/env node
import cli from "./utils/cli.js"; import { QWebChannel } from 'qwebchannel'
import { sceneHelp, sceneList, sceneSwitch, sceneCurrent } from "./utils/scene.js"; import WebSocket from 'ws'
import { audioHelp, audioMute, audioUnmute, audioToggle, audioStatus } from "./utils/audio.js";
import { streamHelp, streamStart, streamStop, streamStatus } from "./utils/stream.js";
import { recordHelp, recordStart, recordStop, recordStatus } from "./utils/record.js";
import { QWebChannel } from "qwebchannel";
import cli from './utils/cli.js'
import { sceneHelp, sceneList, sceneSwitch, sceneCurrent } from './utils/scene.js'
import { audioHelp, audioMute, audioUnmute, audioToggle, audioStatus } from './utils/audio.js'
import { streamHelp, streamStart, streamStop, streamStatus } from './utils/stream.js'
import { recordHelp, recordStart, recordStop, recordStatus } from './utils/record.js'
const address = process.env.MELD_CLI_HOST || "localhost"; const address = process.env.MELD_CLI_HOST || 'localhost'
const port = process.env.MELD_CLI_PORT || 13376; const port = process.env.MELD_CLI_PORT || 13376
const input = cli.input; const input = cli.input
const flags = cli.flags; const flags = cli.flags
var socket = new WebSocket(`ws://${address}:${port}`); const socket = new WebSocket(`ws://${address}:${port}`)
socket.onopen = function () {
socket.onopen = function() { (() => {
let channel; let channel
(() => { try {
try { if (input[0] === 'scene') {
if (input[0] === "scene") { if (flags.help) {
if (flags.help) { console.log(sceneHelp)
console.log(sceneHelp); socket.close()
socket.close(); process.exit(0)
process.exit(0);
}
const sceneCommand = input[1];
switch (sceneCommand) {
case "list":
channel = new QWebChannel(socket, function (channel) {
sceneList(channel)
.then((scenes) => {
console.log("Available scenes:");
scenes.forEach(scene => {
console.log(`- ${scene.name} (ID: ${scene.id})`);
});
socket.close();
process.exit(0);
})
.catch((err) => {
console.error(`${err}`);
socket.close();
process.exit(1);
});
});
break;
case "switch":
const sceneName = input[2];
if (!sceneName) {
console.error("Error: Scene name is required for the switch command.");
process.exit(1);
}
channel = new QWebChannel(socket, function (channel) {
sceneSwitch(channel, sceneName)
.then(() => {
socket.close();
process.exit(0);
})
.catch((err) => {
console.error(`${err}`);
socket.close();
process.exit(1);
});
});
return;
case "current":
channel = new QWebChannel(socket, function (channel) {
sceneCurrent(channel)
.then((currentScene) => {
if (currentScene) {
console.log(`Current scene: ${currentScene.name} (ID: ${currentScene.id})`);
} else {
console.log("No current scene found.");
}
socket.close();
process.exit(0);
})
.catch((err) => {
console.error(`${err}`);
socket.close();
process.exit(1);
});
});
return;
default:
console.log(sceneHelp);
socket.close();
process.exit(0);
}
} else if (input[0] === "audio") {
if (flags.help) {
console.log(audioHelp);
socket.close();
process.exit(0);
}
const audioCommand = input[1];
const audioName = input[2];
switch (audioCommand) {
case "mute":
if (!audioName) {
console.error("Error: Audio name is required for the mute command.");
process.exit(1);
}
channel = new QWebChannel(socket, function (channel) {
audioMute(channel, audioName)
.then((message) => {
console.log(message);
socket.close();
process.exit(0);
})
.catch((err) => {
console.error(`${err}`);
socket.close();
process.exit(1);
});
});
return;
case "unmute":
if (!audioName) {
console.error("Error: Audio name is required for the mute command.");
process.exit(1);
}
channel = new QWebChannel(socket, function (channel) {
audioUnmute(channel, audioName)
.then((message) => {
console.log(message);
socket.close();
process.exit(0);
})
.catch((err) => {
console.error(`${err}`);
socket.close();
process.exit(1);
});
});
return;
case "toggle":
channel = new QWebChannel(socket, function (channel) {
audioToggle(channel, audioName)
.then((message) => {
console.log(message);
socket.close();
process.exit(0);
})
.catch((err) => {
console.error(`${err}`);
socket.close();
process.exit(1);
});
});
return;
case "status":
channel = new QWebChannel(socket, function (channel) {
audioStatus(channel, audioName)
.then((status) => {
console.log(`${audioName} is ${status ? "muted" : "unmuted"}`);
socket.close();
process.exit(0);
})
.catch((err) => {
console.error(`Error fetching audio status: ${err}`);
socket.close();
process.exit(1);
});
});
return;
default:
console.log(audioHelp);
socket.close();
process.exit(0);
}
} else if (input[0] === "stream") {
if (flags.help) {
console.log(streamHelp);
socket.close();
process.exit(0);
}
const streamCommand = input[1];
switch (streamCommand) {
case "start":
channel = new QWebChannel(socket, function (channel) {
streamStart(channel)
.then((message) => {
console.log(message);
socket.close();
process.exit(0);
})
.catch((err) => {
console.error(`${err}`);
socket.close();
process.exit(1);
});
});
return;
case "stop":
channel = new QWebChannel(socket, function (channel) {
streamStop(channel)
.then((message) => {
console.log(message);
socket.close();
process.exit(0);
})
.catch((err) => {
console.error(`${err}`);
socket.close();
process.exit(1);
});
});
break;
case "status":
channel = new QWebChannel(socket, function (channel) {
streamStatus(channel)
.then((isStreaming) => {
console.log(`Streaming is currently ${isStreaming ? "active" : "inactive"}`);
socket.close();
process.exit(0);
})
.catch((err) => {
console.error(`Error fetching stream status: ${err}`);
socket.close();
process.exit(1);
});
});
return;
default:
console.log(streamHelp);
socket.close();
process.exit(0);
}
} else if (input[0] === "record") {
if (flags.help) {
console.log(recordHelp);
socket.close();
process.exit(0);
}
const recordCommand = input[1];
switch (recordCommand) {
case "start":
channel = new QWebChannel(socket, function (channel) {
recordStart(channel)
.then((message) => {
console.log(message);
socket.close();
process.exit(0);
})
.catch((err) => {
console.error(`${err}`);
socket.close();
process.exit(1);
});
});
return;
case "stop":
channel = new QWebChannel(socket, function (channel) {
recordStop(channel)
.then((message) => {
console.log(message);
socket.close();
process.exit(0);
})
.catch((err) => {
console.error(`${err}`);
socket.close();
process.exit(1);
});
});
return;
case "status":
channel = new QWebChannel(socket, function (channel) {
recordStatus(channel)
.then((isRecording) => {
console.log(`Recording is currently ${isRecording ? "active" : "inactive"}`);
socket.close();
process.exit(0);
})
.catch((err) => {
console.error(`Error fetching recording status: ${err}`);
socket.close();
process.exit(1);
});
});
return;
default:
console.log(recordHelp);
socket.close();
process.exit(0);
}
} else {
console.log("Unknown command. Use --help for available commands.");
socket.close();
process.exit(0);
}
} catch (error) {
console.error("Error handling CLI flags:", error);
} }
})();
}; const sceneCommand = input[1]
const sceneArguments = input.slice(2)
switch (sceneCommand) {
case 'list':
channel = new QWebChannel(socket, function (channel) {
sceneList(channel)
.then((scenes) => {
console.log(scenes)
socket.close()
process.exit(0)
})
.catch((err) => {
console.error(`${err}`)
socket.close()
process.exit(1)
})
})
break
case 'switch':
if (!sceneArguments[0]) {
console.error('Error: Scene name is required for the switch command.')
process.exit(1)
}
channel = new QWebChannel(socket, function (channel) {
sceneSwitch(channel, sceneArguments[0])
.then((message) => {
console.log(message)
socket.close()
process.exit(0)
})
.catch((err) => {
console.error(`${err}`)
socket.close()
process.exit(1)
})
})
break
case 'current':
channel = new QWebChannel(socket, function (channel) {
sceneCurrent(channel)
.then((message) => {
console.log(message)
socket.close()
process.exit(0)
})
.catch((err) => {
console.error(`${err}`)
socket.close()
process.exit(1)
})
})
break
default:
console.log(sceneHelp)
socket.close()
process.exit(0)
}
} else if (input[0] === 'audio') {
if (flags.help) {
console.log(audioHelp)
socket.close()
process.exit(0)
}
const audioCommand = input[1]
const audioName = input[2]
switch (audioCommand) {
case 'mute':
if (!audioName) {
console.error('Error: Audio name is required for the mute command.')
process.exit(1)
}
channel = new QWebChannel(socket, function (channel) {
audioMute(channel, audioName)
.then((message) => {
console.log(message)
socket.close()
process.exit(0)
})
.catch((err) => {
console.error(`${err}`)
socket.close()
process.exit(1)
})
})
break
case 'unmute':
if (!audioName) {
console.error('Error: Audio name is required for the unmute command.')
process.exit(1)
}
channel = new QWebChannel(socket, function (channel) {
audioUnmute(channel, audioName)
.then((message) => {
console.log(message)
socket.close()
process.exit(0)
})
.catch((err) => {
console.error(`${err}`)
socket.close()
process.exit(1)
})
})
break
case 'toggle':
channel = new QWebChannel(socket, function (channel) {
audioToggle(channel, audioName)
.then((message) => {
console.log(message)
socket.close()
process.exit(0)
})
.catch((err) => {
console.error(`${err}`)
socket.close()
process.exit(1)
})
})
break
case 'status':
channel = new QWebChannel(socket, function (channel) {
audioStatus(channel, audioName)
.then((message) => {
console.log(message)
socket.close()
process.exit(0)
})
.catch((err) => {
console.error(`${err}`)
socket.close()
process.exit(1)
})
})
break
default:
console.log(audioHelp)
socket.close()
process.exit(0)
}
} else if (input[0] === 'stream') {
if (flags.help) {
console.log(streamHelp)
socket.close()
process.exit(0)
}
const streamCommand = input[1]
switch (streamCommand) {
case 'start':
channel = new QWebChannel(socket, function (channel) {
streamStart(channel)
.then((message) => {
console.log(message)
socket.close()
process.exit(0)
})
.catch((err) => {
console.error(`${err}`)
socket.close()
process.exit(1)
})
})
break
case 'stop':
channel = new QWebChannel(socket, function (channel) {
streamStop(channel)
.then((message) => {
console.log(message)
socket.close()
process.exit(0)
})
.catch((err) => {
console.error(`${err}`)
socket.close()
process.exit(1)
})
})
break
case 'status':
channel = new QWebChannel(socket, function (channel) {
streamStatus(channel)
.then((message) => {
console.log(message)
socket.close()
process.exit(0)
})
.catch((err) => {
console.error(`${err}`)
socket.close()
process.exit(1)
})
})
break
default:
console.log(streamHelp)
socket.close()
process.exit(0)
}
} else if (input[0] === 'record') {
if (flags.help) {
console.log(recordHelp)
socket.close()
process.exit(0)
}
const recordCommand = input[1]
switch (recordCommand) {
case 'start':
channel = new QWebChannel(socket, function (channel) {
recordStart(channel)
.then((message) => {
console.log(message)
socket.close()
process.exit(0)
})
.catch((err) => {
console.error(`${err}`)
socket.close()
process.exit(1)
})
})
break
case 'stop':
channel = new QWebChannel(socket, function (channel) {
recordStop(channel)
.then((message) => {
console.log(message)
socket.close()
process.exit(0)
})
.catch((err) => {
console.error(`${err}`)
socket.close()
process.exit(1)
})
})
break
case 'status':
channel = new QWebChannel(socket, function (channel) {
recordStatus(channel)
.then((message) => {
console.log(message)
socket.close()
process.exit(0)
})
.catch((err) => {
console.error(`${err}`)
socket.close()
process.exit(1)
})
})
break
default:
console.log(recordHelp)
socket.close()
process.exit(0)
}
} else {
console.log('Unknown command. Use meld-cli --help for available commands.')
socket.close()
process.exit(0)
}
} catch (error) {
console.error('Error handling CLI flags:', error)
}
})()
}

4072
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -26,8 +26,14 @@
"meld-cli": "index.js" "meld-cli": "index.js"
}, },
"dependencies": { "dependencies": {
"cli-color": "^2.0.4",
"cli-meow-help": "^4.0.0", "cli-meow-help": "^4.0.0",
"cli-table3": "^0.6.5",
"meow": "^13.2.0", "meow": "^13.2.0",
"qwebchannel": "^6.2.0" "qwebchannel": "^6.2.0",
"ws": "^8.18.3"
},
"devDependencies": {
"standard": "^17.1.2"
} }
} }

View File

@ -1,150 +1,158 @@
import meowHelp from "cli-meow-help"; import meowHelp from 'cli-meow-help'
import { highlight, error } from './style.js'
const commands = { const commands = {
mute: { mute: {
desc: "Mute the audio", desc: 'Mute the audio'
}, },
unmute: { unmute: {
desc: "Unmute the audio", desc: 'Unmute the audio'
}, },
toggle: { toggle: {
desc: "Toggle audio mute state", desc: 'Toggle audio mute state'
}, },
status: { status: {
desc: "Show current audio status", desc: 'Show current audio status'
}, }
} }
const flags = { const flags = {
help: { help: {
type: "boolean", type: 'boolean',
shortFlag: "h", shortFlag: 'h',
desc: "Display help information" desc: 'Display help information'
}, }
}; }
const audioHelp = meowHelp({ const audioHelp = meowHelp({
name: "meld-cli audio", name: 'meld-cli audio',
flags, flags,
commands, commands,
description: "Manage audio settings in Meld", description: 'Manage audio settings in Meld',
defaults: false, defaults: false
}); })
function audioMute(channel, audioName) { function audioMute (channel, audioName) {
if (!channel.objects || !channel.objects.meld) { if (!channel.objects || !channel.objects.meld) {
return Promise.reject(new Error("Meld object not found in channel.")); return Promise.reject(new Error(error('Meld object not found in channel.')))
} }
const meld = channel.objects.meld; const meld = channel.objects.meld
let itemId; let itemId
let isMuted; let isMuted
for (const [key, value] of Object.entries(meld.session.items)) { for (const [key, value] of Object.entries(meld.session.items)) {
if (value.type === "track" && value.name === audioName) { if (value.type === 'track' && value.name === audioName) {
itemId = key; itemId = key
isMuted = value.muted; isMuted = value.muted
break; break
}
} }
}
if (!itemId) { if (!itemId) {
return Promise.reject(new Error(`No audio device with name ${audioName} found.`)); return Promise.reject(new Error(`No audio device with name ${audioName} found.`))
} }
if (isMuted) { if (isMuted) {
return Promise.resolve(`Audio track ${audioName} is already muted.`); return Promise.resolve(`Audio track ${highlight(audioName)} is already muted.`)
} }
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
meld.toggleMute(itemId) meld.toggleMute(itemId)
.then(() => { .then(() => {
resolve(`Audio track ${audioName} has been muted.`); resolve(`Audio track ${highlight(audioName)} has been muted.`)
}) })
.catch((err) => { .catch((err) => {
reject(new Error(`Error muting audio track: ${err}`)); reject(new Error(`Error muting audio track: ${err}`))
}); })
}) })
} }
function audioUnmute(channel, audioName) { function audioUnmute (channel, audioName) {
if (!channel.objects || !channel.objects.meld) { if (!channel.objects || !channel.objects.meld) {
return Promise.reject(new Error("Meld object not found in channel.")); return Promise.reject(new Error('Meld object not found in channel.'))
} }
const meld = channel.objects.meld; const meld = channel.objects.meld
let itemId; let itemId
let isMuted; let isMuted
for (const [key, value] of Object.entries(meld.session.items)) { for (const [key, value] of Object.entries(meld.session.items)) {
if (value.type === "track" && value.name === audioName) { if (value.type === 'track' && value.name === audioName) {
itemId = key; itemId = key
isMuted = value.muted; isMuted = value.muted
break; break
}
}
if (!itemId) {
return Promise.reject(new Error("No audio track found."));
}
if (!isMuted) {
return Promise.resolve(`Audio track ${audioName} is already unmuted.`);
} }
}
if (!itemId) {
return Promise.reject(new Error('No audio track found.'))
}
if (!isMuted) {
return Promise.resolve(`Audio track ${audioName} is already unmuted.`)
}
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
meld.toggleMute(itemId) meld.toggleMute(itemId)
.then(() => { .then(() => {
resolve(`Audio track ${audioName} has been unmuted.`); resolve(`Audio track ${audioName} has been unmuted.`)
}) })
.catch((err) => { .catch((err) => {
reject(new Error(`Error unmuting audio track: ${err}`)); reject(new Error(`Error unmuting audio track: ${err}`))
}); })
}); })
} }
function audioToggle(channel, audioName) { function audioToggle (channel, audioName) {
if (!channel.objects || !channel.objects.meld) { if (!channel.objects || !channel.objects.meld) {
return Promise.reject(new Error("Meld object not found in channel.")); return Promise.reject(new Error('Meld object not found in channel.'))
}
const meld = channel.objects.meld
let itemId
let isMuted
for (const [key, value] of Object.entries(meld.session.items)) {
if (value.type === 'track' && value.name === audioName) {
itemId = key
isMuted = value.muted
break
} }
const meld = channel.objects.meld; }
let itemId; if (!itemId) {
let isMuted; return Promise.reject(new Error(`No audio device with name ${audioName} found.`))
for (const [key, value] of Object.entries(meld.session.items)) { }
if (value.type === "track" && value.name === audioName) { return new Promise((resolve, reject) => {
itemId = key; meld.toggleMute(itemId)
isMuted = value.muted; .then(() => {
break; const status = isMuted ? 'unmuted' : 'muted'
} resolve(`Audio track ${audioName} has been ${status}.`)
} })
if (!itemId) { .catch((err) => {
return Promise.reject(new Error(`No audio device with name ${audioName} found.`)); reject(new Error(`Error toggling audio track: ${err}`))
} })
return new Promise((resolve, reject) => { })
meld.toggleMute(itemId)
.then(() => {
const status = isMuted ? "unmuted" : "muted";
resolve(`Audio track ${audioName} has been ${status}.`);
})
.catch((err) => {
reject(new Error(`Error toggling audio track: ${err}`));
});
});
} }
function audioStatus(channel, audioName) { function audioStatus (channel, audioName) {
if (!channel.objects || !channel.objects.meld) { if (!channel.objects || !channel.objects.meld) {
return Promise.reject(new Error("Meld object not found in channel.")); return Promise.reject(new Error('Meld object not found in channel.'))
}
const meld = channel.objects.meld
let itemId
let isMuted
for (const [key, value] of Object.entries(meld.session.items)) {
if (value.type === 'track' && value.name === audioName) {
itemId = key
isMuted = value.muted
break
} }
const meld = channel.objects.meld; }
let itemId; if (!itemId) {
let isMuted; return Promise.reject(new Error(`No audio device with name ${audioName} found.`))
for (const [key, value] of Object.entries(meld.session.items)) { }
if (value.type === "track" && value.name === audioName) { return new Promise((resolve, reject) => {
itemId = key; resolve(`${highlight(audioName)} is ${isMuted ? 'muted' : 'unmuted'}`)
isMuted = value.muted; })
break;
}
}
if (!itemId) {
return Promise.reject(new Error(`No audio device with name ${audioName} found.`));
}
return new Promise((resolve, reject) => {
resolve(isMuted);
});
} }
export { audioHelp, audioMute, audioUnmute, audioToggle, audioStatus } export {
audioHelp,
audioMute,
audioUnmute,
audioToggle,
audioStatus
}

View File

@ -1,43 +1,43 @@
import meow from "meow"; import meow from 'meow'
import meowHelp from "cli-meow-help"; import meowHelp from 'cli-meow-help'
const commands = { const commands = {
scene: { scene: {
desc: "Manage scenes", desc: 'Manage scenes'
}, },
audio: { audio: {
desc: "Manage audio settings", desc: 'Manage audio settings'
}, },
stream: { stream: {
desc: "Manage streaming", desc: 'Manage streaming'
}, },
record: { record: {
desc: "Manage recording", desc: 'Manage recording'
}, }
}; }
const flags = { const flags = {
help: { help: {
type: "boolean", type: 'boolean',
shortFlag: "h", shortFlag: 'h',
description: "Display help information" description: 'Display help information'
}, },
version: { version: {
type: "boolean", type: 'boolean',
shortFlag: "v", shortFlag: 'v',
description: "Display the version number" description: 'Display the version number'
} }
} }
const helpText = meowHelp({ const helpText = meowHelp({
name: "meld-cli", name: 'meld-cli',
flags, flags,
commands, commands,
description: "A command-line interface for managing scenes in Meld", description: 'A command-line interface for managing scenes in Meld',
defaults: false, defaults: false
}); })
export default meow(helpText, { export default meow(helpText, {
importMeta: import.meta, importMeta: import.meta,
flags, flags
}) })

View File

@ -1,82 +1,87 @@
import meowHelp from "cli-meow-help"; import meowHelp from 'cli-meow-help'
const commands = { const commands = {
start: { start: {
desc: "Start streaming", desc: 'Start streaming'
}, },
stop: { stop: {
desc: "Stop streaming", desc: 'Stop streaming'
}, },
status: { status: {
desc: "Show the current streaming status", desc: 'Show the current streaming status'
}, }
}; }
const flags = { const flags = {
help: { help: {
type: "boolean", type: 'boolean',
shortFlag: "h", shortFlag: 'h',
desc: "Display help information", desc: 'Display help information'
}, }
}; }
const recordHelp = meowHelp({ const recordHelp = meowHelp({
name: "meld-cli record", name: 'meld-cli record',
flags, flags,
commands, commands,
description: "Manage recording in Meld", description: 'Manage recording in Meld',
defaults: false, defaults: false
}); })
function recordStart(channel) { function recordStart (channel) {
if (!channel.objects || !channel.objects.meld) { if (!channel.objects || !channel.objects.meld) {
return Promise.reject(new Error("Meld object not found in channel.")); return Promise.reject(new Error('Meld object not found in channel.'))
} }
const meld = channel.objects.meld; const meld = channel.objects.meld
if (meld.isRecording) { if (meld.isRecording) {
return Promise.reject(new Error("Recording is already active.")); return Promise.reject(new Error('Recording is already active.'))
} }
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
meld.toggleRecord() meld.toggleRecord()
.then(() => { .then(() => {
resolve("Recording started successfully."); resolve('Recording started successfully.')
}) })
.catch((err) => { .catch((err) => {
reject(err); reject(err)
}); })
}); })
} }
function recordStop(channel) { function recordStop (channel) {
if (!channel.objects || !channel.objects.meld) { if (!channel.objects || !channel.objects.meld) {
return Promise.reject(new Error("Meld object not found in channel.")); return Promise.reject(new Error('Meld object not found in channel.'))
} }
const meld = channel.objects.meld; const meld = channel.objects.meld
if (!meld.isRecording) { if (!meld.isRecording) {
return Promise.reject(new Error("Recording is not currently active.")); return Promise.reject(new Error('Recording is not currently active.'))
} }
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
meld.toggleRecord() meld.toggleRecord()
.then(() => { .then(() => {
resolve("Recording stopped successfully."); resolve('Recording stopped successfully.')
}) })
.catch((err) => { .catch((err) => {
reject(err); reject(err)
}); })
}); })
} }
function recordStatus(channel) { function recordStatus (channel) {
if (!channel.objects || !channel.objects.meld) { if (!channel.objects || !channel.objects.meld) {
return Promise.reject(new Error("Meld object not found in channel.")); return Promise.reject(new Error('Meld object not found in channel.'))
} }
const meld = channel.objects.meld; const meld = channel.objects.meld
return Promise.resolve(meld.isRecording); return Promise.resolve(`Recording is currently ${meld.isRecording ? 'active' : 'inactive'}`)
} }
export { recordHelp, recordStart, recordStop, recordStatus }; export {
recordHelp,
recordStart,
recordStop,
recordStatus
}

View File

@ -1,90 +1,104 @@
import meowHelp from "cli-meow-help"; import meowHelp from 'cli-meow-help'
import Table from 'cli-table3'
import { highlight, error, errorHighlight } from './style.js'
const commands = { const commands = {
list: { list: {
desc: "List all scenes", desc: 'List all scenes'
}, },
switch: { switch: {
desc: "Switch to a scene by name", desc: 'Switch to a scene by name'
}, },
current: { current: {
desc: "Show the current scene", desc: 'Show the current scene'
}, }
} }
const flags = { const flags = {
help: { help: {
type: "boolean", type: 'boolean',
shortFlag: "h", shortFlag: 'h',
desc: "Display help information" desc: 'Display help information'
}, }
}; }
const sceneHelp = meowHelp({ const sceneHelp = meowHelp({
name: "meld-cli scene", name: 'meld-cli scene',
flags, flags,
commands, commands,
description: "Manage scenes in Meld", description: 'Manage scenes in Meld',
defaults: false, defaults: false
}); })
function sceneList(channel) { function sceneList (channel) {
if (!channel.objects || !channel.objects.meld) { if (!channel.objects || !channel.objects.meld) {
return Promise.reject(new Error("Meld object not found in channel.")); return Promise.reject(new Error('Meld object not found in channel.'))
} }
const meld = channel.objects.meld; const table = new Table({
const scenes = []; style: {
for (const [key, value] of Object.entries(meld.session.items)) { head: ['none'],
if (value.type === "scene") { compact: true
scenes.push({ name: value.name, id: key }); },
} head: [{ content: 'Scene Name', hAlign: 'center' }, { content: 'ID', hAlign: 'center' }]
})
const meld = channel.objects.meld
for (const [key, value] of Object.entries(meld.session.items)) {
if (value.type === 'scene') {
table.push([highlight(value.name), highlight(key)])
} }
if (scenes.length === 0) { }
return Promise.reject(new Error("No scenes found.")); if (table.length === 0) {
} return Promise.reject(new Error('No scenes found.'))
return Promise.resolve(scenes); }
return Promise.resolve(table.toString())
} }
function sceneSwitch(channel, sceneName) { function sceneSwitch (channel, sceneName) {
if (!channel.objects || !channel.objects.meld) { if (!channel.objects || !channel.objects.meld) {
return Promise.reject(new Error("Meld object not found in channel.")); return Promise.reject(new Error('Meld object not found in channel.'))
} }
const meld = channel.objects.meld; const meld = channel.objects.meld
let itemId; let itemId
for (const [key, value] of Object.entries(meld.session.items)) { for (const [key, value] of Object.entries(meld.session.items)) {
if (value.type === "scene" && value.name === sceneName) { if (value.type === 'scene' && value.name === sceneName) {
itemId = key; itemId = key
break; break
}
}
if (!itemId) {
return Promise.reject(new Error(`Scene "${sceneName}" not found.`));
} }
}
if (!itemId) {
return Promise.reject(new Error(error(`No scene with name ${errorHighlight(sceneName)} found.`)))
}
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
meld.showScene(itemId).then(() => { meld.showScene(itemId).then(() => {
console.log(`Switched to scene: ${sceneName}`); resolve(`Switched to scene: ${highlight(sceneName)}`)
resolve(); }).catch(err => {
}).catch(err => { reject(err)
reject(err); })
}); })
});
} }
function sceneCurrent(channel) { function sceneCurrent (channel) {
if (!channel.objects || !channel.objects.meld) { if (!channel.objects || !channel.objects.meld) {
return Promise.reject(new Error("Meld object not found in channel.")); return Promise.reject(new Error('Meld object not found in channel.'))
} }
const meld = channel.objects.meld; const meld = channel.objects.meld
for (const [key, value] of Object.entries(meld.session.items)) { for (const [key, value] of Object.entries(meld.session.items)) {
if (value.type === "scene" && value.current) { if (value.type === 'scene' && value.current) {
return Promise.resolve({ name: value.name, id: key }); return Promise.resolve(`Current scene: ${highlight(value.name)} (ID: ${highlight(key)})`)
}
} }
return Promise.reject(new Error("No current scene found.")); }
return Promise.reject(new Error('No current scene found.'))
} }
export { sceneHelp, sceneList, sceneSwitch, sceneCurrent }; export {
sceneHelp,
sceneList,
sceneSwitch,
sceneCurrent
}

View File

@ -1,83 +1,87 @@
import meowHelp from "cli-meow-help"; import meowHelp from 'cli-meow-help'
const commands = { const commands = {
start: { start: {
desc: "Start streaming", desc: 'Start streaming'
}, },
stop: { stop: {
desc: "Stop streaming", desc: 'Stop streaming'
}, },
status: { status: {
desc: "Show the current streaming status", desc: 'Show the current streaming status'
}, }
}; }
const flags = { const flags = {
help: { help: {
type: "boolean", type: 'boolean',
shortFlag: "h", shortFlag: 'h',
desc: "Display help information", desc: 'Display help information'
}, }
}; }
const streamHelp = meowHelp({ const streamHelp = meowHelp({
name: "meld-cli stream", name: 'meld-cli stream',
flags, flags,
commands, commands,
description: "Manage streaming in Meld", description: 'Manage streaming in Meld',
defaults: false, defaults: false
}); })
function streamStart(channel) { function streamStart (channel) {
if (!channel.objects || !channel.objects.meld) { if (!channel.objects || !channel.objects.meld) {
return Promise.reject(new Error("Meld object not found in channel.")); return Promise.reject(new Error('Meld object not found in channel.'))
} }
const meld = channel.objects.meld; const meld = channel.objects.meld
if (meld.isStreaming) { if (meld.isStreaming) {
return Promise.reject(new Error("Streaming is already active.")); return Promise.reject(new Error('Streaming is already active.'))
} }
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
meld.toggleStream() meld.toggleStream()
.then(() => { .then(() => {
resolve("Streaming started successfully."); resolve('Streaming started successfully.')
}) })
.catch((err) => { .catch((err) => {
reject(err); reject(err)
}); })
}); })
} }
function streamStop(channel) { function streamStop (channel) {
if (!channel.objects || !channel.objects.meld) { if (!channel.objects || !channel.objects.meld) {
return Promise.reject(new Error("Meld object not found in channel.")); return Promise.reject(new Error('Meld object not found in channel.'))
} }
const meld = channel.objects.meld; const meld = channel.objects.meld
if (!meld.isStreaming) { if (!meld.isStreaming) {
return Promise.reject(new Error("Streaming is not currently active.")); return Promise.reject(new Error('Streaming is not currently active.'))
} }
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
meld.toggleStream() meld.toggleStream()
.then(() => { .then(() => {
resolve("Streaming stopped successfully."); resolve('Streaming stopped successfully.')
}) })
.catch((err) => { .catch((err) => {
reject(err); reject(err)
}); })
}); })
} }
function streamStatus (channel) {
if (!channel.objects || !channel.objects.meld) {
return Promise.reject(new Error('Meld object not found in channel.'))
}
function streamStatus(channel) { const meld = channel.objects.meld
if (!channel.objects || !channel.objects.meld) { return Promise.resolve(`Streaming is currently ${meld.isStreaming ? 'active' : 'inactive'}`)
return Promise.reject(new Error("Meld object not found in channel."));
}
const meld = channel.objects.meld;
return Promise.resolve(meld.isStreaming);
} }
export { streamHelp, streamStart, streamStop, streamStatus }; export {
streamStart,
streamStop,
streamStatus,
streamHelp
}

11
utils/style.js Normal file
View File

@ -0,0 +1,11 @@
import clc from 'cli-color'
const highlight = clc.cyan
const error = clc.red.bold
const errorHighlight = clc.yellow.bold
export {
highlight,
error,
errorHighlight
}