@raphiiko/wavelink-cli 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,207 @@
1
+ import { WaveLinkClient } from "@raphiiko/wavelink-ts";
2
+ import { Argument, Command } from "commander";
3
+ import { withClient } from "../services/client.js";
4
+ import { requireOutput, requireMix } from "../services/finders.js";
5
+ import { formatPercent, formatMuted } from "../utils/format.js";
6
+ import { parsePercent } from "../utils/validation.js";
7
+
8
+ export async function setOutputVolume(
9
+ client: WaveLinkClient,
10
+ outputId: string,
11
+ volumePercent: number
12
+ ): Promise<void> {
13
+ const output = await requireOutput(client, outputId);
14
+ await client.setOutputVolume(output.deviceId, output.outputId, volumePercent / 100);
15
+ console.log(`Successfully set output '${output.outputName}' volume to ${volumePercent}%`);
16
+ }
17
+
18
+ export async function setOutputMute(
19
+ client: WaveLinkClient,
20
+ outputId: string,
21
+ isMuted: boolean
22
+ ): Promise<void> {
23
+ const output = await requireOutput(client, outputId);
24
+ await client.setOutputDevice({
25
+ outputDevice: { id: output.deviceId, outputs: [{ id: output.outputId, isMuted }] },
26
+ });
27
+ console.log(`Successfully ${isMuted ? "muted" : "unmuted"} output '${output.outputName}'`);
28
+ }
29
+
30
+ export async function listOutputs(client: WaveLinkClient): Promise<void> {
31
+ const { outputDevices, mainOutput } = await client.getOutputDevices();
32
+ const { mixes } = await client.getMixes();
33
+
34
+ console.log("\n=== Output Devices ===\n");
35
+
36
+ if (outputDevices.length === 0) {
37
+ console.log("No output devices found.");
38
+ return;
39
+ }
40
+
41
+ for (const device of outputDevices) {
42
+ const isMain = device.id === mainOutput ? " (MAIN OUTPUT)" : "";
43
+ console.log(`Device: ${device.name || device.id}${isMain}`);
44
+ console.log(` Device ID: ${device.id}`);
45
+ console.log(` Wave Device: ${formatMuted(device.isWaveDevice)}`);
46
+
47
+ if (device.outputs.length === 0) {
48
+ console.log(" No outputs available");
49
+ } else {
50
+ for (const output of device.outputs) {
51
+ const mix = mixes.find((m) => m.id === output.mixId);
52
+ const mixDisplay = output.mixId
53
+ ? `${mix?.name ?? output.mixId} (${output.mixId})`
54
+ : "Not assigned";
55
+ console.log(` Output: ${output.name || output.id}`);
56
+ console.log(` Output ID: ${output.id}`);
57
+ console.log(` Current Mix: ${mixDisplay}`);
58
+ console.log(` Level: ${formatPercent(output.level)}`);
59
+ console.log(` Muted: ${formatMuted(output.isMuted)}`);
60
+ }
61
+ }
62
+ console.log();
63
+ }
64
+ }
65
+
66
+ export async function assignOutputToMix(
67
+ client: WaveLinkClient,
68
+ outputId: string,
69
+ mixId: string
70
+ ): Promise<void> {
71
+ const mix = await requireMix(client, mixId);
72
+ const output = await requireOutput(client, outputId);
73
+
74
+ if (output.currentMixId === mix.id) {
75
+ console.log(`Output '${output.outputName}' is already assigned to mix '${mix.name}'`);
76
+ return;
77
+ }
78
+
79
+ await client.switchOutputMix(output.deviceId, output.outputId, mix.id);
80
+ console.log(`Successfully assigned output '${output.outputName}' to mix '${mix.name}'`);
81
+ }
82
+
83
+ export async function unassignOutputDevice(
84
+ client: WaveLinkClient,
85
+ outputId: string
86
+ ): Promise<void> {
87
+ const output = await requireOutput(client, outputId);
88
+ await client.removeOutputFromMix(output.deviceId, output.outputId);
89
+ console.log(`Successfully unassigned output '${output.outputName}'`);
90
+ }
91
+
92
+ export async function setSingleOutputForMix(
93
+ client: WaveLinkClient,
94
+ outputId: string,
95
+ mixId: string
96
+ ): Promise<void> {
97
+ const mix = await requireMix(client, mixId);
98
+ const targetOutput = await requireOutput(client, outputId);
99
+
100
+ const { outputDevices } = await client.getOutputDevices();
101
+
102
+ let outputsRemoved = 0;
103
+ let targetOutputAssigned = false;
104
+
105
+ for (const device of outputDevices) {
106
+ for (const output of device.outputs) {
107
+ const isTargetOutput =
108
+ device.id === targetOutput.deviceId && output.id === targetOutput.outputId;
109
+
110
+ if (isTargetOutput && output.mixId !== mix.id) {
111
+ await client.switchOutputMix(device.id, output.id, mix.id);
112
+ targetOutputAssigned = true;
113
+ } else if (!isTargetOutput && output.mixId === mix.id) {
114
+ await client.removeOutputFromMix(device.id, output.id);
115
+ outputsRemoved++;
116
+ }
117
+ }
118
+ }
119
+
120
+ if (targetOutputAssigned && outputsRemoved > 0) {
121
+ console.log(
122
+ `Successfully set '${targetOutput.outputName}' as the only output for mix '${mix.name}' ` +
123
+ `(removed ${outputsRemoved} other output(s) from the mix)`
124
+ );
125
+ } else if (targetOutputAssigned) {
126
+ console.log(
127
+ `Successfully assigned '${targetOutput.outputName}' to mix '${mix.name}' ` +
128
+ `(it is now the only output on this mix)`
129
+ );
130
+ } else if (outputsRemoved > 0) {
131
+ console.log(
132
+ `'${targetOutput.outputName}' was already assigned to mix '${mix.name}'. ` +
133
+ `Removed ${outputsRemoved} other output(s) from the mix.`
134
+ );
135
+ } else {
136
+ console.log(`'${targetOutput.outputName}' is already the only output for mix '${mix.name}'`);
137
+ }
138
+ }
139
+
140
+ export function registerOutputCommands(program: Command): void {
141
+ const outputCmd = program.command("output").description("Manage output devices");
142
+
143
+ outputCmd
144
+ .command("list")
145
+ .description("List all output devices with their IDs and current mix assignments")
146
+ .action(() => withClient(listOutputs));
147
+
148
+ outputCmd
149
+ .command("assign")
150
+ .description("Assign an output device to a specific mix")
151
+ .addArgument(
152
+ new Argument("<output-id-or-name>", "ID or name of the output device (case-insensitive)")
153
+ )
154
+ .addArgument(new Argument("<mix-id-or-name>", "ID or name of the mix (case-insensitive)"))
155
+ .action((outputId: string, mixId: string) =>
156
+ withClient((client) => assignOutputToMix(client, outputId, mixId))
157
+ );
158
+
159
+ outputCmd
160
+ .command("unassign")
161
+ .description("Unassign an output device from its current mix")
162
+ .addArgument(
163
+ new Argument("<output-id-or-name>", "ID or name of the output device (case-insensitive)")
164
+ )
165
+ .action((outputId: string) => withClient((client) => unassignOutputDevice(client, outputId)));
166
+
167
+ outputCmd
168
+ .command("set-volume")
169
+ .description("Set output device volume")
170
+ .addArgument(
171
+ new Argument("<output-id-or-name>", "ID or name of the output device (case-insensitive)")
172
+ )
173
+ .addArgument(new Argument("<volume>", "Volume level (0-100)"))
174
+ .action((outputId: string, volume: string) => {
175
+ const volumePercent = parsePercent(volume, "Volume");
176
+ return withClient((client) => setOutputVolume(client, outputId, volumePercent));
177
+ });
178
+
179
+ outputCmd
180
+ .command("mute")
181
+ .description("Mute an output device")
182
+ .addArgument(
183
+ new Argument("<output-id-or-name>", "ID or name of the output device (case-insensitive)")
184
+ )
185
+ .action((outputId: string) => withClient((client) => setOutputMute(client, outputId, true)));
186
+
187
+ outputCmd
188
+ .command("unmute")
189
+ .description("Unmute an output device")
190
+ .addArgument(
191
+ new Argument("<output-id-or-name>", "ID or name of the output device (case-insensitive)")
192
+ )
193
+ .action((outputId: string) => withClient((client) => setOutputMute(client, outputId, false)));
194
+
195
+ outputCmd
196
+ .command("toggle-mute")
197
+ .description("Toggle output device mute state")
198
+ .addArgument(
199
+ new Argument("<output-id-or-name>", "ID or name of the output device (case-insensitive)")
200
+ )
201
+ .action((outputId: string) =>
202
+ withClient(async (client) => {
203
+ const output = await requireOutput(client, outputId);
204
+ await setOutputMute(client, outputId, !output.isMuted);
205
+ })
206
+ );
207
+ }