@raphiiko/wavelink-cli 0.0.5 → 0.0.7

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,24 @@
1
+ import { WaveLinkClient } from "@raphiiko/wavelink-ts";
2
+
3
+ export async function withClient<T>(action: (client: WaveLinkClient) => Promise<T>): Promise<T> {
4
+ const client = new WaveLinkClient({
5
+ autoReconnect: false,
6
+ });
7
+
8
+ try {
9
+ console.log("Connecting to Wave Link...");
10
+ await client.connect();
11
+ console.log("Connected successfully");
12
+
13
+ return await action(client);
14
+ } catch (error) {
15
+ if (error instanceof Error) {
16
+ console.error(`Error: ${error.message}`);
17
+ } else {
18
+ console.error("An unexpected error occurred");
19
+ }
20
+ process.exit(1);
21
+ } finally {
22
+ client.disconnect();
23
+ }
24
+ }
@@ -0,0 +1,150 @@
1
+ import { WaveLinkClient } from "@raphiiko/wavelink-ts";
2
+ import type { MixInfo, OutputInfo, InputInfo, ChannelInfo } from "../types/index.js";
3
+ import { exitWithError } from "../utils/error.js";
4
+ import { getChannelName } from "../utils/format.js";
5
+
6
+ export async function findMixByIdOrName(
7
+ client: WaveLinkClient,
8
+ idOrName: string
9
+ ): Promise<MixInfo | null> {
10
+ const { mixes } = await client.getMixes();
11
+ const lowerIdOrName = idOrName.toLowerCase();
12
+ const mix = mixes.find(
13
+ (m) => m.id.toLowerCase() === lowerIdOrName || (m.name || "").toLowerCase() === lowerIdOrName
14
+ );
15
+ return mix ? { id: mix.id, name: mix.name || mix.id } : null;
16
+ }
17
+
18
+ export async function findChannelByIdOrName(
19
+ client: WaveLinkClient,
20
+ idOrName: string
21
+ ): Promise<ChannelInfo | null> {
22
+ const { channels } = await client.getChannels();
23
+ const lowerIdOrName = idOrName.toLowerCase();
24
+
25
+ // First try exact ID match
26
+ const channelById = channels.find((c) => c.id.toLowerCase() === lowerIdOrName);
27
+ if (channelById) {
28
+ return { id: channelById.id, name: getChannelName(channelById) };
29
+ }
30
+
31
+ // Then try name match (checking both channel.name and channel.image.name)
32
+ const channelByName = channels.find((c) => {
33
+ const name = getChannelName(c);
34
+ return name.toLowerCase() === lowerIdOrName;
35
+ });
36
+
37
+ return channelByName ? { id: channelByName.id, name: getChannelName(channelByName) } : null;
38
+ }
39
+
40
+ export async function findInputByIdOrName(
41
+ client: WaveLinkClient,
42
+ idOrName: string
43
+ ): Promise<InputInfo | null> {
44
+ const { inputDevices } = await client.getInputDevices();
45
+ const lowerIdOrName = idOrName.toLowerCase();
46
+
47
+ // First try exact ID match
48
+ for (const device of inputDevices) {
49
+ const input = device.inputs.find((i) => i.id.toLowerCase() === lowerIdOrName);
50
+ if (input) {
51
+ return {
52
+ deviceId: device.id,
53
+ deviceName: device.name || device.id,
54
+ inputId: input.id,
55
+ inputName: input.name || input.id,
56
+ gain: input.gain.value,
57
+ isMuted: input.isMuted,
58
+ };
59
+ }
60
+ }
61
+
62
+ // Then try name match
63
+ for (const device of inputDevices) {
64
+ const input = device.inputs.find((i) => (i.name || "").toLowerCase() === lowerIdOrName);
65
+ if (input) {
66
+ return {
67
+ deviceId: device.id,
68
+ deviceName: device.name || device.id,
69
+ inputId: input.id,
70
+ inputName: input.name || input.id,
71
+ gain: input.gain.value,
72
+ isMuted: input.isMuted,
73
+ };
74
+ }
75
+ }
76
+
77
+ return null;
78
+ }
79
+
80
+ export async function findOutputByIdOrName(
81
+ client: WaveLinkClient,
82
+ idOrName: string
83
+ ): Promise<OutputInfo | null> {
84
+ const { outputDevices } = await client.getOutputDevices();
85
+ const lowerIdOrName = idOrName.toLowerCase();
86
+
87
+ // First try exact ID match
88
+ for (const device of outputDevices) {
89
+ const output = device.outputs.find((o) => o.id.toLowerCase() === lowerIdOrName);
90
+ if (output) {
91
+ return {
92
+ deviceId: device.id,
93
+ outputId: output.id,
94
+ currentMixId: output.mixId,
95
+ deviceName: device.name || device.id,
96
+ isWaveDevice: device.isWaveDevice,
97
+ outputName: output.name || output.id,
98
+ level: output.level,
99
+ isMuted: output.isMuted,
100
+ };
101
+ }
102
+ }
103
+
104
+ // Then try name match
105
+ for (const device of outputDevices) {
106
+ const output = device.outputs.find((o) => (o.name || "").toLowerCase() === lowerIdOrName);
107
+ if (output) {
108
+ return {
109
+ deviceId: device.id,
110
+ outputId: output.id,
111
+ currentMixId: output.mixId,
112
+ deviceName: device.name || device.id,
113
+ isWaveDevice: device.isWaveDevice,
114
+ outputName: output.name || output.id,
115
+ level: output.level,
116
+ isMuted: output.isMuted,
117
+ };
118
+ }
119
+ }
120
+
121
+ return null;
122
+ }
123
+
124
+ // Required finder wrappers that exit on not found
125
+ export async function requireMix(client: WaveLinkClient, mixId: string): Promise<MixInfo> {
126
+ const mix = await findMixByIdOrName(client, mixId);
127
+ if (!mix) exitWithError(`Mix '${mixId}' not found`);
128
+ return mix;
129
+ }
130
+
131
+ export async function requireOutput(client: WaveLinkClient, outputId: string): Promise<OutputInfo> {
132
+ const output = await findOutputByIdOrName(client, outputId);
133
+ if (!output) exitWithError(`Output '${outputId}' not found`);
134
+ return output;
135
+ }
136
+
137
+ export async function requireInput(client: WaveLinkClient, inputId: string): Promise<InputInfo> {
138
+ const input = await findInputByIdOrName(client, inputId);
139
+ if (!input) exitWithError(`Input '${inputId}' not found`);
140
+ return input;
141
+ }
142
+
143
+ export async function requireChannel(
144
+ client: WaveLinkClient,
145
+ channelId: string
146
+ ): Promise<ChannelInfo> {
147
+ const channel = await findChannelByIdOrName(client, channelId);
148
+ if (!channel) exitWithError(`Channel '${channelId}' not found`);
149
+ return channel;
150
+ }
@@ -0,0 +1,23 @@
1
+ export type MixInfo = { id: string; name: string };
2
+
3
+ export type OutputInfo = {
4
+ deviceId: string;
5
+ outputId: string;
6
+ currentMixId: string;
7
+ deviceName: string;
8
+ isWaveDevice: boolean;
9
+ outputName: string;
10
+ level: number;
11
+ isMuted: boolean;
12
+ };
13
+
14
+ export type InputInfo = {
15
+ deviceId: string;
16
+ deviceName: string;
17
+ inputId: string;
18
+ inputName: string;
19
+ gain: number;
20
+ isMuted: boolean;
21
+ };
22
+
23
+ export type ChannelInfo = { id: string; name: string };
@@ -0,0 +1,4 @@
1
+ export function exitWithError(message: string): never {
2
+ console.error(`Error: ${message}`);
3
+ process.exit(1);
4
+ }
@@ -0,0 +1,15 @@
1
+ export function formatPercent(value: number): string {
2
+ return `${(value * 100).toFixed(0)}%`;
3
+ }
4
+
5
+ export function formatMuted(isMuted: boolean): string {
6
+ return isMuted ? "Yes" : "No";
7
+ }
8
+
9
+ export function getChannelName(channel: {
10
+ id: string;
11
+ name?: string;
12
+ image?: { name?: string };
13
+ }): string {
14
+ return channel.name ?? channel.image?.name ?? channel.id;
15
+ }
@@ -0,0 +1,9 @@
1
+ import { exitWithError } from "./error.js";
2
+
3
+ export function parsePercent(value: string, name: string): number {
4
+ const percent = parseInt(value, 10);
5
+ if (isNaN(percent) || percent < 0 || percent > 100) {
6
+ exitWithError(`${name} must be a number between 0 and 100`);
7
+ }
8
+ return percent;
9
+ }