Connect to a Music Player Daemon (MPD) server, send commands, and receive events.
This library is a re-write version of the original mpd.js (mpd2) library, fully implemented in TypeScript and leveraging the Web Streams API. This design allows for efficient, non-blocking handling of MPD responses with multiple connections, even for large music libraries or playlists.
# from npm registry (recommended)
npm install @prokosna/mpd3The package is also installable directly from GitHub for users that prefer pinning to a tag:
npm install github:prokosna/mpd.js#2.0.0import { Client, Parsers } from "@prokosna/mpd3";
async function main() {
// Connect to MPD server (defaults to localhost:6600)
const client = await Client.connect({
host: "localhost",
port: 6600,
});
try {
console.log("Connected to MPD!");
console.log();
// Get current status - using sendCommand
const status = await client.sendCommand("status");
console.log("Status:", status);
console.log();
// Get current playlist info as a stream - using streamCommands
// This is a raw stream of lines fetched from MPD.
// OK and ACK are handled by stream's end and error events.
const playlistInfoStream = await client.streamCommands(["playlistinfo"]);
// Transform the stream into a list of objects
const playlistInfoListStream = playlistInfoStream.pipeThrough(
Parsers.transformToList({ delimiterKeys: "file" })
);
// Transform the list of objects into a typed list
const playlistInfoTypedListStream = playlistInfoListStream.pipeThrough(
Parsers.transformToTyped()
);
// Aggregate the list into an array
const playlistInfo = await Parsers.aggregateToList(
playlistInfoTypedListStream
);
console.log("Playlist Info (Count):", playlistInfo.length); // Result is an array of track objects
console.log();
// Other transforms are available in Parsers
const listAllInfo = await client
.streamCommand("listallinfo")
.then((stream) =>
stream
.pipeThrough(
Parsers.transformToListAndAccumulate({
delimiterKeys: ["directory", "file"],
})
)
.pipeThrough(Parsers.transformToTyped())
)
.then(Parsers.aggregateToList);
console.log("List All Info (Count):", listAllInfo.length); // Result is an array of track objects
console.log();
// Get object from stream
const stats = await client
.streamCommand("stats")
.then((stream) => stream.pipeThrough(Parsers.transformToObject()))
.then(Parsers.takeFirstObject);
console.log("Stats:", stats);
console.log();
// Listen for events
client.on("system", (subsystem) => {
console.log(`MPD subsystem changed: ${subsystem}`);
});
// Stop track if playlist is not empty
if (playlistInfo.length > 0) {
await client.sendCommand("play 0");
console.log("Playback started.");
} else {
console.log("Playlist is empty, cannot start playback.");
}
console.log();
// Keep the script running to listen for events
console.log("Listening for MPD events... (Press Ctrl+C to exit)");
} catch (error) {
console.error("MPD Error:", error);
} finally {
process.on("SIGINT", async () => {
console.log("\nDisconnecting...");
await client.disconnect();
console.log("Disconnected from MPD.");
process.exit(0);
});
}
}
main().catch((err) => {
console.error("Unhandled error in main:", err);
process.exit(1);
});Static Method
Establishes connection(s) to the MPD server and returns a connected Client instance. This is the primary way to create a client.
Options (Config type, extends net.NetConnectOpts):
host(string): MPD server hostname (default:localhost).port(number): MPD server port (default:6600).password(string): Optional MPD password.timeout(number): Connection timeout in milliseconds (default:5000).poolSize(number): Maximum number of connections in the pool (default:3).reconnectDelay(number): Delay in milliseconds between reconnection attempts (default:5000).maxRetries(number): Maximum number of retry attempts after a failed connection or a dropped event-monitoring connection. The initial connection attempt is not counted as a retry, so the total number of attempts on the initial path is1 + maxRetries. Used for both initial connection and event monitoring reconnection (default:3).
Reconnection Behavior:
The client implements automatic reconnection in two scenarios:
- Initial Connection: If the first attempt of
Client.connect()fails, it will retry up tomaxRetriesmore times withreconnectDelaybetween each attempt. With the defaultmaxRetries: 3, this means up to 4 total attempts before rejecting. - Event Monitoring: If the event monitoring connection drops (used for system events), the client automatically attempts to reconnect up to
maxRetriestimes. System events will continue to be emitted after successful reconnection. Acloseevent is only emitted after all reconnection attempts have been exhausted.
Sends a command to the MPD server.
command: The command string (e.g.,'status') or aCommandobject.
Returns: A Promise resolving to the full response string aggregated from the server, including the final OK line.
Sends multiple commands as a single command list to the MPD server.
commandList: An array of command strings orCommandobjects.
Returns: A Promise resolving to the full response string aggregated from the server for the entire command list.
Sends a single command and returns the response as a ReadableStream.
command: The command string orCommandobject.
Returns: A Promise resolving to a ReadableStream where each chunk is a ResponseLine object ({ raw: string } containing one line of the MPD response, excluding the final OK). Useful for processing large responses line by line.
Sends multiple commands as a command list and returns the response as a ReadableStream.
commandList: An array of command strings orCommandobjects.
Returns: A Promise resolving to a ReadableStream of ResponseLine objects for the entire command list response.
Closes all connections to the MPD server, stops event monitoring, and cleans up resources.
Returns the MPD protocol version reported by the server during the initial connection.
The following parser utilities are exported. They can be imported either
as a Parsers namespace object (as shown in the examples above) or
individually as named exports for better tree-shaking:
import { Parsers } from "@prokosna/mpd3";
// or
import { transformToList, aggregateToList } from "@prokosna/mpd3";Available utilities:
transformToListtransformToListAndAccumulatetransformToObjecttransformToTypedaggregateToListaggregateToStringtakeFirstLineValuetakeFirstObjecttakeFirstBinary
These utility functions are used by pipeThrough() or then() of Promise<ReadableStream>.
The Client class extends Node's EventEmitter, so the standard client.on(...), client.off(...), and client.once(...) methods are available. Listening on a system/system-<subsystem> event lazily starts the dedicated MPD idle connection; the connection lives until client.disconnect() is called.
system(subsystem: string): Emitted when MPD reports a change in one of its subsystems (e.g.,player,mixer,options,playlist). This event continues to be emitted after automatic reconnection.system-<subsystem>(no payload): Per-subsystem variant, emitted alongsidesystem. For example,client.on("system-player", () => { ... })fires only when theplayersubsystem changes.error(error: Error): Emitted when a connection or protocol error occurs within the connection pool or event monitoring.close(error?: Error): Emitted when thedisconnect()method is called, or when the event monitoring connection fails after exhausting all reconnection attempts. If an error is provided, the connection was closed due to that error.