commit b89c0ccf95f120c45271c83f3159dfe37e82ed15
parent 518266ee6eb78ce8b616414cd7ee8f24cc3a6f8b
Author: lostd <lostd@2f30.org>
Date: Sun, 8 Mar 2015 13:10:27 +0200
Album art mpd client and merge with mpdlen
Diffstat:
5 files changed, 306 insertions(+), 39 deletions(-)
diff --git a/mpdlen/Makefile b/mpdlen/Makefile
@@ -1,7 +0,0 @@
-LDLIBS = -lmpdclient
-
-BIN = mpdlen
-all: $(BIN)
-
-clean:
- rm -f $(BIN)
diff --git a/mpdlen/mpdlen.c b/mpdlen/mpdlen.c
@@ -1,32 +0,0 @@
-#include <stdio.h>
-
-#include <mpd/client.h>
-
-/* usage: mpdlen [list] */
-
-int
-main(int argc, char *argv[])
-{
- struct mpd_connection *conn;
- struct mpd_song *song;
- unsigned secs = 0;
- char *list = argv[1];
-
- conn = mpd_connection_new(NULL, 0, 0);
-
- if (list != NULL)
- mpd_send_list_playlist_meta(conn, list);
- else
- mpd_send_list_queue_meta(conn);
-
- while ((song = mpd_recv_song(conn)) != NULL) {
- secs += mpd_song_get_duration(song);
- mpd_song_free(song);
- }
-
- mpd_connection_free(conn);
-
- printf("%02u:%02u:%02u\n", secs / 3600, secs % 3600 / 60, secs % 60);
-
- return 0;
-}
diff --git a/mpdutil/Makefile b/mpdutil/Makefile
@@ -0,0 +1,10 @@
+#CPPFLAGS = -g -DDEBUG
+CFLAGS = -I/usr/local/include
+LDFLAGS = -L/usr/local/lib
+LDLIBS = -lmpdclient
+
+BIN = mpdlen mpdart
+all: $(BIN)
+
+clean:
+ rm -f $(BIN)
diff --git a/mpdutil/mpdart.c b/mpdutil/mpdart.c
@@ -0,0 +1,261 @@
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <dirent.h>
+#include <libgen.h>
+#include <poll.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <mpd/client.h>
+
+#ifdef DEBUG
+#define DPRINTF printf
+#define DPRINTF_D(t) printf(#t"=%d\n", t)
+#define DPRINTF_U(t) printf(#t"=%u\n", t)
+#define DPRINTF_S(t) printf(#t"=%s\n", t)
+#else
+#define DPRINTF
+#define DPRINTF_D(t)
+#define DPRINTF_U(t)
+#define DPRINTF_S(t)
+#endif
+
+char *musicdir = "/home/lostd/.mpd/music";
+char **imgs;
+unsigned int cur;
+char *defimg = "/home/lostd/.mpdart.png";
+unsigned int cyclms = 3000;
+unsigned int pollms = 3000;
+int change;
+
+char *
+xdirname(const char *path)
+{
+ char *p, *tmp;
+
+ tmp = strdup(path);
+ p = dirname(tmp);
+ p = strdup(p);
+ free(tmp);
+
+ return p;
+}
+
+int
+imgcmp(const void *va, const void *vb)
+{
+ const char *a, *b;
+ static regex_t regex;
+
+ a = *(const char **)va;
+ b = *(const char **)vb;
+ DPRINTF_S(a);
+ DPRINTF_S(b);
+
+ /* Front covers first */
+ regcomp(®ex, "cover|front", REG_NOSUB | REG_EXTENDED);
+ if (regexec(®ex, a, 0, NULL, 0) == 0)
+ return -1;
+ if (regexec(®ex, b, 0, NULL, 0) == 0)
+ return 1;
+
+ return strcmp(a, b);
+}
+
+void
+init_imgs_default(void)
+{
+ DPRINTF("default\n");
+
+ imgs = malloc(2 * sizeof(*imgs));
+ imgs[0] = strdup(defimg);
+ imgs[1] = NULL;
+ cur = 0;
+}
+
+void
+init_imgs_from_path(char *path)
+{
+ DIR *dirp;
+ struct dirent *dp;
+ unsigned int n = 0;
+ static regex_t regex;
+
+ DPRINTF("images\n");
+
+ regcomp(®ex, "\\.(jpg|png|gif)$", REG_NOSUB | REG_EXTENDED);
+
+ dirp = opendir(path);
+ if (dirp == NULL)
+ err(1, "opendir %s", path);
+
+ while ((dp = readdir(dirp)) != NULL) {
+ /* Skip self and parent */
+ if (strcmp(dp->d_name, ".") == 0
+ || strcmp(dp->d_name, "..") == 0)
+ continue;
+ if (regexec(®ex, dp->d_name, 0, NULL, 0) != 0)
+ continue;
+ imgs = realloc(imgs, (n + 1) * sizeof(*imgs));
+ asprintf(&imgs[n], "%s/%s", path, dp->d_name);
+ n++;
+ }
+
+ qsort(imgs, n, sizeof(*imgs), imgcmp);
+
+ /* Terminate list or set default image if empty */
+ if (n > 0) {
+ imgs = realloc(imgs, (n + 1) * sizeof(*imgs));
+ imgs[n] = NULL;
+ cur = 0;
+ } else {
+ init_imgs_default();
+ }
+
+ closedir(dirp);
+}
+
+void
+free_imgs(void)
+{
+ unsigned int i;
+
+ for (i = 0; imgs[i] != NULL; i++)
+ free(imgs[i]);
+ free(imgs);
+ imgs = NULL;
+}
+
+void
+print_imgs(void)
+{
+ unsigned int i;
+ static char *oldimg = NULL;
+ static struct timespec tp, oldtp = { 0, 0 };
+ unsigned int delta;
+
+ clock_gettime(CLOCK_MONOTONIC, &tp);
+ delta = (tp.tv_sec * 1000 + tp.tv_nsec / 1000000)
+ - (oldtp.tv_sec * 1000 + oldtp.tv_nsec / 1000000);
+
+ DPRINTF("delta=%u\n", delta);
+
+ if (delta < cyclms && !change) {
+ pollms = cyclms - delta;
+ return;
+ }
+
+ if (change) {
+ cur = 0;
+ change = 0;
+ }
+
+ oldtp = tp;
+
+ for (i = 0; imgs[i] != NULL; i++)
+ DPRINTF("%s\n", imgs[i]);
+ DPRINTF("i=%u cur=%u\n", i, cur);
+
+ if (oldimg == NULL || strcmp(imgs[cur], oldimg) != 0) {
+ printf("%s\n", imgs[cur]);
+ fflush(stdout);
+ }
+ free(oldimg);
+ oldimg = strdup(imgs[cur]);
+
+ cur++;
+ if (cur == i)
+ cur = 0;
+}
+
+void
+update_imgs(struct mpd_connection *conn)
+{
+ struct mpd_status *status;
+ struct mpd_song *song;
+ const char *name;
+ enum mpd_state state;
+ static char *path, *oldpath = NULL;
+ char *abspath;
+
+ DPRINTF("update\n");
+
+ /* State */
+ mpd_send_status(conn);
+ status = mpd_recv_status(conn);
+ state = mpd_status_get_state(status);
+ /* Not playing */
+ if (state != MPD_STATE_PLAY &&
+ state != MPD_STATE_PAUSE) {
+ DPRINTF("state\n");
+ free_imgs();
+ init_imgs_default();
+ mpd_status_free(status);
+ free(oldpath);
+ oldpath = NULL;
+ change = 1;
+ return;
+ }
+ mpd_response_finish(conn);
+
+ /* Song */
+ mpd_send_current_song(conn);
+ song = mpd_recv_song(conn);
+ name = mpd_song_get_uri(song);
+ path = xdirname(name);
+ /* Album change */
+ if (oldpath == NULL || strcmp(path, oldpath) != 0) {
+ DPRINTF("song\n");
+ DPRINTF("path=%s oldpath=%s\n", path, oldpath);
+ asprintf(&abspath, "%s/%s", musicdir, path);
+ free_imgs();
+ init_imgs_from_path(abspath);
+ free(abspath);
+ change = 1;
+ }
+ free(oldpath);
+ oldpath = strdup(path);
+ mpd_song_free(song);
+ mpd_response_finish(conn);
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct mpd_connection *conn;
+ struct pollfd fds[1];
+
+ conn = mpd_connection_new(NULL, 0, 0);
+ if (mpd_connection_get_error(conn) != MPD_ERROR_SUCCESS)
+ err(1, "mpd_connection_new");
+
+ fds[0].fd = mpd_connection_get_fd(conn);
+ fds[0].events = POLLIN;
+
+ init_imgs_default();
+
+ for (;;) {
+ /* Update images if needed */
+ update_imgs(conn);
+
+ /* Print next image on change or timeout */
+ print_imgs();
+
+ /* Wait for a player change */
+ mpd_send_idle_mask(conn, MPD_IDLE_PLAYER);
+ poll(fds, 1, pollms);
+ mpd_send_noidle(conn);
+ mpd_response_finish(conn);
+
+ DPRINTF("poll\n");
+ }
+
+ mpd_connection_free(conn);
+
+ return 0;
+}
diff --git a/mpdutil/mpdlen.c b/mpdutil/mpdlen.c
@@ -0,0 +1,35 @@
+#include <stdio.h>
+
+#include <mpd/client.h>
+
+/* usage: mpdlen [list] */
+
+int
+main(int argc, char *argv[])
+{
+ struct mpd_connection *conn;
+ struct mpd_song *song;
+ unsigned secs = 0;
+ char *list = argv[1];
+
+ conn = mpd_connection_new(NULL, 0, 0);
+
+ if (mpd_connection_get_error(conn) != MPD_ERROR_SUCCESS)
+ err(1, "mpd_connection_new");
+
+ if (list != NULL)
+ mpd_send_list_playlist_meta(conn, list);
+ else
+ mpd_send_list_queue_meta(conn);
+
+ while ((song = mpd_recv_song(conn)) != NULL) {
+ secs += mpd_song_get_duration(song);
+ mpd_song_free(song);
+ }
+
+ mpd_connection_free(conn);
+
+ printf("%02u:%02u:%02u\n", secs / 3600, secs % 3600 / 60, secs % 60);
+
+ return 0;
+}