Hey,

There are a thousand things you could do on MPD state changes.
I, for instance, use the mpd 'play' or 'pause' state to power up the
audio amplifier.

Rather than listening for the metadata tags only, I listen for all
events. In order to easy deploy things, I wrote myself an mpdstate
program that listens, and pipes the MPD state events into a bash script
that does the real job on incoming events, and that you could easily
write yourself one to log your played songs in mysql.

Do you agree it suits your needs?
I imagined a script like:

        while read KEY VALUE; do
        case "$KEY" in
        songid)
                # put FILE, ARTIST, ALBUM and TITLE in environment and
                # run /path/to/command
                eval `mpc current -f "FILE='%file%'[ ARTIST='%artist%'][ 
ALBUM='%album%'][ TITLE='%title%']"` /path/to/command PARAMS
                ;;
        esac
        done

You can find my mpdstat on:

https://github.com/kurt-vd/mpdstate

Kind regards,
Kurt


--- Original message ---
> Date: Sun, 23 Oct 2016 10:57:02 +0200
> From: Mart <m...@martlubbers.net>
> To: mpd-devel@musicpd.org
> Subject: [mpd-devel] CGI like output support
> User-Agent: NeoMutt/20161014 (1.7.1)
> 
> 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




> _______________________________________________
> mpd-devel mailing list
> mpd-devel@musicpd.org
> http://mailman.blarg.de/listinfo/mpd-devel

_______________________________________________
mpd-devel mailing list
mpd-devel@musicpd.org
http://mailman.blarg.de/listinfo/mpd-devel

Reply via email to