npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

mpd2

v1.0.5

Published

Music Player Daemon client

Downloads

297

Readme

node mpd client

Connect to a Music Player Daemon (GIT) server, send commands, emit events.

This is a rewrite of mpd.js module to promise based methods and support for parsing of various MPD responses.

For higher level API module check out mpd-api.

Usage

npm i / yarn mpd2
const mpd = require('mpd2')
const { cmd } = mpd

// config is passed to net.connect()
const config = {
  host: 'localhost',
  port: 6600,

  // if connecting to a local socket rather than
  // host and port; trailing `~` is replaced by
  // `os.homedir()`
  // path: '~/.config/mpd/socket'

  // if MPD requires a password, pass
  // it within the config as well:
  //password: 'password'
}

const client = await mpd.connect(config)

// without config will default to `localhost:6600`
// const client = await mpd.connect()


const status = await client.sendCommand('status').then(mpd.parseObject)
console.log(status)

client.on('close', () => {
  console.log('client connection closed')
})

client.on('system', name => {
  console.log('on system event: %s', name)
})

client.on('system-player', () => {
  console.log('on system player event')
})

await client.disconnect()

// typings included

import mpd, { MPD } from 'mpd2'

type Status = {
  volume: number
  repeat: boolean
  playlist: number
  state: 'play' | 'stop' | 'pause'
  // ...
}

type ListAllInfo = {
  directory: string
  last_modified: string
  file?: File[]
}

type File = {
  file: string
  last_modified: string
  format: string
  time: number
  artist: string
  title: string
  // ...
}

const client: MPD.Client = await mpd.connect()

const statusString = await client.sendCommand('status')
const status = mpd.parseObject<Status>(statusString)

console.log('state:', status.state)

const lsAllParser = mpd.parseListAndAccumulate<ListAllInfo>(['directory', 'file'])
const lsAllString = await client.sendCommand('listallinfo')
const lsAll = lsAllParser(lsAllString)
console.log('first directory: %s, files: %o', lsAll[0].directory, lsAll[0].file)

try {

  await client.sendCommands([
    'status',
    mpd.cmd('foo', 'bar')
  ])
} catch (e) {
  const err: MPD.MPDError = e

  switch (err.errno) {
    case mpd.MPDError.CODES.UNKNOWN:
      console.log('command does not exist')
      break;
    default:
      console.log('some other error', err)
      break;
  }
}

Documentation

See also the MPD Protocol Documentation.

Client methods

  • async client.sendCommand(command)

    command can be a MpdClient.Command or a string, use mpd.cmd helper to construct the Command when using arguments:

      
    await client.sendCommand(mpd.cmd('setvol', [50]))
      
    // args can be overloaded as well, no need to pass them as array:
    const searched = await client.sendCommand(
      mpd.cmd('search', '(artist contains "Empire")', 'group', 'album'))
      
  • async client.sendCommands(commandList)

    commandList will be wrapped between command_list_begin and command_list_end (see MPD documentation for more info)

  • async client.disconnect()

    Disconnects the client.

Static functions
  • async mpd.connect(options)

    Connects to a MPD server and returns a client.

  • mpd.cmd(name, [args]) or overloaded mpd.cmd(name, ...args)

    Convert name/args pair into a Command.

Parsers
  • mpd.normalizeKeys([bool])

    Getter / setter to enable normalization of keys while parsing. MPD responses contains various keys, upper/lower/kebap cases, this setting normalizes all keys into snake_case.

    Turned on by default

  • mpd.autoparseValues([bool])

    Getter / setter to enable auto parsing of known values based on keys.

    Turned on by default

  • mpd.parseObject(msg)

    msg: a string which contains an MPD response. Returns an object.

  • mpd.parseList(msg, [delimiters])

    msg: a string which contains an MPD response. delimiters: which keys represent distinct object types within the response

    Returns an array, see source for more info

  • mpd.parseList.by(delimiters)

    delimiters: a string or array of delimiters

    returns wrapped function parser(msg) which calls parseList(msg, delimiters)

    const songparser = mpd.parseList.by('file')
    await client.sendCommand('listallinfo').then(songparser)
  • mpd.parsNestedList(msg)

    msg: a string which contains an MPD response.

    Parse the list response, first item key indicates the unique key identifier, any subtiems will be nested within that object. Returns an array of parsed objects. See source for more info.

  • mpd.parseListAndAccumulate(msg, path)

    msg: a string which contains an MPD response. path: array of nested objects

    Parse the list response and nest objects based on path. See source for more info.

Events

  • close

    The connection is closed.

  • system(systemName)

    A system has updated. systemName is one of:

    • database - the song database has been modified after update.
    • update - a database update has started or finished. If the database was modified during the update, the database event is also emitted.
    • stored_playlist - a stored playlist has been modified, renamed, created or deleted
    • playlist - the current playlist has been modified
    • player - the player has been started, stopped or seeked
    • mixer - the volume has been changed
    • output - an audio output has been enabled or disabled
    • options - options like repeat, random, crossfade, replay gain
    • sticker - the sticker database has been modified.
    • subscription - a client has subscribed or unsubscribed to a channel
    • message - a message was received on a channel this client is subscribed to; this event is only emitted when the queue is empty
  • system-*

    See above event. Each system name has its own event as well.

Properties

  • client.PROTOCOL_VERSION

    Protocol version returned by the MPD server after connection is established

  • mpd.MPDError

    MPDError.CODES contains ACK codes map, as seen here Ack.hxx

    MPDError.CODES = {
      NOT_LIST: 1,
      ARG: 2,
      PASSWORD: 3,
      PERMISSION: 4,
      UNKNOWN: 5,
    
      NO_EXIST: 50,
      PLAYLIST_MAX: 51,
      SYSTEM: 52,
      PLAYLIST_LOAD: 53,
      UPDATE_ALREADY: 54,
      PLAYER_SYNC: 55,
      EXIST: 56
    }

    All errors thrown by MPD are converted into MPDError isntance:

    // MPD ACK line looks like
    'ACK [error@command_listNum] {current_command} message_text'
      
    err.code = 'ARG' // one of CODES
    err.errno = 2 // for CODES.ARG
    err.message = 'whatever mpd returned'
    err.cmd_list_num = x // whatever MPD returned as listNum found in MPD ACK line
    err.current_command = 'which command this error relates to' // found by MPD ACK line