diff options
-rw-r--r-- | plugins/artwork/Makefile.am | 2 | ||||
-rw-r--r-- | plugins/artwork/artwork.c | 93 | ||||
-rw-r--r-- | plugins/artwork/artwork.h | 2 | ||||
-rw-r--r-- | plugins/gtkui/coverart.c | 2 | ||||
-rw-r--r-- | plugins/gtkui/gtkui.c | 2 | ||||
-rw-r--r-- | plugins/notify/notify.c | 247 |
6 files changed, 215 insertions, 133 deletions
diff --git a/plugins/artwork/Makefile.am b/plugins/artwork/Makefile.am index b60c86cb..4ca2ed19 100644 --- a/plugins/artwork/Makefile.am +++ b/plugins/artwork/Makefile.am @@ -5,6 +5,6 @@ artwork_la_SOURCES = artwork.c artwork.h albumartorg.c albumartorg.h lastfm.c la artwork_la_LDFLAGS = -module -artwork_la_LIBADD = $(LDADD) $(ARTWORK_DEPS_LIBS) +artwork_la_LIBADD = $(LDADD) $(ARTWORK_DEPS_LIBS) -lImlib2 AM_CFLAGS = -std=c99 $(ARTWORK_DEPS_CFLAGS) endif diff --git a/plugins/artwork/artwork.c b/plugins/artwork/artwork.c index b8258957..c9d5c964 100644 --- a/plugins/artwork/artwork.c +++ b/plugins/artwork/artwork.c @@ -7,6 +7,7 @@ #include <unistd.h> #include <fnmatch.h> #include <inttypes.h> +#include <Imlib2.h> #include "../../deadbeef.h" #include "artwork.h" #include "lastfm.h" @@ -29,6 +30,7 @@ typedef struct cover_query_s { char *fname; char *artist; char *album; + int size; artwork_callback callback; void *user_data; struct cover_query_s *next; @@ -54,10 +56,17 @@ static const char *get_default_cover (void) { } int -make_cache_dir_path (char *path, int size, const char *artist) { +make_cache_dir_path (char *path, int size, const char *artist, int img_size) { const char *cache = getenv ("XDG_CACHE_HOME"); - int sz = snprintf (path, size, "%s/deadbeef/", cache ? cache : getenv ("HOME")); + int sz; + + if (img_size == -1) { + sz = snprintf (path, size, "%s/deadbeef/covers/", cache ? cache : getenv ("HOME")); + } + else { + sz = snprintf (path, size, "%s/deadbeef/covers-%d/", cache ? cache : getenv ("HOME"), img_size); + } path += sz; sz += snprintf (path, size-sz, "%s", artist); @@ -70,9 +79,9 @@ make_cache_dir_path (char *path, int size, const char *artist) { } void -make_cache_path (char *path, int size, const char *album, const char *artist) { +make_cache_path (char *path, int size, const char *album, const char *artist, int img_size) { char *p = path; - int sz = make_cache_dir_path (path, size, artist); + int sz = make_cache_dir_path (path, size, artist, img_size); size -= sz; path += sz; sz = snprintf (path, size, "/%s.jpg", album); @@ -84,7 +93,7 @@ make_cache_path (char *path, int size, const char *album, const char *artist) { } void -queue_add (const char *fname, const char *artist, const char *album, artwork_callback callback, void *user_data) { +queue_add (const char *fname, const char *artist, const char *album, int img_size, artwork_callback callback, void *user_data) { if (!artist) { artist = ""; } @@ -105,6 +114,7 @@ queue_add (const char *fname, const char *artist, const char *album, artwork_cal q->fname = strdup (fname); q->artist = strdup (artist); q->album = strdup (album); + q->size = img_size; q->callback = callback; q->user_data = user_data; if (queue_tail) { @@ -165,8 +175,47 @@ check_dir (const char *dir, mode_t mode) #define BUFFER_SIZE 4096 static int -copy_file (const char *in, const char *out) { +copy_file (const char *in, const char *out, int img_size) { trace ("copying %s to %s\n", in, out); + + if (img_size != -1) { + // need to scale, use imlib2 + Imlib_Image img = imlib_load_image_immediately (in); + if (!img) { + trace ("file %s not found, or imlib2 can't load it\n", in); + return -1; + } + imlib_context_set_image(img); + int w = imlib_image_get_width (); + int h = imlib_image_get_height (); + int sw, sh; + if (w < h) { + sh = img_size; + sw = img_size * w / h; + } + else { + sw = img_size; + sh = img_size * h / w; + } + Imlib_Image scaled = imlib_create_image (sw, sh); + imlib_context_set_image (scaled); + imlib_blend_image_onto_image (img, 1, 0, 0, w, h, 0, 0, sw, sh); + Imlib_Load_Error err = 0; + imlib_image_set_format ("jpg"); + imlib_save_image_with_error_return (out, &err); + if (err != 0) { + imlib_free_image (); + imlib_context_set_image(img); + imlib_free_image (); + return -1; + } + imlib_free_image (); + imlib_context_set_image(img); + imlib_free_image (); + + return 0; + } + FILE *fin = fopen (in, "rb"); if (!fin) { trace ("artwork: failed to open file %s for reading\n", in); @@ -290,7 +339,7 @@ fetcher_thread (void *none) struct dirent **files; int files_count; - make_cache_dir_path (path, sizeof (path), param->artist); + make_cache_dir_path (path, sizeof (path), param->artist, param->size); trace ("cache folder: %s\n", path); if (!check_dir (path, 0755)) { queue_pop (); @@ -349,7 +398,7 @@ fetcher_thread (void *none) char tmp_path[1024]; char cache_path[1024]; - make_cache_path (cache_path, sizeof (cache_path), param->album, param->artist); + make_cache_path (cache_path, sizeof (cache_path), param->album, param->artist, param->size); trace ("will write id3v2 APIC into %s\n", cache_path); snprintf (tmp_path, sizeof (tmp_path), "%s.part", cache_path); FILE *out = fopen (tmp_path, "w+b"); @@ -430,7 +479,7 @@ fetcher_thread (void *none) trace ("found apev2 cover art of %d bytes (%s)\n", sz, ext); char tmp_path[1024]; char cache_path[1024]; - make_cache_path (cache_path, sizeof (cache_path), param->album, param->artist); + make_cache_path (cache_path, sizeof (cache_path), param->album, param->artist, param->size); trace ("will write apev2 cover art into %s\n", cache_path); snprintf (tmp_path, sizeof (tmp_path), "%s.part", cache_path); FILE *out = fopen (tmp_path, "w+b"); @@ -491,9 +540,9 @@ fetcher_thread (void *none) strcat (path, files[0]->d_name); char cache_path[1024]; char tmp_path[1024]; - make_cache_path (cache_path, sizeof (cache_path), param->album, param->artist); + make_cache_path (cache_path, sizeof (cache_path), param->album, param->artist, param->size); snprintf (tmp_path, sizeof (tmp_path), "%s.part", cache_path); - copy_file (path, tmp_path); + copy_file (path, tmp_path, param->size); int err = rename (tmp_path, cache_path); if (err != 0) { trace ("Failed not move %s to %s: %s\n", tmp_path, cache_path, strerror (err)); @@ -513,7 +562,7 @@ fetcher_thread (void *none) } } - make_cache_path (path, sizeof (path), param->album, param->artist); + make_cache_path (path, sizeof (path), param->album, param->artist, param->size); if (artwork_enable_lfm && !fetch_from_lastfm (param->artist, param->album, path)) { trace ("art found on last.fm for %s %s\n", param->album, param->artist); @@ -552,7 +601,7 @@ fetcher_thread (void *none) } char* -get_album_art (const char *fname, const char *artist, const char *album, artwork_callback callback, void *user_data) +get_album_art (const char *fname, const char *artist, const char *album, int size, artwork_callback callback, void *user_data) { // trace ("get_album_art: %s (%s - %s)\n", fname, artist, album); char path [1024]; @@ -567,14 +616,14 @@ get_album_art (const char *fname, const char *artist, const char *album, artwork if (!*artist || !*album) { //give up - return strdup (get_default_cover ()); + return size == -1 ? strdup (get_default_cover ()) : NULL; } if (!deadbeef->is_local_file (fname)) { - return strdup (get_default_cover ()); + return size == -1 ? strdup (get_default_cover ()) : NULL; } - make_cache_path (path, sizeof (path), album, artist); + make_cache_path (path, sizeof (path), album, artist, size); struct stat stat_buf; if (0 == stat (path, &stat_buf)) { int cache_period = deadbeef->conf_get_int ("artwork.cache.period", 48); @@ -584,16 +633,16 @@ get_album_art (const char *fname, const char *artist, const char *album, artwork || artwork_reset_time > stat_buf.st_mtime) { trace ("reloading cached file %s\n", path); unlink (path); - queue_add (fname, artist, album, callback, user_data); - return strdup (get_default_cover ()); + queue_add (fname, artist, album, size, callback, user_data); + return size == -1 ? strdup (get_default_cover ()) : NULL; } // trace ("found %s in cache, resettime %" PRId64 ", filetime %" PRId64 ", time %" PRId64 "\n", path, artwork_reset_time, stat_buf.st_mtime, tm); return strdup (path); } - queue_add (fname, artist, album, callback, user_data); - return strdup (get_default_cover ()); + queue_add (fname, artist, album, size, callback, user_data); + return size == -1 ? strdup (get_default_cover ()) : NULL; } DB_plugin_t * @@ -647,7 +696,7 @@ artwork_on_configchanged (DB_event_t *ev, uintptr_t data) { || new_artwork_enable_lfm != artwork_enable_lfm || new_artwork_enable_aao != artwork_enable_aao || strcmp (new_artwork_filemask, artwork_filemask)) { - printf ("artwork config changed, invalidating cache...\n"); + trace ("artwork config changed, invalidating cache...\n"); artwork_enable_embedded = new_artwork_enable_embedded; artwork_enable_local = new_artwork_enable_local; artwork_enable_lfm = new_artwork_enable_lfm; @@ -736,7 +785,7 @@ static DB_artwork_plugin_t plugin = { .plugin.plugin.version_major = 1, .plugin.plugin.version_minor = 0, .plugin.plugin.type = DB_PLUGIN_MISC, - .plugin.plugin.id = "cover_loader", + .plugin.plugin.id = "artwork", .plugin.plugin.name = "Album Artwork", .plugin.plugin.descr = "Loads album artwork either from local directories or from internet", .plugin.plugin.author = "Viktor Semykin, Alexey Yakovenko", diff --git a/plugins/artwork/artwork.h b/plugins/artwork/artwork.h index ed5357df..130bf3fe 100644 --- a/plugins/artwork/artwork.h +++ b/plugins/artwork/artwork.h @@ -10,7 +10,7 @@ typedef void (*artwork_callback) (const char *fname, const char *artist, const c typedef struct { DB_misc_t plugin; // returns filename of cached image, or NULL - char* (*get_album_art) (const char *fname, const char *artist, const char *album, artwork_callback callback, void *user_data); + char* (*get_album_art) (const char *fname, const char *artist, const char *album, int size, artwork_callback callback, void *user_data); // this has to be called to clear queue on exit, before caller terminates // `fast=1' means "don't wait, just flush queue" void (*reset) (int fast); diff --git a/plugins/gtkui/coverart.c b/plugins/gtkui/coverart.c index 158d7a1e..4118aa66 100644 --- a/plugins/gtkui/coverart.c +++ b/plugins/gtkui/coverart.c @@ -241,7 +241,7 @@ get_cover_art (const char *fname, const char *artist, const char *album, int wid if (!coverart_plugin) { return NULL; } - char *image_fname = coverart_plugin->get_album_art (fname, artist, album, cover_avail_callback, (void *)(intptr_t)width); + char *image_fname = coverart_plugin->get_album_art (fname, artist, album, -1, cover_avail_callback, (void *)(intptr_t)width); if (image_fname) { GdkPixbuf *pb = get_pixbuf (image_fname, width); free (image_fname); diff --git a/plugins/gtkui/gtkui.c b/plugins/gtkui/gtkui.c index d95592cf..b85dca4a 100644 --- a/plugins/gtkui/gtkui.c +++ b/plugins/gtkui/gtkui.c @@ -1187,7 +1187,7 @@ gtkui_connect_cb (void *none) { DB_plugin_t **plugins = deadbeef->plug_get_list (); for (int i = 0; plugins[i]; i++) { DB_plugin_t *p = plugins[i]; - if (p->id && !strcmp (p->id, "cover_loader")) { + if (p->id && !strcmp (p->id, "artwork")) { trace ("gtkui: found cover-art loader plugin\n"); coverart_plugin = (DB_artwork_plugin_t *)p; break; diff --git a/plugins/notify/notify.c b/plugins/notify/notify.c index 2b9bfadc..193f6bef 100644 --- a/plugins/notify/notify.c +++ b/plugins/notify/notify.c @@ -22,6 +22,7 @@ #include <stdlib.h> #include <string.h> #include "../../gettext.h" +#include "../artwork/artwork.h" #define E_NOTIFICATION_BUS_NAME "org.freedesktop.Notifications" #define E_NOTIFICATION_INTERFACE "org.freedesktop.Notifications" @@ -29,10 +30,12 @@ DB_functions_t *deadbeef; DB_misc_t plugin; +DB_artwork_plugin_t *artwork_plugin; static dbus_uint32_t replaces_id = 0; -#define NOTIFY_DEFAULT_FORMAT "%a - %t" +#define NOTIFY_DEFAULT_TITLE "%t" +#define NOTIFY_DEFAULT_CONTENT "%a - %b" static void notify_thread (void *ctx) { @@ -114,116 +117,130 @@ notify_marshal_dict_string(DBusMessageIter *iter, const char *key, const char *v } #endif +static void +esc_xml (const char *cmd, char *esc, int size) { + const char *src = cmd; + char *dst = esc; + char *end = dst + size - 1; + while (*src && dst < end) { + if (*src == '&') { + if (end - dst < 5) { + break; + } + strcpy (dst, "&"); + dst += 5; + src++; + } + else if (*src == '<') { + if (end - dst < 4) { + break; + } + strcpy (dst, "<"); + dst += 4; + src++; + } + else if (*src == '>') { + if (end - dst < 4) { + break; + } + strcpy (dst, ">"); + dst += 4; + src++; + } + else if (*src == '\'') { + if (end - dst < 6) { + break; + } + strcpy (dst, "'"); + dst += 6; + src++; + } + else if (*src == '"') { + if (end - dst < 6) { + break; + } + strcpy (dst, """); + dst += 6; + src++; + } + else { + *dst++ = *src++; + } + } + *dst = 0; +} + + +static void +cover_avail_callback (const char *fname, const char *artist, const char *album, void *user_data) { +// show_notification (track); +} + +static void show_notification (DB_playItem_t *track) { + char title[1024]; + char content[1024]; + deadbeef->pl_format_title (track, -1, title, sizeof (title), -1, deadbeef->conf_get_str ("notify.format", NOTIFY_DEFAULT_TITLE)); + deadbeef->pl_format_title (track, -1, content, sizeof (content), -1, deadbeef->conf_get_str ("notify.format_content", NOTIFY_DEFAULT_CONTENT)); + + // escape & + char esc_title[1024]; + char esc_content[1024]; + esc_xml (title, esc_title, sizeof (esc_title)); + esc_xml (content, esc_content, sizeof (esc_content)); + DBusMessage *msg = dbus_message_new_method_call (E_NOTIFICATION_BUS_NAME, E_NOTIFICATION_PATH, E_NOTIFICATION_INTERFACE, "Notify"); + + const char *v_appname = "DeaDBeeF"; + dbus_uint32_t v_id = 0; + char *v_iconname = NULL; + if (deadbeef->conf_get_int("notify.albumart", 0) && artwork_plugin) { + const char *album = deadbeef->pl_find_meta (track, "album"); + const char *artist = deadbeef->pl_find_meta (track, "artist"); + v_iconname = artwork_plugin->get_album_art (track->fname, artist, album, 48, cover_avail_callback, NULL); + } + if (!v_iconname) { + v_iconname = strdup ("deadbeef"); + } + const char *v_summary = esc_title; + const char *v_body = esc_content; + dbus_int32_t v_timeout = -1; + + dbus_message_append_args (msg + , DBUS_TYPE_STRING, &v_appname + , DBUS_TYPE_UINT32, &replaces_id + , DBUS_TYPE_STRING, &v_iconname + , DBUS_TYPE_STRING, &v_summary + , DBUS_TYPE_STRING, &v_body + , DBUS_TYPE_INVALID + ); + + DBusMessageIter iter, sub; + // actions + dbus_message_iter_init_append(msg, &iter); + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub); + dbus_message_iter_close_container(&iter, &sub); + // hints + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub); + dbus_message_iter_close_container(&iter, &sub); + + dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &v_timeout); + + intptr_t tid = 0; + if ((tid=deadbeef->thread_start(notify_thread, msg)) != 0) { + dbus_message_ref (msg); + deadbeef->thread_detach (tid); + } + dbus_message_unref (msg); + if (v_iconname) { + free (v_iconname); + } +} + static int on_songchanged (DB_event_trackchange_t *ev, uintptr_t data) { if (ev->to && deadbeef->conf_get_int ("notify.enable", 0)) { DB_playItem_t *track = ev->to; if (track) { - char cmd[1024]; - deadbeef->pl_format_title (track, -1, cmd, sizeof (cmd), -1, deadbeef->conf_get_str ("notify.format", NOTIFY_DEFAULT_FORMAT)); - - // escape & - char esc[1024]; - - char *src = cmd; - char *dst = esc; - char *end = dst + sizeof (esc) - 1; - while (*src && dst < end) { - if (*src == '&') { - if (end - dst < 5) { - break; - } - strcpy (dst, "&"); - dst += 5; - src++; - } - else if (*src == '<') { - if (end - dst < 4) { - break; - } - strcpy (dst, "<"); - dst += 4; - src++; - } - else if (*src == '>') { - if (end - dst < 4) { - break; - } - strcpy (dst, ">"); - dst += 4; - src++; - } - else if (*src == '\'') { - if (end - dst < 6) { - break; - } - strcpy (dst, "'"); - dst += 6; - src++; - } - else if (*src == '"') { - if (end - dst < 6) { - break; - } - strcpy (dst, """); - dst += 6; - src++; - } - else { - *dst++ = *src++; - } - } - *dst = 0; -/* - DBusError error; - dbus_error_init (&error); - DBusConnection *conn = dbus_bus_get (DBUS_BUS_SESSION, &error); - if(conn == NULL) { - printf("connection failed: %s",error.message); - exit(1); - } -*/ - DBusMessage *msg = dbus_message_new_method_call (E_NOTIFICATION_BUS_NAME, E_NOTIFICATION_PATH, E_NOTIFICATION_INTERFACE, "Notify"); - - const char *v_appname = "DeaDBeeF"; - dbus_uint32_t v_id = 0; - const char *v_iconname = "deadbeef"; - const char *v_summary = _("DeaDBeeF now playing"); - const char *v_body = esc; - dbus_int32_t v_timeout = -1; - - dbus_message_append_args (msg - , DBUS_TYPE_STRING, &v_appname -// , DBUS_TYPE_UINT32, &v_id - , DBUS_TYPE_UINT32, &replaces_id - , DBUS_TYPE_STRING, &v_iconname - , DBUS_TYPE_STRING, &v_summary - , DBUS_TYPE_STRING, &v_body - , DBUS_TYPE_INVALID - ); - - DBusMessageIter iter, sub; - // actions - dbus_message_iter_init_append(msg, &iter); - dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub); - dbus_message_iter_close_container(&iter, &sub); - // hints - dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub); - dbus_message_iter_close_container(&iter, &sub); - - dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &v_timeout); - - //int serial; - //dbus_bool_t retval = dbus_connection_send(conn,msg,&serial); - //dbus_connection_flush (conn); - //dbus_message_unref (msg); - - intptr_t tid = 0; - if ((tid=deadbeef->thread_start(notify_thread, msg)) != 0) { - dbus_message_ref (msg); - deadbeef->thread_detach (tid); - } - dbus_message_unref (msg); + show_notification (track); } } return 0; @@ -241,9 +258,23 @@ notify_stop (void) { return 0; } +static int +notify_connect (void) { + artwork_plugin = (DB_artwork_plugin_t *)deadbeef->plug_get_for_id ("artwork"); + return 0; +} + +static int +notify_disconnect (void) { + artwork_plugin = NULL; + return 0; +} + static const char settings_dlg[] = "property \"Enable\" checkbox notify.enable 0;\n" - "property \"Notification format\" entry notify.format \"" NOTIFY_DEFAULT_FORMAT "\";\n" + "property \"Notification title format\" entry notify.format \"" NOTIFY_DEFAULT_TITLE "\";\n" + "property \"Notification content format\" entry notify.format_content \"" NOTIFY_DEFAULT_CONTENT "\";\n" + "property \"Show album art\" checkbox notify.albumart 1;\n" ; DB_misc_t plugin = { @@ -259,6 +290,8 @@ DB_misc_t plugin = { .plugin.website = "http://deadbeef.sourceforge.net", .plugin.start = notify_start, .plugin.stop = notify_stop, + .plugin.connect = notify_connect, + .plugin.disconnect = notify_disconnect, .plugin.configdialog = settings_dlg, }; |