-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 The subject says it all. :P
Reasons why this is better: - - It times out after 1 sec if mpd is unreachable, old code could freeze awesome - - It works with passworded mpd servers (untested, but saw a bug in the old code) - - It can do xcb-style async requests - - The code doesn't have a 200 lines license header ;) - - It doesn't error out badly if lua-socket is missing - - No API breakage, old code will continue to work - - I wrote it! Uli The following changes since commit e64d4f92f1f1a6430a000c5051e157218ccfe7b7: Gregor Best (1): Merge branch 'for-farhaven' of git://git.znc.in/psychon/obvious are available in the git repository at: git://git.znc.in/psychon/obvious.git mpd Uli Schlachter (1): Replace lib.mpd with a waaay better version :P lib/mpd.lua | 212 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/mpd/init.lua | 160 ---------------------------------------- 2 files changed, 212 insertions(+), 160 deletions(-) create mode 100644 lib/mpd.lua delete mode 100644 lib/mpd/init.lua - -- "Do you know that books smell like nutmeg or some spice from a foreign land?" -- Faber in Fahrenheit 451 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (GNU/Linux) iQEcBAEBCAAGBQJKjZNtAAoJECLkKOvLj8sGukcH/jvk0Qfbg2uy9LgKGSQhWF8n FM5BevTe9+pv3HhAXwMJVwlbmMBQo+oV6rnwZdGSOy/YRwN1OxdO14r+MQNr/SGR Sgze4jd+zYRpYniac2hEm3Zmswj6BCSntioe+0I7Kf+BHwUZVOFfPY0849opa1iJ GLghCa27ntwxP/r45hUi2V0S9G1LOp6Hxfohd1kT3Bl8nswfKdpGF9HXLh5rN3yP +N52ju8zz3+MVeFJnc4YE4981xtGg5dj4pfCf0/7KelYVPhbGqc/dV7QnyHzxyPA sWmLkrUZ+t3kJ3YFMYTFTr7oE+C73HLPt3f+F9Tq2s0IZOFN7mQFegonUN4rU9c= =Hp64 -----END PGP SIGNATURE-----
>From 2055732a68008b7010c8034139afd3c0c6b2762c Mon Sep 17 00:00:00 2001 From: Uli Schlachter <psyc...@znc.in> Date: Thu, 20 Aug 2009 20:10:38 +0200 Subject: [PATCH] Replace lib.mpd with a waaay better version :P The api stays the same, no breakage here. Signed-off-by: Uli Schlachter <psyc...@znc.in> --- lib/mpd.lua | 212 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/mpd/init.lua | 160 ---------------------------------------- 2 files changed, 212 insertions(+), 160 deletions(-) create mode 100644 lib/mpd.lua delete mode 100644 lib/mpd/init.lua diff --git a/lib/mpd.lua b/lib/mpd.lua new file mode 100644 index 0000000..e29f6e8 --- /dev/null +++ b/lib/mpd.lua @@ -0,0 +1,212 @@ +----------------------------------- +-- Author: Uli Schlachter -- +-- Copyright 2009 Uli Schlachter -- +----------------------------------- + +-- pcall() catches errors if socket is not available +local have_socket, socket = pcall(function() return require("socket") end) +local setmetatable = setmetatable +local print = print +local pairs = pairs +local string = string +local tonumber = tonumber + +module("obvious.lib.mpd") + +local mpd_socket = nil +local settings = { + hostname = "localhost", + port = 6600, + password = nil, + timeout = 1, +} + +local function reconnect() + if not have_socket then + print('obvious.lib.mpd: require("socket") failed') + return + end + + mpd_socket = socket.tcp() + + -- First set the timeout so that :connect() honors it + mpd_socket:settimeout(settings.timeout, "t") + mpd_socket:setoption("keepalive", true) + + local connected, err + connected, err = mpd_socket:connect(settings.hostname, settings.port) + if not connected then + -- Do something with err + mpd_socket:close() + mpd_socket = nil + + return false + end + + -- Skip the server's welcome message + mpd_socket:receive("*l") + + if settings.password then + mpd_socket:send("password " .. settings.password .. "\n") + -- Get rid of that "OK" or "ACK" + mpd_socket:receive("*l") + end + + return true +end + +-- Send a command to mpd +function send_internal(command) + if not mpd_socket then + reconnect() + end + + if mpd_socket then + local sent, err + sent, err = mpd_socket:send(command .. "\n") + if not sent and err then + -- Do something with err (can be "closed" or "timeout") + end + end +end + +-- Collect the result of a previous send_internal() call +-- *MUST* be called for each send_internal() call, not necessarily immediatly +-- It returns a table with each server reply as key-value pairs +-- (The special key _reply is used for the server's status code) +function recv_internal() + local ret = { } + + if mpd_socket then + local line, err + line, err = mpd_socket:receive("*l") + if not line then -- mpd died? + -- Do something with err (can be "closed" or "timeout") + mpd_socket:close() + mpd_socket = nil + else + while line do + if line:match("^OK ?") or line:match("^ACK ") then + ret._reply = line + break + end + local key = line:match("^([^:]+)") + local value = line:match(": ?(.*)$") + key = string.lower(key) + + ret[key] = value + + line = mpd_socket:receive("*l") + end + end + end + + return ret +end + +-- Send a command and return the reply +function send(c) + send_internal(c) + return recv_internal() +end + +local function get() + local ret = { } + local reply + + send_internal("status") + send_internal("currentsong") + + reply = recv_internal() + if reply then + ret.state = reply.state + end + + reply = recv_internal() + if reply then + local title = reply.title + local artist = reply.artist + local file = reply.file + + if title and artist then + ret.song = artist .. " - " .. title + elseif title then + ret.song = title + elseif artist then + ret.song = artist + elseif file then + ret.song = file + elseif #ret ~= 0 then + ret.song = "error" + local l = "" + for k, v in pairs(reply) do + l = l .. "\n" .. k .. ": " .. v + end + print("MPD: Could not parse:" .. l) + end + end + + return ret +end + +function toggle_play() + local reply = send("status") + + if reply.state == "play" then + send("pause 1") + elseif reply.state == "pause" then + send("pause 0") + else + -- This should be the "stopped" case or MPD is down + send("play -1") + end +end + +function toggle_random() + local reply = send("status") + if stats.random == "0" then + send("random 1") + else + send("random 0") + end +end + +function toggle_repeat() + local reply = send("status") + if reply["repeat"] == "0" then + send("repeat 1") + else + send("repeat 0") + end +end + +function next() + send("next") +end + +function previous() + send("previous") +end + +function pause() + send("pause") +end + +function stop() + send("stop") +end + +-- no need to check the new value, mpd will set the volume in [0,100] +function volume_up(delta) + local stats = send("status") + local new_volume = tonumber(stats.volume) + delta + send(string.format("setvol %d", new_volume)) +end + +function volume_down(delta) + volume_up(-delta) +end + +setmetatable(_M, { __call = get }) + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/lib/mpd/init.lua b/lib/mpd/init.lua deleted file mode 100644 index d1f0e35..0000000 --- a/lib/mpd/init.lua +++ /dev/null @@ -1,160 +0,0 @@ --- Small interface to MusicPD --- based on a netcat version from Steve Jothen <sjothen at gmail dot com> --- (see http://github.com/otkrove/ion3-config/tree/master/mpd.lua) --- --- Copyright (c) 2008-2009, Alexandre Perrin <kaw...@kaworu.ch> --- All rights reserved. --- --- Redistribution and use in source and binary forms, with or without --- modification, are permitted provided that the following conditions --- are met: --- --- 1. Redistributions of source code must retain the above copyright --- notice, this list of conditions and the following disclaimer. --- 2. Redistributions in binary form must reproduce the above copyright --- notice, this list of conditions and the following disclaimer in the --- documentation and/or other materials provided with the distribution. --- 4. Neither the name of the author nor the names of its contributors --- may be used to endorse or promote products derived from this software --- without specific prior written permission. --- --- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND --- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE --- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE --- ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE --- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL --- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS --- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) --- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT --- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY --- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF --- SUCH DAMAGE. - -require("socket") - --- Grab env -local socket = socket -local string = string -local tonumber = tonumber - --- Music Player Daemon Lua library. -module("obvious.lib.mpd") - --- default settings values -settings = -{ - hostname = "localhost", - port = 6600, - password = nil, -} - --- our socket -local sock = nil; - --- override default settings values -function setup(hostname, port, password) - settings.hostname = hostname - settings.port = port - settings.password = password - -- Unset this so that next operation knows to - -- get a different server - sock = nil -end - - --- calls the action and returns the server's response. --- Example: if the server's response to "status" action is: --- volume: 20 --- repeat: 0 --- random: 0 --- playlist: 599 --- ... --- then the returned table is: --- { volume = 20, repeat = 0, random = 0, playlist = 599, ... } -function send(action) - local command = string.format("%s\n", action) - local values = {} - - -- connect to MPD server if not already done. - if not sock then - sock = socket.connect(settings.hostname, settings.port) - if sock and settings.password then - send(string.format("password %s", settings.password)) - end - end - - if sock then - sock:send(command) - local line = sock:receive("*l") - - if not line then -- closed (mpd killed?): reset socket and retry - sock = nil - return send(action) - end - - while not (line:match("^OK$") or line:match(string.format("unknow command \"%s\"", action))) do - local _, _, key, value = string.find(line, "(.+):%s(.+)") - if key then - values[string.lower(key)] = value - end - line = sock:receive("*l") - end - end - - return values -end - -function next() - send("next") -end - -function previous() - send("previous") -end - -function pause() - send("pause") -end - -function stop() - send("stop") -end - --- no need to check the new value, mpd will set the volume in [0,100] -function volume_up(delta) - local stats = send("status") - local new_volume = tonumber(stats.volume) + delta - send(string.format("setvol %d", new_volume)) -end - -function volume_down(delta) - volume_up(-delta) -end - -function toggle_random() - local stats = send("status") - if tonumber(stats.random) == 0 then - send("random 1") - else - send("random 0") - end -end - -function toggle_repeat() - local stats = send("status") - if tonumber(stats["repeat"]) == 0 then - send("repeat 1") - else - send("repeat 0") - end -end - -function toggle_play() - if send("status").state == "stop" then - send("play") - else - send("pause") - end -end - --- vim:filetype=lua:tabstop=8:shiftwidth=2:fdm=marker: -- 1.6.3.3