diff options
author | 2010-05-25 03:37:44 +0300 | |
---|---|---|
committer | 2010-05-25 03:37:44 +0300 | |
commit | 8c012917f5530d947c1a31adfc6aba4b0cf3853c (patch) | |
tree | f9183ee845fd497006dde0c5f80049714a15d9a4 | |
parent | be0f4b1926f7e77c7e03eae7b70ec12f1b905025 (diff) |
Misc plugin actions
-rw-r--r-- | configure.ac | 11 | ||||
-rw-r--r-- | deadbeef.h | 14 | ||||
-rw-r--r-- | plugins/gtkui/plcommon.c | 48 | ||||
-rw-r--r-- | plugins/lastfm/lastfm.c | 62 | ||||
-rw-r--r-- | plugins/shellexec/Makefile.am | 9 | ||||
-rw-r--r-- | plugins/shellexec/shellexec.c | 125 |
6 files changed, 262 insertions, 7 deletions
diff --git a/configure.ac b/configure.ac index d10f8ed2..51113954 100644 --- a/configure.ac +++ b/configure.ac @@ -74,6 +74,7 @@ AC_ARG_ENABLE(cdda, [ --disable-cdda disable CD-Audio plugin (defa AC_ARG_ENABLE(gme, [ --disable-gme disable Game Music Emu plugin for NSF, AY, etc (default: enabled)], [enable_gme=$enableval], [enable_gme=yes]) AC_ARG_ENABLE(dumb, [ --disable-dumb disable D.U.M.B. plugin for MOD, S3M and other tracker formats (default: enabled)], [enable_dumb=$enableval], [enable_dumb=yes]) AC_ARG_ENABLE(notify, [ --disable-notify disable notification-daemon support plugin (default: enabled)], [enable_notify=$enableval], [enable_notify=yes]) +AC_ARG_ENABLE(shellexec, [ --disable-notify disable notification-daemon support plugin (default: enabled)], [enable_notify=$enableval], [enable_notify=yes]) PKG_CHECK_MODULES(DEPS, samplerate) @@ -290,6 +291,11 @@ if test "x$enable_lfm" != "xno" ; then fi fi +dnl shellexec plugin +if test "x$enable_shellexec" != "xno" ; then + HAVE_SHELLEXEC=yes +fi + if test "x$enable_artwork" != "xno" ; then if test "x$HAVE_CURL" = "xyes" && test "x$HAVE_VFS_CURL" = "xyes" ; then HAVE_ARTWORK=yes @@ -336,7 +342,7 @@ if test "x$HAVE_DBUS" = "xyes" && test "x$enable_notify" != "xno" ; then AC_SUBST(NOTIFY_CFLAGS) fi -PLUGINS_DIRS="plugins/lastfm plugins/mpgmad plugins/vorbis plugins/flac plugins/wavpack plugins/sndfile plugins/vfs_curl plugins/cdda plugins/gtkui plugins/alsa plugins/ffmpeg plugins/hotkeys plugins/oss plugins/artwork plugins/adplug plugins/ffap plugins/sid plugins/nullout plugins/supereq plugins/vtx plugins/gme plugins/dumb plugins/pulse plugins/notify" +PLUGINS_DIRS="plugins/lastfm plugins/mpgmad plugins/vorbis plugins/flac plugins/wavpack plugins/sndfile plugins/vfs_curl plugins/cdda plugins/gtkui plugins/alsa plugins/ffmpeg plugins/hotkeys plugins/oss plugins/artwork plugins/adplug plugins/ffap plugins/sid plugins/nullout plugins/supereq plugins/vtx plugins/gme plugins/dumb plugins/pulse plugins/notify plugins/shellexec" AM_CONDITIONAL(HAVE_VORBIS, test "x$HAVE_VORBISPLUGIN" = "xyes") AM_CONDITIONAL(HAVE_FLAC, test "x$HAVE_FLACPLUGIN" = "xyes") @@ -362,6 +368,7 @@ AM_CONDITIONAL(HAVE_MPGMAD, test "x$HAVE_MPGMAD" = "xyes") AM_CONDITIONAL(HAVE_OSS, test "x$HAVE_OSS" = "xyes") AM_CONDITIONAL(HAVE_SUPEREQ, test "x$HAVE_SUPEREQ" = "xyes") AM_CONDITIONAL(HAVE_NOTIFY, test "x$HAVE_NOTIFY" = "xyes") +AM_CONDITIONAL(HAVE_SHELLEXEC, test "x$HAVE_SHELLEXEC" = "xyes") AC_SUBST(PLUGINS_DIRS) @@ -414,6 +421,7 @@ PRINT_PLUGIN_INFO([pulse],[PulseAudio output plugin],[test "x$HAVE_PULSEPLUGIN" PRINT_PLUGIN_INFO([artwork],[Cover art plugin],[test "x$HAVE_ARTWORK" = "xyes"]) PRINT_PLUGIN_INFO([supereq],[Equalizer based on Super EQ library by Naoki Shibata],[test "x$HAVE_SUPEREQ" = "xyes"]) PRINT_PLUGIN_INFO([notify],[notification-daemon support plugin],[test "x$HAVE_NOTIFY" = "xyes"]) +PRINT_PLUGIN_INFO([shellexec],[shell commands plugin],[test "x$HAVE_SHELLEXEC" = "xyes"]) echo @@ -445,6 +453,7 @@ plugins/pulse/Makefile plugins/artwork/Makefile plugins/supereq/Makefile plugins/notify/Makefile +plugins/shellexec/Makefile deadbeef.desktop ]) @@ -646,12 +646,26 @@ typedef struct DB_dsp_s { int (*enabled) (void); } DB_dsp_t; +typedef struct +{ + const char *title; + int (*callback) (DB_playItem_t *it, void *data); + void *data; +} DB_single_action_t; + // misc plugin // purpose is to provide extra services // e.g. scrobbling, converting, tagging, custom gui, etc. // misc plugins should be mostly event driven, so no special entry points in them typedef struct { DB_plugin_t plugin; + /* Returns actions available for this track + it - track + actions - array of actions + size - on input, size of array in pointers; on output - count of actions + returns 0 on error, nonzero on success + */ + int (*get_single_actions) (DB_playItem_t *it, DB_single_action_t *actions[], int *size); } DB_misc_t; // vfs plugin diff --git a/plugins/gtkui/plcommon.c b/plugins/gtkui/plcommon.c index 96ddff69..3b72b901 100644 --- a/plugins/gtkui/plcommon.c +++ b/plugins/gtkui/plcommon.c @@ -346,6 +346,14 @@ on_remove_from_disk_activate (GtkMenuItem *menuitem, } void +actionitem_activate (GtkMenuItem *menuitem, + DB_single_action_t *action) +{ + DB_playItem_t *it = deadbeef->pl_get_for_idx_and_iter (clicked_idx, PL_MAIN); + action->callback (it, action->data); +} + +void list_context_menu (DdbListview *listview, DdbListviewIter it, int idx) { clicked_idx = deadbeef->pl_get_idx_of (it); int inqueue = deadbeef->pl_playqueue_test (it); @@ -399,6 +407,46 @@ list_context_menu (DdbListview *listview, DdbListviewIter it, int idx) { gtk_container_add (GTK_CONTAINER (playlist_menu), separator8); gtk_widget_set_sensitive (separator8, FALSE); + /// + int count; + int i, j; + GtkWidget *actionitem; + DB_single_action_t *actions[4]; + DB_plugin_t **plugins = deadbeef->plug_get_list(); + for (i = 0; plugins[i]; i++) + { + if (plugins[i]->type != DB_PLUGIN_MISC) + continue; + + DB_misc_t *misc = (DB_misc_t*)plugins[i]; + if (!misc->get_single_actions) + continue; + + count = 4; + if (!misc->get_single_actions (it, actions, &count)) + continue; + + if (count == 0) + continue; + + for (j = 0; j < count; j++) + { + actionitem = gtk_menu_item_new_with_mnemonic (actions[j]->title); + gtk_widget_show (actionitem); + gtk_container_add (GTK_CONTAINER (playlist_menu), actionitem); + g_object_set_data (G_OBJECT (actionitem), "ps", listview); + + g_signal_connect ((gpointer) actionitem, "activate", + G_CALLBACK (actionitem_activate), + actions[j]); + } + separator8 = gtk_separator_menu_item_new (); + gtk_widget_show (separator8); + gtk_container_add (GTK_CONTAINER (playlist_menu), separator8); + gtk_widget_set_sensitive (separator8, FALSE); + } + /// + properties1 = gtk_menu_item_new_with_mnemonic ("Properties"); gtk_widget_show (properties1); gtk_container_add (GTK_CONTAINER (playlist_menu), properties1); diff --git a/plugins/lastfm/lastfm.c b/plugins/lastfm/lastfm.c index 3ba8def8..02dff618 100644 --- a/plugins/lastfm/lastfm.c +++ b/plugins/lastfm/lastfm.c @@ -334,26 +334,31 @@ lfm_fetch_song_info (DB_playItem_t *song, const char **a, const char **t, const static int lfm_uri_encode (char *out, int outl, const char *str) { int l = outl; - static const char echars[] = " ;/?:@=#&+"; //trace ("lfm_uri_encode %p %d %s\n", out, outl, str); while (*str) { if (outl <= 1) { //trace ("no space left for 1 byte in buffer\n"); return -1; } - if (strchr (echars, *str)) { + + if (!( + (*str >= '0' && *str <= '9') || + (*str >= 'a' && *str <= 'z') || + (*str >= 'A' && *str <= 'Z') || + (*str == ' ') + )) + { if (outl <= 3) { //trace ("no space left for 3 bytes in the buffer\n"); return -1; } - //trace ("adding escaped value for %c\n", *str); - snprintf (out, outl, "%%%02x", (int)*str); + snprintf (out, outl, "%%%02x", (uint8_t)*str); outl -= 3; str++; out += 3; } else { - *out = *str; + *out = *str == ' ' ? '+' : *str; out++; str++; outl--; @@ -819,6 +824,50 @@ lastfm_stop (void) { return 0; } +static int +lfm_action_lookup (DB_playItem_t *it, void *data) +{ + const char *artist = deadbeef->pl_find_meta (it, "artist"); + const char *title = deadbeef->pl_find_meta (it, "title"); + + if (!title || !artist) + return 0; + + char eartist [strlen (artist) * 3 + 1]; + char etitle [strlen (title) * 3 + 1]; + + if (-1 == lfm_uri_encode (eartist, sizeof (eartist), artist)) + return 0; + + if (-1 == lfm_uri_encode (etitle, sizeof (etitle), title)) + return 0; + + char *command = NULL; + if (-1 == asprintf (&command, "xdg-open http://www.last.fm/music/%s/_/%s", eartist, etitle)) + return 0; + system (command); + free (command); +} + +static DB_single_action_t lookup_action = { + .title = "Lookup at Last.fm", + .callback = lfm_action_lookup +}; + +static int +lfm_get_single_actions (DB_playItem_t *it, DB_single_action_t *actions[], int *size) +{ + if (deadbeef->pl_find_meta (it, "artist") && + deadbeef->pl_find_meta (it, "title")) + { + actions[0] = &lookup_action; + *size = 1; + } + else + *size = 0; + return 1; +} + static const char settings_dlg[] = "property \"Enable scrobbler\" checkbox lastfm.enable 0;" "property \"Disable nowplaying\" checkbox lastfm.disable_np 0;" @@ -840,5 +889,6 @@ static DB_misc_t plugin = { .plugin.website = "http://deadbeef.sf.net", .plugin.start = lastfm_start, .plugin.stop = lastfm_stop, - .plugin.configdialog = settings_dlg + .plugin.configdialog = settings_dlg, + .get_single_actions = lfm_get_single_actions }; diff --git a/plugins/shellexec/Makefile.am b/plugins/shellexec/Makefile.am new file mode 100644 index 00000000..65d6a5b8 --- /dev/null +++ b/plugins/shellexec/Makefile.am @@ -0,0 +1,9 @@ +if HAVE_SHELLEXEC +shxdir = $(libdir)/$(PACKAGE) +pkglib_LTLIBRARIES = shellexec.la +shellexec_la_SOURCES = shellexec.c +shellexec_la_LDFLAGS = -module + +shellexec_la_LIBADD = $(LDADD) $(HOTKEYS_LIBS) +AM_CFLAGS = $(CFLAGS) -std=c99 +endif diff --git a/plugins/shellexec/shellexec.c b/plugins/shellexec/shellexec.c new file mode 100644 index 00000000..39e7f4da --- /dev/null +++ b/plugins/shellexec/shellexec.c @@ -0,0 +1,125 @@ +/* + Shellexec plugin for DeaDBeeF + Copyright (C) 2009 Viktor Semykin <thesame.ml@gmail.com> + + 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, see <http://www.gnu.org/licenses/>. +*/ +#include <stdio.h> +#include <string.h> + +#include "../../deadbeef.h" + +#define MAX_COMMANDS 128 + +#define trace(...) { fprintf(stderr, __VA_ARGS__); } +//#define trace(fmt,...) + +static DB_misc_t plugin; +static DB_functions_t *deadbeef; + +DB_single_action_t shx_actions [MAX_COMMANDS]; +static int single_action_count; + +DB_plugin_t * +shellexec_load (DB_functions_t *api) { + deadbeef = api; + return DB_PLUGIN (&plugin); +} + +static int +shx_get_single_actions (DB_playItem_t *it, DB_single_action_t *actions[], int *size) +{ + if (*size < single_action_count) + return 0; + + int i; + *size = single_action_count; + trace ("Shellexec: %d actions\n", single_action_count); + for (i=0; i < single_action_count; i++) + actions[i] = &shx_actions[i]; + return 1; +} + +static int +shx_callback (DB_playItem_t *it, void *data) +{ + char fmt[1024]; //FIXME: possible stack corruption + deadbeef->pl_format_title (it, -1, fmt, sizeof (fmt), -1, data); + printf ("%s\n", fmt); + return 0; +} + +static char* +trim (char* s) +{ + char *h, *t; + + for (h = s; *h == ' ' || *h == '\t'; h++); + for (t = s + strlen (s); *t == ' ' || *t == '\t'; t--); + * (t+1) = 0; + return h; +} + +static int +shellexec_start (void) +{ + trace ("Starting shellexec\n"); + single_action_count = 0; + DB_conf_item_t *item = deadbeef->conf_find ("shellexec.", NULL); + while (item) + { + if (single_action_count == MAX_COMMANDS) + { + fprintf (stdout, "Shellexec: max number of commands (%d) exceeded\n", MAX_COMMANDS); + break; + } + size_t l = strlen (item->value) + 1; + char tmp[l]; + strcpy (tmp, item->value); + trace ("Shellexec: %s\n", tmp); + + char *semicolon = strchr (tmp, ':'); + if (!semicolon) + { + fprintf (stdout, "Shellexec: wrong option <%s>\n", tmp); + continue; + } + + *semicolon = 0; + + shx_actions[single_action_count].title = strdup (trim (semicolon + 1)); + shx_actions[single_action_count].callback = shx_callback; + shx_actions[single_action_count].data = strdup (trim (tmp)); + + item = deadbeef->conf_find ("shellexec.", item); + single_action_count++; + } +} + +// define plugin interface +static DB_misc_t plugin = { + .plugin.api_vmajor = DB_API_VERSION_MAJOR, + .plugin.api_vminor = DB_API_VERSION_MINOR, + .plugin.type = DB_PLUGIN_MISC, + .plugin.id = "shellexec", + .plugin.name = "Shell commands for tracks", + .plugin.descr = "Executes configurable shell commands for tracks", + .plugin.author = "Viktor Semykin", + .plugin.email = "thesame.ml@gmail.com", + .plugin.website = "http://deadbeef.sf.net", + .plugin.start = shellexec_start, + + .get_single_actions = shx_get_single_actions +}; + |