Dear MPD-developers, Lately I fantasized about a CGI like mechanism that is called when a song changes for example. External programs can then be notified without listening all the time, a push basis. For example it can be used to: - Log data about playing behaviour. - Change the wallpaper of the system. - Output playing information to an external device like a character LCD display. - Scrobble to last.fm like services.
Anyways, I was not sure whether this was in the scope of the project and what other thought about it. But since it was an easy hack I've include a patch anyhow that supplies this functionality. An example program that uses the functionality can be found here: https://github.com/dopefishh/mpdcgilog Best, Mart
diff --git a/AUTHORS b/AUTHORS index 09eb11c..d620531 100644 --- a/AUTHORS +++ b/AUTHORS @@ -30,3 +30,4 @@ The following people have contributed code to MPD: Jurgen Kramer <gtmkra...@xs4all.nl> Jean-Francois Dockes <j...@dockes.org> Yue Wang <yuleo...@gmail.com> + Mart Lubbers <m...@martlubbers.net> diff --git a/Makefile.am b/Makefile.am index ef65231..e34d069 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1403,6 +1403,12 @@ liboutput_plugins_a_SOURCES += \ src/output/plugins/FifoOutputPlugin.hxx endif +if ENABLE_CGI_OUTPUT +liboutput_plugins_a_SOURCES += \ + src/output/plugins/CgiOutputPlugin.cxx \ + src/output/plugins/CgiOutputPlugin.hxx +endif + if HAVE_SNDIO liboutput_plugins_a_SOURCES += \ src/output/plugins/SndioOutputPlugin.cxx \ diff --git a/configure.ac b/configure.ac index d94cad3..6c21026 100644 --- a/configure.ac +++ b/configure.ac @@ -334,6 +334,11 @@ AC_ARG_ENABLE(fifo, [disable support for writing audio to a FIFO (default: enable)]),, enable_fifo=yes) +AC_ARG_ENABLE(cgi-output, + AS_HELP_STRING([--enable-cgi-output], + [enable support for writing audio/events to a CGI script (default: disabled)]),, + enable_cgi_output=yes) + AC_ARG_ENABLE(sndio, AS_HELP_STRING([--enable-sndio], [enable support for sndio output plugin (default: auto)]),, @@ -1119,6 +1124,10 @@ fi MPD_DEFINE_CONDITIONAL(enable_fifo, HAVE_FIFO, [support for writing audio to a FIFO]) +dnl ----------------------------------- CGI ----------------------------------- +MPD_DEFINE_CONDITIONAL(enable_cgi_output, ENABLE_CGI_OUTPUT, [CGI output]) + + dnl ----------------------------------- SNDIO ---------------------------------- if test x$enable_sndio = xauto; then AC_CHECK_HEADER(sndio.h, @@ -1453,6 +1462,7 @@ results(id3,[ID3]) printf '\nPlayback support:\n\t' results(alsa,ALSA) results(fifo,FIFO) +results(cgi_output,CGI) results(sndio,[SNDIO]) results(recorder_output,[File Recorder]) results(haiku,[Haiku]) diff --git a/doc/mpdconf.example b/doc/mpdconf.example index 7f9ddde..8d8c67d 100644 --- a/doc/mpdconf.example +++ b/doc/mpdconf.example @@ -335,6 +335,13 @@ input { # format "44100:16:2" #} # +## Example "cgi" output: +#audio_output { +# type "cgi" +# name "my cgi" +# command "/path/to/some/script.sh" +#} +# ## An example of a null output (for no audio output): # #audio_output { diff --git a/doc/user.xml b/doc/user.xml index c86458f..d72d3b2 100644 --- a/doc/user.xml +++ b/doc/user.xml @@ -2828,6 +2828,39 @@ buffer_size: 16384</programlisting> </section> <section> + <title><varname>cgi</varname></title> + + <para> + The <varname>cgi</varname> plugin writes the metadata of the + files and events to a <varname>cgi</varname> script. + </para> + + <informaltable> + <tgroup cols="2"> + <thead> + <row> + <entry>Setting</entry> + <entry>Description</entry> + </row> + </thead> + <tbody> + <row> + <entry> + <varname>command</varname> + <parameter>CMD</parameter> + </entry> + <entry> + This specifies the path of the script to write to. + Several environment variables are made available to + the script in the same fashion as web cgi scripts. + </entry> + </row> + </tbody> + </tgroup> + </informaltable> + </section> + + <section> <title><varname>jack</varname></title> <para> diff --git a/src/output/Registry.cxx b/src/output/Registry.cxx index 9d8d826..9500f06 100644 --- a/src/output/Registry.cxx +++ b/src/output/Registry.cxx @@ -23,6 +23,7 @@ #include "plugins/AlsaOutputPlugin.hxx" #include "plugins/AoOutputPlugin.hxx" #include "plugins/FifoOutputPlugin.hxx" +#include "plugins/CgiOutputPlugin.hxx" #include "plugins/SndioOutputPlugin.hxx" #include "plugins/httpd/HttpdOutputPlugin.hxx" #include "plugins/HaikuOutputPlugin.hxx" @@ -53,6 +54,9 @@ const AudioOutputPlugin *const audio_output_plugins[] = { #ifdef HAVE_FIFO &fifo_output_plugin, #endif +#ifdef ENABLE_CGI_OUTPUT + &cgi_output_plugin, +#endif #ifdef HAVE_SNDIO &sndio_output_plugin, #endif diff --git a/src/output/plugins/CgiOutputPlugin.cxx b/src/output/plugins/CgiOutputPlugin.cxx new file mode 100644 index 0000000..ab8baf2 --- /dev/null +++ b/src/output/plugins/CgiOutputPlugin.cxx @@ -0,0 +1,166 @@ +/* + * Copyright 2003-2016 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "CgiOutputPlugin.hxx" +#include "../OutputAPI.hxx" +#include "../Wrapper.hxx" +#include "util/StringUtil.hxx" +#include "config/ConfigError.hxx" +#include "util/Error.hxx" + +#include <string> +#include <string.h> + +#include <stdio.h> +#include <unistd.h> +#include <sys/wait.h> + +static char **make_env(const Tag &tag) +{ + char **env = new char*[tag.num_items+1]; + unsigned short i = 0; + const char *ntag; + char *uptag; + size_t elen; + for (const auto &item : tag) { + ntag = tag_item_names[item.type]; + uptag = new char[strlen(ntag)+1]; + ToUpperASCII(uptag, tag_item_names[item.type], strlen(ntag)+1); + + env[i] = new char[elen = strlen(uptag)+strlen(item.value)+2]; + env[i][0] = '\0'; + + strcat(env[i], uptag); + strcat(env[i], "="); + strcat(env[i], item.value); + + delete[] uptag; + i++; + } + for(;i<tag.num_items; i++){ + env[i] = nullptr; + } + env[i] = nullptr; + return env; +} + +class CgiOutput { + friend struct AudioOutputWrapper<CgiOutput>; + + AudioOutput base; + + std::string cmd; + pid_t previous_pid = 0; + char **env = nullptr; + + CgiOutput() + :base(cgi_output_plugin) {} + + bool Configure(const ConfigBlock &block, Error &error) + { + if (!base.Configure(block, error)) + return false; + + cmd = block.GetBlockValue("command", ""); + if (cmd.empty()) { + error.Set(config_domain, + "No \"command\" parameter specified"); + return false; + } + + return true; + } + +public: + static CgiOutput *Create(const ConfigBlock &block, Error &error) + { + CgiOutput *co = new CgiOutput(); + + if (!co->Configure(block, error)) { + delete co; + return nullptr; + } + + return co; + } + + bool Open(gcc_unused AudioFormat &audio_format, gcc_unused Error &error) + { + return true; + } + + void Close() + { + if(env != nullptr){ + delete[] env; + env = nullptr; + } + } + + void SendTag(const Tag &tag) + { + int wp = waitpid(previous_pid, nullptr, WNOHANG); + if(previous_pid != 0 && wp == 0){ + exit(0); + //Child still alive + } else if(previous_pid != 0 && wp == -1){ + exit(0); + //Error + } else { + //Nothing is wrong + Close(); + + env = make_env(tag); + char *argv[1] = {nullptr}; + pid_t p = fork(); + if(p == 0){ + execvpe(cmd.c_str(), argv, env); + } else { + Close(); + previous_pid = p; + } + } + } + + size_t Play(gcc_unused const void *chunk, size_t size, gcc_unused Error &error) + { + return size; + } +}; + +typedef AudioOutputWrapper<CgiOutput> Wrapper; + +const struct AudioOutputPlugin cgi_output_plugin = { + "cgi-output", + nullptr, //Test + &Wrapper::Init, //Init + &Wrapper::Finish, //Finish + nullptr, //Enable + nullptr, //Disable + &Wrapper::Open, //Open + &Wrapper::Close, //Close + nullptr, //Delay + &Wrapper::SendTag, //Send tag + &Wrapper::Play, //Play + nullptr, //Drain + nullptr, //Cancel + nullptr, //Pause + nullptr, //MixerPlugin +}; diff --git a/src/output/plugins/CgiOutputPlugin.hxx b/src/output/plugins/CgiOutputPlugin.hxx new file mode 100644 index 0000000..2479794 --- /dev/null +++ b/src/output/plugins/CgiOutputPlugin.hxx @@ -0,0 +1,25 @@ +/* + * Copyright 2003-2016 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_CGI_OUTPUT_PLUGIN_HXX +#define MPD_CGI_OUTPUT_PLUGIN_HXX + +extern const struct AudioOutputPlugin cgi_output_plugin; + +#endif
signature.asc
Description: PGP signature
_______________________________________________ mpd-devel mailing list mpd-devel@musicpd.org http://mailman.blarg.de/listinfo/mpd-devel