class MPD
The main class/namespace of the MPD
client.
Constants
- SERVER_ERRORS
- VERSION
Attributes
Public Class Methods
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
# File lib/ruby-mpd.rb, line 169 def authenticate send_command(:password, @password) if @password end
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
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 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
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
Kills the MPD
process. @macro returnraise
# File lib/ruby-mpd.rb, line 158 def kill send_command :kill end
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
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 the server. @macro returnraise
# File lib/ruby-mpd.rb, line 175 def ping send_command :ping end
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
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
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
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
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
# File lib/ruby-mpd.rb, line 272 def socket @socket ||= File.exists?(@hostname) ? UNIXSocket.new(@hostname) : TCPSocket.new(@hostname, @port) end