changeset 18:dc3aa0bf24c0

moved to mpris access
author Yoshiki Yazawa <yaz@honeyplanet.jp>
date Sat, 04 Oct 2008 04:19:46 +0900
parents 14de631fa929
children 12d809123d69
files Makefile.in pidgin-audacious.c
diffstat 2 files changed, 327 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile.in	Thu Oct 02 18:36:39 2008 +0900
+++ b/Makefile.in	Sat Oct 04 04:19:46 2008 +0900
@@ -1,3 +1,4 @@
+TARGET = pidgin-audacious3.so
 PIDGIN_CFLAGS = @PIDGIN_CFLAGS@
 AUD_CFLAGS = @AUD_CFLAGS@
 DBUS_GLIB_CFLAGS = @DBUS_GLIB_CFLAGS@
@@ -12,18 +13,18 @@
 PIDGIN_LIB_DIR = @PIDGIN_LIB_DIR@
 
 
-default: pidgin-audacious.so
+default: $(TARGET)
 
-pidgin-audacious.so: pidgin-audacious.c
+$(TARGET): pidgin-audacious.c
 	gcc -o $@ $< $(CFLAGS) $(LDFLAGS) -g -Wl,-rpath=$(AUD_LIB_DIR)
 
 
-install: pidgin-audacious.so
-	install -m 755 pidgin-audacious.so $(PIDGIN_LIB_DIR)/pidgin
+install: $(TARGET)
+	install -m 755 $(TARGET) $(PIDGIN_LIB_DIR)/pidgin
 
 
 clean:
-	rm -f pidgin-audacious.so
+	rm -f $(TARGET)
 
 
 distclean: clean
--- a/pidgin-audacious.c	Thu Oct 02 18:36:39 2008 +0900
+++ b/pidgin-audacious.c	Sat Oct 04 04:19:46 2008 +0900
@@ -21,6 +21,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <glib.h>
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
 
 #include "gtkplugin.h"
 #include "util.h"
@@ -28,58 +30,240 @@
 #include "connection.h"
 #include "version.h"
 #include "cmds.h"
-#include <audacious/audctrl.h>
-#include <audacious/dbus.h>
-
-extern gchar *botch_utf(const gchar *msg, gsize len, gsize *newlen) __attribute__ ((weak));
+#include "savedstatuses.h"
 
 #define PIDGINAUD_PLUGIN_ID     "pidgin_audacious"
 
 #define OPT_PIDGINAUD           "/plugins/pidgin_audacious"
 #define OPT_PROCESS_STATUS      OPT_PIDGINAUD "/process_status"
 #define OPT_PROCESS_USERINFO    OPT_PIDGINAUD "/process_userinfo"
+#define OPT_SONG_TEMPLATE       OPT_PIDGINAUD "/song_template"
 #define OPT_PASTE_TEMPLATE      OPT_PIDGINAUD "/paste_template"
 
+#define DEFAULT_SONG_TEMPLATE   "%artist - %title"
 #define SONG_TOKEN              "%song"
 #define NO_SONG_MESSAGE         "No song being played."
 
+#define DBUS_TYPE_G_STRING_VALUE_HASHTABLE (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE))
+
 #define aud_debug(fmt, ...)     purple_debug(PURPLE_DEBUG_INFO, \
                                              "Pidgin-Audacious", \
                                              fmt, ## __VA_ARGS__);
 #define aud_error(fmt, ...)     purple_debug(PURPLE_DEBUG_ERROR, \
                                              "Pidgin-Audacious", \
                                              fmt, ## __VA_ARGS__);
-
-static gint timeout_tag = 0;
-
-GHashTable *seed_status;
-GHashTable *seed_userinfo;
+/* xxx move up */
+#define TITLE   "%title"
+#define ARTIST  "%artist"
+#define ALBUM   "%album"
+#define GENRE   "%genre"
 
-GHashTable *pushed_status;
-GHashTable *pushed_userinfo;
+typedef struct song_tuple {
+    gchar *title;
+    gchar *artist;
+    gchar *album;
+    gchar *genre;
+} song_tuple;
+
 
-DBusGConnection *connection = NULL;
-DBusGProxy *session = NULL;
-
+/* globals */
+static GHashTable *seed_status;
+static GHashTable *seed_userinfo;
+static GHashTable *pushed_status;
+static GHashTable *pushed_userinfo;
+static DBusGConnection *connection = NULL;
+static DBusGProxy *session = NULL;
 static PurpleCmdId cmdid_paste_current_song;
 
+/* prototypes */
+extern gchar *botch_utf(const gchar *msg, gsize len, gsize *newlen) __attribute__ ((weak));
 static void aud_process(gchar *aud_info);
+static void track_signal_cb(DBusGProxy *player_proxy, GHashTable *table, gpointer data);
+static void status_signal_cb(DBusGProxy *player_proxy, gint status, gpointer data);
+static gboolean is_app_running(void);
+static GHashTable *get_song_table(void);
+static song_tuple *get_song_tuple(GHashTable *table);
+
+
+/* implementation */
 
 static DBusGProxy *
-get_dbus_proxy(void)
+get_dbus_session(void)
 {
     GError *error = NULL;
+    DBusGProxy *proxy;
     connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
     g_clear_error(&error);
 
-    session = dbus_g_proxy_new_for_name(connection, AUDACIOUS_DBUS_SERVICE,
-                                        AUDACIOUS_DBUS_PATH,
-                                        AUDACIOUS_DBUS_INTERFACE);
+	proxy = dbus_g_proxy_new_for_name(connection,
+                                      "org.mpris.audacious",
+                                      "/Player",
+                                      "org.freedesktop.MediaPlayer");
 
     g_clear_error(&error);
-    return session;
+    return proxy;
+}
+
+
+static void
+connect_dbus_signals()
+{
+	dbus_g_proxy_add_signal(session,
+                            "TrackChange",
+                            DBUS_TYPE_G_STRING_VALUE_HASHTABLE,
+                            G_TYPE_INVALID);
+
+	dbus_g_proxy_connect_signal(session,
+                                "TrackChange",
+                                G_CALLBACK(track_signal_cb),
+                                NULL, NULL);
+
+	dbus_g_proxy_add_signal(session,
+                            "StatusChange",
+                            G_TYPE_INT, G_TYPE_INVALID);
+
+	dbus_g_proxy_connect_signal(session,
+                                "StatusChange",
+                                G_CALLBACK(status_signal_cb),
+                                NULL, NULL);
+}
+
+static GHashTable *
+get_song_table(void)
+{
+    GHashTable *table = NULL;
+
+	status_signal_cb(NULL, -1, NULL);
+
+	if(is_app_running()) {
+		dbus_g_proxy_call(session,
+                          "GetMetadata",
+                          NULL,
+                          G_TYPE_INVALID,
+                          DBUS_TYPE_G_STRING_VALUE_HASHTABLE,
+                          &table,
+                          G_TYPE_INVALID);
+	}
+
+    return table;
+}
+
+static song_tuple *
+get_song_tuple(GHashTable *table)
+{
+    song_tuple *t = NULL;
+	GValue *value;
+
+    if(!table)
+        return NULL;
+
+    t = g_new0(song_tuple, 1);
+
+	value = (GValue *) g_hash_table_lookup(table, "title");
+	if (value && G_VALUE_HOLDS_STRING(value)) {
+		t->title = g_value_dup_string(value);
+	}
+	value = (GValue *) g_hash_table_lookup(table, "artist");
+	if (value != NULL && G_VALUE_HOLDS_STRING(value)) {
+		t->artist = g_value_dup_string(value);
+	}
+	value = (GValue *) g_hash_table_lookup(table, "album");
+	if (value != NULL && G_VALUE_HOLDS_STRING(value)) {
+		t->album = g_value_dup_string(value);
+	}
+	value = (GValue *) g_hash_table_lookup(table, "genre");
+	if (value != NULL && G_VALUE_HOLDS_STRING(value)) {
+		t->genre = g_value_dup_string(value);
+	}
+
+    return t;
 }
 
+void
+free_song_tuple(song_tuple *t)
+{
+    g_free(t->title);
+    g_free(t->artist);
+    g_free(t->album);
+    g_free(t->genre);
+
+    g_free(t);
+}
+
+
+static gchar *
+format_song_info(song_tuple *tuple)
+{
+    gchar *song_info = NULL, *tmp = NULL;
+
+    if(!tuple)
+        return NULL;
+
+	song_info = g_strdup(purple_prefs_get_string(OPT_SONG_TEMPLATE));
+    if(!song_info)
+        return NULL;
+
+    if(tuple->title && strstr(song_info, TITLE)) {
+        tmp = purple_strreplace(song_info, TITLE, tuple->title);
+        g_free(song_info);
+        song_info = tmp;
+    }
+    if(tuple->artist && strstr(song_info, ARTIST)) {
+        tmp = purple_strreplace(song_info, ARTIST, tuple->artist);
+        g_free(song_info);
+        song_info = tmp;
+    }
+    if(tuple->album && strstr(song_info, ALBUM)) {
+        tmp = purple_strreplace(song_info, ALBUM, tuple->album);
+        g_free(song_info);
+        song_info = tmp;
+    }
+    if(tuple->genre && strstr(song_info, GENRE)) {
+        tmp = purple_strreplace(song_info, GENRE, tuple->genre);
+        g_free(song_info);
+        song_info = tmp;
+    }
+
+    return song_info;
+}
+
+
+
+static void
+track_signal_cb(DBusGProxy *player_proxy, GHashTable *table, gpointer data)
+{
+    gchar *song_info = NULL;
+    song_tuple *tuple = get_song_tuple(table);
+
+    /* set current song */
+    purple_util_set_current_song(tuple->title ? tuple->title : "",
+                                 tuple->artist ? tuple->artist : "",
+                                 tuple->album ? tuple->album : "");
+
+    song_info = format_song_info(tuple);
+
+	aud_process(song_info);
+    free_song_tuple(tuple);
+	g_free(song_info);
+}
+
+
+static void
+status_signal_cb(DBusGProxy *player_proxy, gint status, gpointer data)
+{
+	aud_debug("StatusChange %d\n", status);
+
+	if (status != 0) {
+		aud_process("");
+
+        /* clear current song */
+        purple_util_set_current_song(NULL, NULL, NULL);
+
+	}
+}
+
+
+#if 0
 static gboolean
 watchdog_func(void)
 {
@@ -90,7 +274,7 @@
     size_t dummy;
 
     if(!session) {
-        session = get_dbus_proxy();
+        session = get_dbus_session();
     }
 
     aud_debug("session = %p\n", session);
@@ -134,6 +318,11 @@
 
     return rv;
 }
+#endif
+
+
+
+
 
 static void
 aud_process_status(PurpleConnection *gc, gchar *aud_info)
@@ -322,9 +511,10 @@
         if (purple_prefs_get_bool(OPT_PROCESS_STATUS)) {
             aud_process_status(gc, aud_info);
         }
+    }
 
-    }
 }
+
 static void
 removekey(gpointer data)
 {
@@ -337,23 +527,30 @@
     g_free(data);
 }
 
+
+
+
+
 static PurpleCmdRet
 paste_current_song(PurpleConversation *conv, const gchar *cmd,
                    gchar **args, gchar **error, void *data)
 {
-    gint playpos = 0;
     gchar *song = NULL, *tmp = NULL, *tmp2 = NULL;
     PurpleConversationType type = purple_conversation_get_type(conv);
     size_t dummy;
     const gchar *template = NULL;
 
     /* audacious isn't playing */
-    if(!audacious_remote_is_playing(session)) {
+    if(!is_app_running()) {
         return PURPLE_CMD_RET_OK;
     }
 
-    playpos = audacious_remote_get_playlist_pos(session);
-    tmp = audacious_remote_get_playlist_title(session, playpos);
+    /* dbus lookup */
+    GHashTable *table = get_song_table();
+    song_tuple *tuple = get_song_tuple(table);
+    tmp = format_song_info(tuple);
+    free_song_tuple(tuple);
+    g_hash_table_destroy(table);
 
     template = purple_prefs_get_string(OPT_PASTE_TEMPLATE);
 
@@ -391,6 +588,66 @@
     return PURPLE_CMD_RET_OK;
 }
 
+
+
+
+
+static gboolean
+is_app_running(void)
+{
+	gchar *player_name = g_strconcat("org.mpris.", "audacious", NULL);
+
+#if 0
+	if(g_strcasecmp(pidginmpris->player_name, player_name) != 0) {
+		pidginmpris->player_name = g_strdup(player_name);
+		g_object_unref(pidginmpris->player);
+		mpris_connect_dbus_signals();
+	}
+#endif
+
+	DBusGProxy *player =
+        dbus_g_proxy_new_for_name_owner(connection,
+                                        player_name,
+                                        "/Player",
+                                        "org.freedesktop.MediaPlayer",
+                                        NULL);
+
+	if(!player)
+		return FALSE;
+
+	g_object_unref(player);
+	g_free(player_name);
+	return TRUE;
+}
+
+static void
+signed_on_cb(PurpleConnection *gc, void *data)
+{
+    gchar *song_info = NULL;
+    GHashTable *table = NULL;
+    song_tuple *tuple = NULL;
+
+    table = get_song_table();
+    tuple = get_song_tuple(table);
+
+    song_info = format_song_info(tuple);
+    free_song_tuple(tuple);
+    g_hash_table_destroy(table);
+
+    if(song_info)
+        aud_process(song_info);
+
+    g_free(song_info);
+}
+
+
+static void prefs_cb(const char *name, PurplePrefType type,
+                    gconstpointer value, gpointer data)
+{
+	aud_debug("settings change detected at %s\n", name);
+	signed_on_cb(NULL, NULL);
+}
+
 static gboolean
 load_plugin(PurplePlugin *plugin)
 {
@@ -404,8 +661,34 @@
     pushed_userinfo = g_hash_table_new_full(g_str_hash, g_str_equal,
                                             removekey, removeval);
 
-    timeout_tag = g_timeout_add(15*1000, (gpointer)watchdog_func, NULL);
+
+    session = get_dbus_session();
+
+    /* connect to mpris signals */
+	connect_dbus_signals();
+
+    /* connect to purple signals */
+	purple_signal_connect(purple_connections_get_handle(),
+                          "signed-on",
+                          plugin,
+                          PURPLE_CALLBACK(signed_on_cb),
+                          NULL);
 
+	purple_signal_connect(purple_savedstatuses_get_handle(),
+                          "savedstatus-changed",
+                          plugin,
+                          PURPLE_CALLBACK(signed_on_cb),
+                          NULL);
+
+	purple_prefs_connect_callback(purple_prefs_get_handle(),
+                                  OPT_PIDGINAUD,
+                                  prefs_cb,
+                                  NULL);
+
+	status_signal_cb(NULL, -1, NULL);
+
+
+    /* register /song command */
     cmdid_paste_current_song =
         purple_cmd_register("song", "", PURPLE_CMD_P_DEFAULT,
                             PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT,
@@ -420,8 +703,6 @@
 {
     aud_debug("pidgin-audacious unload called\n");
 
-    g_source_remove(timeout_tag);
-
     g_hash_table_destroy(seed_status);
     g_hash_table_destroy(seed_userinfo);
 
@@ -430,8 +711,10 @@
 
     purple_cmd_unregister(cmdid_paste_current_song);
 
-    g_object_unref(session);
-    session = NULL;
+    if(session) {
+        g_object_unref(session);
+        session = NULL;
+    }
 
     if(connection) {
         dbus_g_connection_unref(connection);
@@ -462,6 +745,12 @@
         "Expand " SONG_TOKEN " to song info in the user info");
     purple_plugin_pref_frame_add(frame, pref);
 
+    /* song template */
+    pref = purple_plugin_pref_new_with_name_and_label(
+        OPT_SONG_TEMPLATE,
+        "Song template");
+    purple_plugin_pref_frame_add(frame, pref);
+
     /* paste template */
     pref = purple_plugin_pref_new_with_name_and_label(
         OPT_PASTE_TEMPLATE,
@@ -488,7 +777,7 @@
     PURPLE_PRIORITY_DEFAULT,    /**< priority */
     PIDGINAUD_PLUGIN_ID,        /**< id     */
     "Pidgin-Audacious",         /**< name   */
-    "2.1.0d2",                  /**< version */
+    "3.0.0d2",                  /**< version */
     "Automatically updates your Pidgin status info with the currently "
     "playing music in Audacious.", /**  summary */
     "Automatically updates your Pidgin status info with the currently "
@@ -513,6 +802,7 @@
     purple_prefs_add_none(OPT_PIDGINAUD);
     purple_prefs_add_bool(OPT_PROCESS_STATUS, TRUE);
     purple_prefs_add_bool(OPT_PROCESS_USERINFO, TRUE);
+    purple_prefs_add_string(OPT_SONG_TEMPLATE, DEFAULT_SONG_TEMPLATE);
     purple_prefs_add_string(OPT_PASTE_TEMPLATE, SONG_TOKEN);
 
 }