aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile7
-rw-r--r--README.md14
-rw-r--r--config.def.h17
-rw-r--r--mpd-notification.c157
-rw-r--r--mpd-notification.h6
5 files changed, 126 insertions, 75 deletions
diff --git a/Makefile b/Makefile
index f604121..cbfcdee 100644
--- a/Makefile
+++ b/Makefile
@@ -9,10 +9,7 @@ RM := rm
# flags
CFLAGS_EXTRA += -std=c11 -O2 -fPIC -Wall -Werror
-ifneq ($(wildcard /usr/include/iniparser),)
-CFLAGS_EXTRA += -I/usr/include/iniparser
-endif
-CFLAGS_EXTRA += -liniparser
+CFLAGS_EXTRA += $(shell pkg-config --cflags --libs iniparser)
CFLAGS_SYSTEMD := $(shell pkg-config --cflags --libs libsystemd 2>/dev/null)
ifneq ($(CFLAGS_SYSTEMD),)
CFLAGS_EXTRA += -DHAVE_SYSTEMD $(CFLAGS_SYSTEMD)
@@ -28,7 +25,7 @@ LDFLAGS += -Wl,-z,now -Wl,-z,relro -pie
# this is just a fallback in case you do not use git but downloaded
# a release tarball...
-VERSION := 0.8.7
+VERSION := 0.9.1
all: mpd-notification README.html
diff --git a/README.md b/README.md
index fb93db8..965e4cc 100644
--- a/README.md
+++ b/README.md
@@ -65,7 +65,6 @@ or `systemctl --user enable mpd-notification`.
* *-m MUSIC-DIR*: use *MUSIC-DIR* for artwork lookup
* *--notification-file-workaround*: write artwork to file for notification
daemons that do required it
-* *-o*: Notification text is one line (no line breaks)
* *-p PORT*: connect to *PORT*
* *-s PIXELS*: scale image to a maximum size *PIXELS* x *PIXELS* pixels, keeping
ratio
@@ -84,12 +83,23 @@ look like this:
host = localhost
port = 6600
music-dir = /srv/media/music/
- oneline = true
scale = 200
+ text-topic = MPD Notification
+ text-play = Playing <b>%t</b>\nby <i>%a</i>\nfrom <i>%A</i>
+ text-pause = Paused <b>%t</b>\nby <i>%a</i>\nfrom <i>%A</i>
+ text-stop = Stopped playback
timeout = 20
Unused options can be commented or removed completely.
+The options `text-play` and `text-pause` support custom formatting with
+these specifiers:
+
+* *%t*: title
+* *%a*: artist
+* *%A*: album
+* *%d*: duration
+
Artwork
-------
diff --git a/config.def.h b/config.def.h
index bc64e88..b8ef018 100644
--- a/config.def.h
+++ b/config.def.h
@@ -26,15 +26,14 @@
#define ICON_AUDIO_X_GENERIC "audio-x-generic"
/* strings used to display notification messages
- * TEXT_PLAY_* need to include one string modifier '%s' each. */
-#define TEXT_TOPIC "MPD Notification"
-#define TEXT_PLAY_PAUSE_STATE "%s "
-#define TEXT_PLAY_PAUSE_TITLE "<b>%s</b>"
-#define TEXT_PLAY_PAUSE_ARTIST "by <i>%s</i>"
-#define TEXT_PLAY_PAUSE_ALBUM "from <i>%s</i>"
-#define TEXT_STOP "Stopped playback"
-#define TEXT_NONE "No action received yet."
-#define TEXT_UNKNOWN "(unknown)"
+ * TEXT_PLAY & TEXT_PAUSE can include several specifiers:
+ * %t for title, %a for artist, %A for album and %d for duration */
+#define TEXT_TOPIC "MPD Notification"
+#define TEXT_PLAY "Playing <b>%t</b>\nby <i>%a</i>\nfrom <i>%A</i>"
+#define TEXT_PAUSE "Paused <b>%t</b>\nby <i>%a</i>\nfrom <i>%A</i>"
+#define TEXT_STOP "Stopped playback"
+#define TEXT_NONE "No action received yet"
+#define TEXT_UNKNOWN "(unknown)"
/* this is a regular expression that has to match image filename used
* for artwork */
diff --git a/mpd-notification.c b/mpd-notification.c
index 2e48bb0..af8985a 100644
--- a/mpd-notification.c
+++ b/mpd-notification.c
@@ -18,13 +18,12 @@
#include "mpd-notification.h"
-const static char optstring[] = "hH:m:op:s:t:vV";
+const static char optstring[] = "hH:m:p:s:t:vV";
const static struct option options_long[] = {
/* name has_arg flag val */
{ "help", no_argument, NULL, 'h' },
{ "host", required_argument, NULL, 'H' },
{ "music-dir", required_argument, NULL, 'm' },
- { "oneline", no_argument, NULL, 'o' },
{ "port", required_argument, NULL, 'p' },
{ "scale", required_argument, NULL, 's' },
{ "timeout", required_argument, NULL, 't' },
@@ -41,7 +40,6 @@ NotifyNotification * notification = NULL;
struct mpd_connection * conn = NULL;
uint8_t doexit = 0;
uint8_t verbose = 0;
-uint8_t oneline = 0;
#ifdef HAVE_LIBAV
magic_t magic = NULL;
#endif
@@ -105,7 +103,10 @@ GdkPixbuf * retrieve_artwork(const char * music_dir, const char * uri) {
if (verbose > 0)
printf("%s: MIME type for %s is: %s\n", program, uri_path, magic_mime);
- if (strcmp(magic_mime, "audio/mpeg") != 0)
+ /* Are there more mime-types supporting embedded artwork? Tell me! */
+ if (strcmp(magic_mime, "audio/mp4") != 0 &&
+ strcmp(magic_mime, "audio/mpeg") != 0 &&
+ strcmp(magic_mime, "audio/x-m4a") != 0)
goto image;
if ((pFormatCtx = avformat_alloc_context()) == NULL) {
@@ -118,11 +119,6 @@ GdkPixbuf * retrieve_artwork(const char * music_dir, const char * uri) {
goto image;
}
- if (pFormatCtx->iformat->read_header(pFormatCtx) < 0) {
- fprintf(stderr, "%s: Could not read the format header.\n", program);
- goto image;
- }
-
/* find the first attached picture, if available */
for (i = 0; i < pFormatCtx->nb_streams; i++) {
if (pFormatCtx->streams[i]->disposition & AV_DISPOSITION_ATTACHED_PIC) {
@@ -149,6 +145,9 @@ GdkPixbuf * retrieve_artwork(const char * music_dir, const char * uri) {
}
}
+ if (pixbuf == NULL && verbose > 0)
+ printf("%s: No artwork in media file.\n", program);
+
image:
#endif
@@ -208,26 +207,72 @@ done:
return pixbuf;
}
-/*** append_string ***/
-char * append_string(char * string, const char * format, const char delim, const char * s) {
- char * tmp, * offset;
-
- tmp = g_markup_escape_text(s, -1);
-
- string = realloc(string, strlen(string) + strlen(format) + strlen(tmp) + 2 /* delim + line break */);
-
- offset = string + strlen(string);
-
- if (delim > 0) {
- *offset = delim;
- offset++;
- }
-
- sprintf(offset, format, tmp);
+/*** format_text ***/
+char * format_text(const char* format, const char* title, const char* artist, const char* album, unsigned int duration) {
+ char * formatted, * tmp = NULL;
+ size_t len;
+
+ if (format == NULL || strlen(format) == 0)
+ return NULL;
+
+ formatted = strdup("");
+ len = 0;
+
+ do {
+ if (*format == '%') {
+ format++;
+
+ switch (*format) {
+ case 'a':
+ tmp = g_markup_escape_text(artist, -1);
+ break;
+
+ case 'A':
+ tmp = g_markup_escape_text(album, -1);
+ break;
+
+ case 'd':
+ size_t size;
+ size = snprintf(tmp, 0, "%d:%02d", duration / 60, duration % 60) + 1;
+ tmp = malloc(size);
+ snprintf(tmp, size, "%d:%02d", duration / 60, duration % 60);
+ break;
+
+ case 't':
+ tmp = g_markup_escape_text(title, -1);
+ break;
+
+ default:
+ formatted = realloc(formatted, len + 2);
+ sprintf(formatted + len, "%%");
+ format--;
+ break;
+ }
- free(tmp);
+ if (tmp != NULL) {
+ formatted = realloc(formatted, len + strlen(tmp) + 1);
+ sprintf(formatted + len, "%s", tmp);
+ free(tmp);
+ tmp = NULL;
+ }
+ } else if (*format == '\\') {
+ format++;
+ formatted = realloc(formatted, len + 2);
+
+ if (*format == 'n') {
+ sprintf(formatted + len, "\n");
+ } else {
+ sprintf(formatted + len, "\\");
+ format--;
+ }
+ } else {
+ formatted = realloc(formatted, len + 2);
+ sprintf(formatted + len, "%c", *format);
+ }
+ len = strlen(formatted);
+ } while (*format++);
- return string;
+ return formatted;
}
/*** main ***/
@@ -238,10 +283,11 @@ int main(int argc, char ** argv) {
GdkPixbuf * pixbuf = NULL;
GError * error = NULL;
enum mpd_state state = MPD_STATE_UNKNOWN, last_state = MPD_STATE_UNKNOWN;
- const char * mpd_host, * mpd_port_str, * music_dir, * uri = NULL;
+ const char * mpd_host, * mpd_port_str, * music_dir, * text_topic = TEXT_TOPIC,
+ * text_play = TEXT_PLAY, * text_pause = TEXT_PAUSE, * text_stop = TEXT_STOP, * uri = NULL;
unsigned mpd_port = MPD_PORT, mpd_timeout = MPD_TIMEOUT, notification_timeout = NOTIFICATION_TIMEOUT;
struct mpd_song * song = NULL;
- unsigned int i, version = 0, help = 0, scale = 0, file_workaround = 0;
+ unsigned int i, version = 0, help = 0, scale = 0, file_workaround = 0, duration;
int rc = EXIT_FAILURE;
program = argv[0];
@@ -268,8 +314,11 @@ int main(int argc, char ** argv) {
mpd_port = iniparser_getint(ini, ":port", mpd_port);
music_dir = iniparser_getstring(ini, ":music-dir", music_dir);
notification_timeout = iniparser_getint(ini, ":timeout", notification_timeout);
- oneline = iniparser_getboolean(ini, ":oneline", oneline);
scale = iniparser_getint(ini, ":scale", scale);
+ text_topic = iniparser_getstring(ini, ":text-topic", text_topic);
+ text_play = iniparser_getstring(ini, ":text-play", text_play);
+ text_pause = iniparser_getstring(ini, ":text-pause", text_pause);
+ text_stop = iniparser_getstring(ini, ":text-stop", text_stop);
}
/* get the verbose status */
@@ -278,9 +327,6 @@ int main(int argc, char ** argv) {
case 'h':
help++;
break;
- case 'o':
- oneline++;
- break;
case 'v':
verbose++;
break;
@@ -306,7 +352,7 @@ int main(int argc, char ** argv) {
" (compiled: " __DATE__ ", " __TIME__ ")\n", program, PROGNAME, VERSION);
if (help > 0)
- fprintf(stderr, "usage: %s [-h] [-H HOST] [-m MUSIC-DIR] [-o] [-p PORT] [-s PIXELS] [-t TIMEOUT] [-v] [-V]\n", program);
+ fprintf(stderr, "usage: %s [-h] [-H HOST] [-m MUSIC-DIR] [-p PORT] [-s PIXELS] [-t TIMEOUT] [-v] [-V]\n", program);
if (version > 0 || help > 0)
return EXIT_SUCCESS;
@@ -387,18 +433,21 @@ int main(int argc, char ** argv) {
notification =
# if NOTIFY_CHECK_VERSION(0, 7, 0)
- notify_notification_new(TEXT_TOPIC, TEXT_NONE, ICON_AUDIO_X_GENERIC);
+ notify_notification_new(text_topic, TEXT_NONE, ICON_AUDIO_X_GENERIC);
# else
- notify_notification_new(TEXT_TOPIC, TEXT_NONE, ICON_AUDIO_X_GENERIC, NULL);
+ notify_notification_new(text_topic, TEXT_NONE, ICON_AUDIO_X_GENERIC, NULL);
# endif
notify_notification_set_category(notification, PROGNAME);
notify_notification_set_urgency(notification, NOTIFY_URGENCY_NORMAL);
notify_notification_set_timeout(notification, notification_timeout * 1000);
- signal(SIGHUP, received_signal);
- signal(SIGINT, received_signal);
- signal(SIGTERM, received_signal);
- signal(SIGUSR1, received_signal);
+ struct sigaction act = { 0 };
+ act.sa_handler = received_signal;
+
+ sigaction(SIGHUP, &act, NULL);
+ sigaction(SIGINT, &act, NULL);
+ sigaction(SIGTERM, &act, NULL);
+ sigaction(SIGUSR1, &act, NULL);
/* report ready to systemd */
#ifdef HAVE_SYSTEMD
@@ -417,7 +466,7 @@ int main(int argc, char ** argv) {
* too late, which results in issue with image date. Make sure to
* show a notification without image data (just generic icon) first. */
if (last_state != MPD_STATE_PLAY && last_state != MPD_STATE_PAUSE) {
- notify_notification_update(notification, TEXT_TOPIC, "Starting playback...", ICON_AUDIO_X_GENERIC);
+ notify_notification_update(notification, text_topic, "Starting playback...", ICON_AUDIO_X_GENERIC);
notify_notification_show(notification, NULL);
}
@@ -425,7 +474,10 @@ int main(int argc, char ** argv) {
song = mpd_recv_song(conn);
- title = mpd_song_get_tag(song, MPD_TAG_TITLE, 0);
+ title = mpd_song_get_tag(song, MPD_TAG_TITLE, 0);
+ artist = mpd_song_get_tag(song, MPD_TAG_ARTIST, 0);
+ album = mpd_song_get_tag(song, MPD_TAG_ALBUM, 0);
+ duration = mpd_song_get_duration(song);
/* ignore if we have no title */
if (title == NULL)
@@ -435,16 +487,9 @@ int main(int argc, char ** argv) {
sd_notifyf(0, "READY=1\nSTATUS=%s: %s", state == MPD_STATE_PLAY ? "Playing" : "Paused", title);
#endif
- /* initial allocation and string termination */
- notifystr = strdup("");
- notifystr = append_string(notifystr, TEXT_PLAY_PAUSE_STATE, 0, state == MPD_STATE_PLAY ? "Playing": "Paused");
- notifystr = append_string(notifystr, TEXT_PLAY_PAUSE_TITLE, 0, title);
-
- if ((artist = mpd_song_get_tag(song, MPD_TAG_ARTIST, 0)) != NULL)
- notifystr = append_string(notifystr, TEXT_PLAY_PAUSE_ARTIST, oneline ? ' ' : '\n', artist);
-
- if ((album = mpd_song_get_tag(song, MPD_TAG_ALBUM, 0)) != NULL)
- notifystr = append_string(notifystr, TEXT_PLAY_PAUSE_ALBUM, oneline ? ' ' : '\n', album);
+ /* get the formatted notification string */
+ notifystr = format_text(state == MPD_STATE_PLAY ? text_play : text_pause,
+ title, artist ? artist : "unknown artist", album ? album : "unknown album", duration);
uri = mpd_song_get_uri(song);
@@ -473,9 +518,9 @@ int main(int argc, char ** argv) {
mpd_song_free(song);
} else if (state == MPD_STATE_STOP) {
- notifystr = strdup(TEXT_STOP);
+ notifystr = strdup(text_stop);
#ifdef HAVE_SYSTEMD
- sd_notify(0, "READY=1\nSTATUS=" TEXT_STOP);
+ sd_notifyf(0, "READY=1\nSTATUS=%s", text_stop);
#endif
} else
notifystr = strdup(TEXT_UNKNOWN);
@@ -490,9 +535,9 @@ int main(int argc, char ** argv) {
if (file_workaround > 0 && pixbuf != NULL) {
gdk_pixbuf_save(pixbuf, "/tmp/.mpd-notification-artwork.png", "png", NULL, NULL);
- notify_notification_update(notification, TEXT_TOPIC, notifystr, "/tmp/.mpd-notification-artwork.png");
+ notify_notification_update(notification, text_topic, notifystr, "/tmp/.mpd-notification-artwork.png");
} else
- notify_notification_update(notification, TEXT_TOPIC, notifystr, ICON_AUDIO_X_GENERIC);
+ notify_notification_update(notification, text_topic, notifystr, ICON_AUDIO_X_GENERIC);
/* Call this unconditionally! When pixbuf is NULL this clears old image. */
notify_notification_set_image_from_pixbuf(notification, pixbuf);
diff --git a/mpd-notification.h b/mpd-notification.h
index cd8b386..d11e822 100644
--- a/mpd-notification.h
+++ b/mpd-notification.h
@@ -34,7 +34,7 @@
#include <systemd/sd-daemon.h>
#endif
-#include <iniparser.h>
+#include <iniparser/iniparser.h>
#include <libnotify/notify.h>
#include <mpd/client.h>
@@ -56,8 +56,8 @@ void received_signal(int signal);
/*** retrieve_artwork ***/
GdkPixbuf * retrieve_artwork(const char * music_dir, const char * uri);
-/*** append_string ***/
-char * append_string(char * string, const char * format, const char delim, const char * s);
+/*** format_text ***/
+char * format_text(const char* format, const char* title, const char* artist, const char* album, unsigned int duration);
/*** main ***/
int main(int argc, char ** argv);