@groovenet/player 0.0.0-stage → 0.1.1

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.
package/README.md CHANGED
@@ -1,3 +1,42 @@
1
- # Temporary Holding Version
1
+ # @groovenet/player
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ UI-free playback core for the Groovenet collection player. It keeps queue and
4
+ playback state independent of a terminal interface and exposes a replaceable
5
+ `PlaybackBackend`; `MpvBackend` is the first backend and communicates with a
6
+ locally installed `mpv` process over its JSON IPC socket.
7
+
8
+ ```ts
9
+ import { GroovenetClient, loadConfig } from "@groovenet/client";
10
+ import { MpvBackend, PlayerCore, TrackResolver } from "@groovenet/player";
11
+
12
+ const config = loadConfig();
13
+ const client = new GroovenetClient({
14
+ baseUrl: config.api_base,
15
+ apiKey: config.api_key,
16
+ insecureTls: config.insecure_tls,
17
+ clientName: "cli",
18
+ });
19
+ const resolver = new TrackResolver(client, { apiBase: config.api_base, apiKey: config.api_key });
20
+ const player = new PlayerCore(
21
+ new MpvBackend({ insecureTls: config.insecure_tls }),
22
+ resolver
23
+ );
24
+ await player.enqueueSearch("Cumbia");
25
+ // Or enqueue a playlist in its saved order:
26
+ // await player.enqueuePlaylist(42);
27
+ await player.play();
28
+ ```
29
+
30
+ The resolver turns `local_audio_url` into the server's range-capable
31
+ `/api/audio?filename=…` endpoint and passes the configured bearer key to mpv.
32
+ Tracks without downloaded audio are skipped with a typed `NO_AUDIO` error.
33
+ `insecureTls` is forwarded as mpv's `--tls-verify=no` setting for installations
34
+ using a self-signed server certificate.
35
+
36
+ `MpvBackend` does not install mpv. Install it separately and make it available
37
+ on `PATH`, or pass an executable path in the constructor. `close()` stops the
38
+ owned process. The `TestPlaybackBackend` from `@groovenet/player/testing` is a small in-memory
39
+ implementation for consumers that need to exercise the core without audio.
40
+
41
+ Build with `npm run build --workspace=@groovenet/player` after building
42
+ `@groovenet/client`.
@@ -0,0 +1,39 @@
1
+ import { createServer, type Socket } from "node:net";
2
+ import type { PlayerCore } from "./player.js";
3
+ export interface PlayerDaemonPaths {
4
+ socketPath: string;
5
+ pidPath: string;
6
+ }
7
+ export interface PlayerDaemonOptions {
8
+ player: PlayerCore;
9
+ paths: PlayerDaemonPaths;
10
+ createServer?: typeof createServer;
11
+ connectSocket?: (path: string) => Socket;
12
+ isProcessAlive?: (pid: number) => boolean;
13
+ }
14
+ /** Owns the control socket and pidfile for a headless PlayerCore process. */
15
+ export declare class PlayerDaemon {
16
+ private readonly options;
17
+ private server;
18
+ private readonly clients;
19
+ private readonly createServer;
20
+ private readonly connectSocket;
21
+ private readonly isProcessAlive;
22
+ private stopped;
23
+ private lastSnapshot;
24
+ private readonly broadcastChange;
25
+ private readonly broadcastTrackStart;
26
+ private readonly broadcastTrackEnd;
27
+ private readonly broadcastTrackSkip;
28
+ constructor(options: PlayerDaemonOptions);
29
+ start(): Promise<void>;
30
+ stop(): Promise<void>;
31
+ private recoverStaleFiles;
32
+ private socketIsActive;
33
+ private accept;
34
+ private handleLine;
35
+ private dispatch;
36
+ private numberParam;
37
+ private broadcast;
38
+ }
39
+ //# sourceMappingURL=daemon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,YAAY,EAAe,KAAK,MAAM,EAAE,MAAM,UAAU,CAAC;AAGpF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAI9C,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,iBAAiB,CAAC;IACzB,YAAY,CAAC,EAAE,OAAO,YAAY,CAAC;IACnC,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACzC,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;CAC3C;AAED,6EAA6E;AAC7E,qBAAa,YAAY;IAoBX,OAAO,CAAC,QAAQ,CAAC,OAAO;IAnBpC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAsB;IACnD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA2B;IACzD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA2B;IAC1D,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,YAAY,CAAU;IAC9B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAO9B;IACF,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAA6D;IACjG,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA4D;IAC9F,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAiF;gBAEvF,OAAO,EAAE,mBAAmB;IAQnD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAoBb,iBAAiB;YAejB,cAAc;IAiB5B,OAAO,CAAC,MAAM;YAeA,UAAU;YAyBV,QAAQ;IAgDtB,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,SAAS;CAIlB"}
@@ -0,0 +1,236 @@
1
+ import { createConnection, createServer } from "node:net";
2
+ import { mkdir, readFile, unlink, writeFile } from "node:fs/promises";
3
+ import { dirname } from "node:path";
4
+ import { encodeRpcEvent, encodeRpcResponse, PLAYER_PROTOCOL_VERSION } from "./protocol.js";
5
+ /** Owns the control socket and pidfile for a headless PlayerCore process. */
6
+ export class PlayerDaemon {
7
+ options;
8
+ server = null;
9
+ clients = new Set();
10
+ createServer;
11
+ connectSocket;
12
+ isProcessAlive;
13
+ stopped = false;
14
+ lastSnapshot;
15
+ broadcastChange = (snapshot) => {
16
+ const current = snapshot;
17
+ const previous = this.lastSnapshot;
18
+ this.broadcast("state", snapshot);
19
+ if (current.position !== previous?.position || current.duration !== previous?.duration)
20
+ this.broadcast("position", { position: current.position, duration: current.duration });
21
+ if (JSON.stringify(current.queue) !== JSON.stringify(previous?.queue))
22
+ this.broadcast("queue-change", current.queue);
23
+ this.lastSnapshot = snapshot;
24
+ };
25
+ broadcastTrackStart = (entry) => this.broadcast("track-change", entry);
26
+ broadcastTrackEnd = (entry) => this.broadcast("track-ended", entry);
27
+ broadcastTrackSkip = (entry, error) => this.broadcast("error", { entry, error });
28
+ constructor(options) {
29
+ this.options = options;
30
+ this.createServer = options.createServer ?? createServer;
31
+ this.connectSocket = options.connectSocket ?? createConnection;
32
+ this.isProcessAlive = options.isProcessAlive ?? ((pid) => {
33
+ try {
34
+ process.kill(pid, 0);
35
+ return true;
36
+ }
37
+ catch (error) {
38
+ return error.code === "EPERM";
39
+ }
40
+ });
41
+ }
42
+ async start() {
43
+ await mkdir(dirname(this.options.paths.socketPath), { recursive: true, mode: 0o700 });
44
+ await this.recoverStaleFiles();
45
+ const server = this.createServer((socket) => this.accept(socket));
46
+ this.server = server;
47
+ await new Promise((resolve, reject) => {
48
+ const onError = (error) => { server.off("listening", onListening); reject(error); };
49
+ const onListening = () => { server.off("error", onError); resolve(); };
50
+ server.once("error", onError);
51
+ server.once("listening", onListening);
52
+ server.listen(this.options.paths.socketPath);
53
+ });
54
+ await writeFile(this.options.paths.pidPath, `${process.pid}\n`, { mode: 0o600 });
55
+ this.options.player.on("change", this.broadcastChange);
56
+ this.options.player.on("track-started", this.broadcastTrackStart);
57
+ this.options.player.on("track-ended", this.broadcastTrackEnd);
58
+ this.options.player.on("track-skipped", this.broadcastTrackSkip);
59
+ }
60
+ async stop() {
61
+ if (this.stopped)
62
+ return;
63
+ this.stopped = true;
64
+ this.options.player.off("change", this.broadcastChange);
65
+ this.options.player.off("track-started", this.broadcastTrackStart);
66
+ this.options.player.off("track-ended", this.broadcastTrackEnd);
67
+ this.options.player.off("track-skipped", this.broadcastTrackSkip);
68
+ for (const socket of this.clients)
69
+ socket.destroy();
70
+ this.clients.clear();
71
+ if (this.server?.listening) {
72
+ await new Promise((resolve) => this.server.close(() => resolve()));
73
+ }
74
+ this.server = null;
75
+ await this.options.player.close();
76
+ await Promise.all([
77
+ unlink(this.options.paths.socketPath).catch(() => undefined),
78
+ unlink(this.options.paths.pidPath).catch(() => undefined),
79
+ ]);
80
+ }
81
+ async recoverStaleFiles() {
82
+ let pid = null;
83
+ try {
84
+ const parsed = Number.parseInt(await readFile(this.options.paths.pidPath, "utf8"), 10);
85
+ if (Number.isInteger(parsed) && parsed > 0)
86
+ pid = parsed;
87
+ }
88
+ catch { /* no pidfile */ }
89
+ if (pid !== null && this.isProcessAlive(pid) && await this.socketIsActive()) {
90
+ throw new Error(`Player daemon already appears to be running (pid ${pid}).`);
91
+ }
92
+ await Promise.all([
93
+ unlink(this.options.paths.pidPath).catch(() => undefined),
94
+ unlink(this.options.paths.socketPath).catch(() => undefined),
95
+ ]);
96
+ }
97
+ async socketIsActive() {
98
+ return new Promise((resolve) => {
99
+ let settled = false;
100
+ const socket = this.connectSocket(this.options.paths.socketPath);
101
+ const finish = (active) => {
102
+ if (settled)
103
+ return;
104
+ settled = true;
105
+ clearTimeout(timer);
106
+ socket.destroy();
107
+ resolve(active);
108
+ };
109
+ const timer = setTimeout(() => finish(false), 250);
110
+ socket.once("connect", () => finish(true));
111
+ socket.once("error", () => finish(false));
112
+ });
113
+ }
114
+ accept(socket) {
115
+ this.clients.add(socket);
116
+ let buffer = "";
117
+ socket.on("data", (chunk) => {
118
+ buffer += chunk.toString("utf8");
119
+ let newline;
120
+ while ((newline = buffer.indexOf("\n")) >= 0) {
121
+ const line = buffer.slice(0, newline);
122
+ buffer = buffer.slice(newline + 1);
123
+ void this.handleLine(socket, line);
124
+ }
125
+ });
126
+ socket.on("close", () => this.clients.delete(socket));
127
+ }
128
+ async handleLine(socket, line) {
129
+ let request;
130
+ try {
131
+ request = JSON.parse(line);
132
+ }
133
+ catch {
134
+ socket.write(encodeRpcResponse({ version: PLAYER_PROTOCOL_VERSION, id: 0, error: { code: "INVALID_REQUEST", message: "Request must be a JSON object." } }));
135
+ return;
136
+ }
137
+ if (!Number.isInteger(request.id))
138
+ return;
139
+ if (request.jsonrpc !== "2.0") {
140
+ socket.write(encodeRpcResponse({ version: PLAYER_PROTOCOL_VERSION, id: request.id, error: { code: "INVALID_REQUEST", message: "Expected JSON-RPC version 2.0." } }));
141
+ return;
142
+ }
143
+ if (request.version !== PLAYER_PROTOCOL_VERSION) {
144
+ socket.write(encodeRpcResponse({ version: PLAYER_PROTOCOL_VERSION, id: request.id, error: { code: "VERSION_MISMATCH", message: `Unsupported player protocol version ${request.version}; this daemon supports version ${PLAYER_PROTOCOL_VERSION}.` } }));
145
+ return;
146
+ }
147
+ try {
148
+ const result = await this.dispatch(request.method, request.params ?? {});
149
+ socket.write(encodeRpcResponse({ version: PLAYER_PROTOCOL_VERSION, id: request.id, result }));
150
+ }
151
+ catch (error) {
152
+ const code = typeof error === "object" && error !== null && "code" in error ? String(error.code) : "PLAYER_ERROR";
153
+ const message = error instanceof Error ? error.message : String(error);
154
+ socket.write(encodeRpcResponse({ version: PLAYER_PROTOCOL_VERSION, id: request.id, error: { code, message } }));
155
+ }
156
+ }
157
+ async dispatch(method, params) {
158
+ const player = this.options.player;
159
+ switch (method) {
160
+ case "status": return player.snapshot;
161
+ case "play":
162
+ if (params.index !== undefined && (typeof params.index !== "number" || !Number.isInteger(params.index) || params.index < 0)) {
163
+ throw new Error("Playback index must be a non-negative integer.");
164
+ }
165
+ if (player.snapshot.status === "paused" && params.index === undefined)
166
+ await player.resume();
167
+ else
168
+ await player.play(typeof params.index === "number" ? params.index : undefined);
169
+ return player.snapshot;
170
+ case "pause":
171
+ await player.pause();
172
+ return player.snapshot;
173
+ case "resume":
174
+ await player.resume();
175
+ return player.snapshot;
176
+ case "next":
177
+ await player.next();
178
+ return player.snapshot;
179
+ case "prev":
180
+ await player.previous();
181
+ return player.snapshot;
182
+ case "seek":
183
+ await player.seek(this.numberParam(params, "seconds"));
184
+ return player.snapshot;
185
+ case "volume":
186
+ await player.setVolume(this.numberParam(params, "volume"));
187
+ return player.snapshot;
188
+ case "queue.list": return player.snapshot.queue;
189
+ case "queue.remove": {
190
+ const key = params.id ?? params.index;
191
+ if (typeof key !== "string" && typeof key !== "number")
192
+ throw new Error("Queue remove requires an id or index.");
193
+ const removed = player.remove(key);
194
+ if (!removed)
195
+ throw new Error(`No queue entry found for ${key}.`);
196
+ return removed;
197
+ }
198
+ case "devices": return player.listDevices();
199
+ case "devices.select": {
200
+ if (typeof params.id !== "string" || !params.id)
201
+ throw new Error("Device selection requires an id.");
202
+ await player.setOutputDevice(params.id);
203
+ return player.listDevices();
204
+ }
205
+ case "queue.add": {
206
+ if (typeof params.playlistId === "string" || typeof params.playlistId === "number")
207
+ return player.enqueuePlaylist(params.playlistId);
208
+ if (typeof params.query !== "string" || !params.query.trim())
209
+ throw new Error("Queue add requires a search query or playlist id.");
210
+ return player.enqueueSearch(params.query);
211
+ }
212
+ case "queue.addTrack": {
213
+ if (typeof params.track !== "object" || params.track === null || Array.isArray(params.track))
214
+ throw new Error("Queue add requires a track object.");
215
+ return player.add([params.track]);
216
+ }
217
+ case "shutdown": {
218
+ setImmediate(() => { void this.stop(); });
219
+ return { stopping: true };
220
+ }
221
+ default: throw new Error(`Unknown player command “${method}”.`);
222
+ }
223
+ }
224
+ numberParam(params, key) {
225
+ if (typeof params[key] !== "number" || !Number.isFinite(params[key]))
226
+ throw new Error(`${key} must be a number.`);
227
+ return params[key];
228
+ }
229
+ broadcast(event, data) {
230
+ const line = encodeRpcEvent(event, data);
231
+ for (const client of this.clients)
232
+ if (client.writable)
233
+ client.write(line);
234
+ }
235
+ }
236
+ //# sourceMappingURL=daemon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon.js","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export * from "./types.js";
2
+ export * from "./queue.js";
3
+ export * from "./resolver.js";
4
+ export * from "./player.js";
5
+ export * from "./mpvBackend.js";
6
+ export * from "./protocol.js";
7
+ export * from "./daemon.js";
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC"}
package/build/index.js ADDED
@@ -0,0 +1,8 @@
1
+ export * from "./types.js";
2
+ export * from "./queue.js";
3
+ export * from "./resolver.js";
4
+ export * from "./player.js";
5
+ export * from "./mpvBackend.js";
6
+ export * from "./protocol.js";
7
+ export * from "./daemon.js";
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC"}
@@ -0,0 +1,55 @@
1
+ import { type ChildProcess } from "node:child_process";
2
+ import { EventEmitter } from "node:events";
3
+ import { type Socket } from "node:net";
4
+ import type { AudioDevice, PlaybackBackend, PlaybackBackendEvents, PlaybackSource } from "./types.js";
5
+ export interface MpvBackendOptions {
6
+ executable?: string;
7
+ insecureTls?: boolean;
8
+ startupTimeoutMs?: number;
9
+ commandTimeoutMs?: number;
10
+ /** Injectable process and IPC transport for deterministic backend tests. */
11
+ spawnProcess?: (executable: string, args: string[]) => ChildProcess;
12
+ connectSocket?: (path: string) => Socket;
13
+ }
14
+ /** mpv child process controlled through its line-delimited JSON IPC socket. */
15
+ export declare class MpvBackend extends EventEmitter implements PlaybackBackend {
16
+ private process;
17
+ private socket;
18
+ private socketPath;
19
+ private buffer;
20
+ private nextId;
21
+ private pending;
22
+ private startup;
23
+ private closing;
24
+ private spawnError;
25
+ private readonly executable;
26
+ private readonly startupTimeoutMs;
27
+ private readonly commandTimeoutMs;
28
+ private readonly spawnProcess;
29
+ private readonly connectSocket;
30
+ private duration;
31
+ constructor(options?: MpvBackendOptions);
32
+ private readonly insecureTls;
33
+ on(event: string | symbol, listener: (...args: any[]) => void): this;
34
+ on<E extends keyof PlaybackBackendEvents>(event: E, listener: PlaybackBackendEvents[E]): this;
35
+ off(event: string | symbol, listener: (...args: any[]) => void): this;
36
+ off<E extends keyof PlaybackBackendEvents>(event: E, listener: PlaybackBackendEvents[E]): this;
37
+ load(source: PlaybackSource): Promise<void>;
38
+ pause(paused: boolean): Promise<void>;
39
+ seek(seconds: number): Promise<void>;
40
+ setVolume(volume: number): Promise<void>;
41
+ listDevices(): Promise<AudioDevice[]>;
42
+ setOutputDevice(deviceId: string): Promise<void>;
43
+ close(): Promise<void>;
44
+ private ensureStarted;
45
+ private startMpv;
46
+ private connect;
47
+ private command;
48
+ private onData;
49
+ private onEvent;
50
+ private mapMpvError;
51
+ private rejectPending;
52
+ private cleanupAfterStartupFailure;
53
+ private reportError;
54
+ }
55
+ //# sourceMappingURL=mpvBackend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mpvBackend.d.ts","sourceRoot":"","sources":["../src/mpvBackend.ts"],"names":[],"mappings":"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"}