class MPD

The main class/namespace of the MPD client.

Constants

SERVER_ERRORS
VERSION

Attributes

hostname[R]
port[R]
version[R]

Public Class Methods

new(hostname = 'localhost', port = 6600, opts = {}) click to toggle source

Initialize an MPD object with the specified hostname and port. When called without arguments, ‘localhost’ and 6600 are used.

When called with +callbacks: true+ as an optional argument, callbacks will be enabled by starting a separate polling thread.

@param [String] hostname Hostname of the daemon @param [Integer] port Port of the daemon @param [Hash] opts Optional parameters. Currently accepts callbacks

# File lib/ruby-mpd.rb, line 53
def initialize(hostname = 'localhost', port = 6600, opts = {})
  @hostname = hostname
  @port = port
  @options = {callbacks: false}.merge(opts)
  @password = opts.delete(:password) || nil
  reset_vars

  @mutex = Mutex.new
  @callbacks = {}
end

Public Instance Methods

authenticate() click to toggle source
# File lib/ruby-mpd.rb, line 169
def authenticate
  send_command(:password, @password) if @password
end
connect(callbacks = nil) click to toggle source

Connect to the daemon.

When called without any arguments, this will just connect to the server and wait for your commands.

@return [true] Successfully connected. @raise [MPDError] If connect is called on an already connected instance.

# File lib/ruby-mpd.rb, line 99
def connect(callbacks = nil)
  raise ConnectionError, 'Already connected!' if connected?

  # by protocol, we need to get a 'OK MPD <version>' reply
  # should we fail to do so, the connection was unsuccessful
  unless response = socket.gets
    reset_vars
    raise ConnectionError, 'Unable to connect (possibly too many connections open)'
  end

  authenticate
  @version = response.chomp.gsub('OK MPD ', '') # Read the version

  if callbacks
    warn "Using 'true' or 'false' as an argument to MPD#connect has been deprecated, and will be removed in the future!"
    @options.merge!(callbacks: callbacks)
  end

  callback_thread if @options[:callbacks]
  return true
end
connected?() click to toggle source

Check if the client is connected.

@return [Boolean] True only if the server responds otherwise false.

# File lib/ruby-mpd.rb, line 124
def connected?
  return false unless @socket
  send_command(:ping) rescue false
end
disconnect() click to toggle source

Disconnect from the MPD daemon. This has no effect if the client is not connected. Reconnect using the {#connect} method. This will also stop the callback thread, thus disabling callbacks. @return [Boolean] True if successfully disconnected, false otherwise.

# File lib/ruby-mpd.rb, line 133
def disconnect
  @cb_thread[:stop] = true if @cb_thread

  return false unless @socket

  begin
    @socket.puts 'close'
    @socket.close
  rescue Errno::EPIPE
    # socket was forcefully closed
  end

  reset_vars
  return true
end
emit(event, *args) click to toggle source

Triggers an event, running it’s callbacks. @param [Symbol] event The event that happened. @return [void]

# File lib/ruby-mpd.rb, line 87
def emit(event, *args)
  return unless @callbacks[event]
  @callbacks[event].each { |handle| handle.call(*args) }
end
kill() click to toggle source

Kills the MPD process. @macro returnraise

# File lib/ruby-mpd.rb, line 158
def kill
  send_command :kill
end
on(event, &block) click to toggle source

This will register a block callback that will trigger whenever that specific event happens.

mpd.on :volume do |volume|
  puts "Volume was set to #{volume}!"
end

One can also define separate methods or Procs and whatnot, just pass them in as a parameter.

method = Proc.new {|volume| puts "Volume was set to #{volume}!" }
mpd.on :volume, &method

@param [Symbol] event The event we wish to listen for. @param [Proc, Method] block The actual callback. @return [void]

# File lib/ruby-mpd.rb, line 80
def on(event, &block)
  (@callbacks[event] ||= []).push block
end
password(pass) click to toggle source

Used for authentication with the server. @param [String] pass Plaintext password @macro returnraise

# File lib/ruby-mpd.rb, line 165
def password(pass)
  send_command :password, pass
end
ping() click to toggle source

Ping the server. @macro returnraise

# File lib/ruby-mpd.rb, line 175
def ping
  send_command :ping
end
reconnect() click to toggle source

Attempts to reconnect to the MPD daemon. @return [Boolean] True if successfully reconnected, false otherwise.

# File lib/ruby-mpd.rb, line 151
def reconnect
  disconnect
  connect
end
send_command(command, *args) click to toggle source

Used to send a command to the server, and to recieve the reply. Reply gets parsed. Synchronized on a mutex to be thread safe.

Can be used to get low level direct access to MPD daemon. Not recommended, should be just left for internal use by other methods.

@return (see handle_server_response) @raise [MPDError] if the command failed.

# File lib/ruby-mpd.rb, line 188
def send_command(command, *args)
  raise ConnectionError, "Not connected to the server!" unless socket

  @mutex.synchronize do
    begin
      socket.puts convert_command(command, *args)
      response = handle_server_response
      return parse_response(command, response)
    rescue Errno::EPIPE
      reconnect
      retry
    end
  end
end

Private Instance Methods

callback_thread() click to toggle source

Constructs a callback loop thread and/or resumes it. @return [Thread]

# File lib/ruby-mpd.rb, line 214
def callback_thread
  @cb_thread ||= Thread.new(self) do |mpd|
    old_status = {}
    while true
      status = mpd.status rescue {}

      status[:connection] = mpd.connected?

      status[:time] ||= [nil, nil] # elapsed, total
      status[:audio] ||= [nil, nil, nil] # samp, bits, chans
      status[:song] = mpd.current_song rescue nil
      status[:updating_db] ||= nil

      status.each do |key, val|
        next if val == old_status[key] # skip unchanged keys
        emit key, *val # splat arrays
      end

      old_status = status
      sleep 0.1

      unless status[:connection] || Thread.current[:stop]
        sleep 2
        mpd.connect rescue nil
      end

      Thread.stop if Thread.current[:stop]
    end
  end
  @cb_thread[:stop] = false
  @cb_thread.run if @cb_thread.stop?
end
handle_server_response() click to toggle source

Handles the server’s response (called inside {#send_command}). Repeatedly reads the server’s response from the socket.

@return (see Parser#build_response) @return [true] If “OK” is returned. @raise [MPDError] If an “ACK” is returned.

# File lib/ruby-mpd.rb, line 253
def handle_server_response
  msg = ''
  while true
    case line = socket.gets
    when "OK\n", nil
      break
    when /^ACK/
      error = line
      break
    else
      msg << line
    end
  end

  return msg unless error
  err = error.match(/^ACK \[(?<code>\d+)\@(?<pos>\d+)\] \{(?<command>.*)\} (?<message>.+)$/)
  raise SERVER_ERRORS[err[:code].to_i], "[#{err[:command]}] #{err[:message]}"
end
reset_vars() click to toggle source

Initialize instance variables on new object, or on disconnect.

# File lib/ruby-mpd.rb, line 206
def reset_vars
  @socket = nil
  @version = nil
  @tags = nil
end
socket() click to toggle source
# File lib/ruby-mpd.rb, line 272
def socket
  @socket ||= File.exists?(@hostname) ? UNIXSocket.new(@hostname) : TCPSocket.new(@hostname, @port)
end