summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar waker <wakeroid@gmail.com>2009-08-26 23:23:08 +0200
committerGravatar waker <wakeroid@gmail.com>2009-08-26 23:23:08 +0200
commitad816d21ce318c87d9ef5e11124ad5b56afedd1d (patch)
treed47b264522f2ce6b5fcef9cf32c16557628ec156
parent91c33508d0da3cdb4c521df3cf8c7378dc707a8d (diff)
lastfm plugin WIP
-rw-r--r--deadbeef.h30
-rw-r--r--playlist.c2
-rw-r--r--playlist.h1
-rw-r--r--plugins.c37
-rw-r--r--plugins.h7
-rw-r--r--plugins/lastfm/lastfm.c284
-rw-r--r--streamer.c6
7 files changed, 300 insertions, 67 deletions
diff --git a/deadbeef.h b/deadbeef.h
index 416c890d..6106bfec 100644
--- a/deadbeef.h
+++ b/deadbeef.h
@@ -56,6 +56,7 @@ typedef struct {
int startoffset; // offset to seek to skip tags and info-headers
int endoffset; // offset from end of file where music data ends
int shufflerating; // sort order for shuffle mode
+ float playtime; // total playtime
const char *filetype; // e.g. MP3 or OGG
} DB_playItem_t;
@@ -67,19 +68,33 @@ enum {
DB_PLUGIN_MISC = 4
};
+typedef struct {
+ int event;
+ double time;
+} DB_event_t;
+
+typedef struct {
+ DB_event_t ev;
+ DB_playItem_t *song;
+} DB_event_song_t;
+
// event callback type
-typedef int (*db_callback_t)(int ev, uintptr_t data);
-#define DB_CALLBACK(x) ((db_callback_t)(x))
+typedef int (*DB_callback_t)(DB_event_t *, uintptr_t data);
// events
enum {
DB_EV_FRAMEUPDATE = 0, // ticks around 20 times per second, but ticker may stop sometimes
DB_EV_SONGCHANGED = 1, // triggers when song was just changed
+ DB_EV_SONGSTARTED = 2, // triggers when song started playing (for scrobblers and such)
+ DB_EV_SONGFINISHED = 3, // triggers when song finished playing (for scrobblers and such)
DB_EV_MAX
};
// typecasting macros
#define DB_PLUGIN(x) ((DB_plugin_t *)(x))
+#define DB_CALLBACK(x) ((DB_callback_t)(x))
+#define DB_EVENT(x) ((DB_event_t *)(x))
+#define DB_PLAYITEM(x) ((DB_playItem_t *)(x))
// forward decl for plugin struct
struct DB_plugin_s;
@@ -90,8 +105,8 @@ typedef struct {
int vmajor;
int vminor;
// event subscribing
- void (*ev_subscribe) (struct DB_plugin_s *plugin, int ev, db_callback_t callback, uintptr_t data);
- void (*ev_unsubscribe) (struct DB_plugin_s *plugin, int ev, db_callback_t callback, uintptr_t data);
+ void (*ev_subscribe) (struct DB_plugin_s *plugin, int ev, DB_callback_t callback, uintptr_t data);
+ void (*ev_unsubscribe) (struct DB_plugin_s *plugin, int ev, DB_callback_t callback, uintptr_t data);
// md5sum calc
void (*md5) (uint8_t sig[16], const char *in, int len);
void (*md5_to_str) (char *str, const uint8_t sig[16]);
@@ -108,12 +123,19 @@ typedef struct {
void (*mutex_free) (uintptr_t mtx);
int (*mutex_lock) (uintptr_t mtx);
int (*mutex_unlock) (uintptr_t mtx);
+ // playlist access
+ const char *(*pl_find_meta) (DB_playItem_t *song, const char *meta);
+ // web browser
+ int (*show_uri) (const char *uri);
} DB_functions_t;
// base plugin interface
typedef struct DB_plugin_s {
// type must be one of DB_PLUGIN_ types
int32_t type;
+ // version
+ int16_t version_major;
+ int16_t version_minor;
// may be deactivated on failures after load
int inactive;
// any of those can be left NULL
diff --git a/playlist.c b/playlist.c
index c033583a..4957f64d 100644
--- a/playlist.c
+++ b/playlist.c
@@ -31,6 +31,7 @@
#include "messagepump.h"
#include "messages.h"
#include "playback.h"
+#include "plugins.h"
#include "cvorbis.h"
#include "cdumb.h"
@@ -620,6 +621,7 @@ pl_set_current (playItem_t *it) {
}
codec_unlock ();
it->played = 1;
+ plug_trigger_event (DB_EV_SONGSTARTED);
messagepump_push (M_SONGCHANGED, 0, from, to);
return ret;
}
diff --git a/playlist.h b/playlist.h
index d8fe1d6e..7e2df4c2 100644
--- a/playlist.h
+++ b/playlist.h
@@ -38,6 +38,7 @@ typedef struct playItem_s {
int startoffset; // offset to seek to skip tags and info-headers (mp3)
int endoffset; // offset from end of file where music data ends (mp3)
int shufflerating; // sort order for shuffle mode
+ float playtime; // total playtime
const char *filetype; // e.g. MP3 or OGG
struct playItem_s *next[PL_MAX_ITERATORS]; // next item in linked list
struct playItem_s *prev[PL_MAX_ITERATORS]; // prev item in linked list
diff --git a/plugins.c b/plugins.c
index 15ed6424..e0d7f68b 100644
--- a/plugins.c
+++ b/plugins.c
@@ -4,6 +4,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <gtk/gtk.h>
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
@@ -13,6 +14,7 @@
#include "messages.h"
#include "threading.h"
#include "progress.h"
+#include "playlist.h"
// deadbeef api
DB_functions_t deadbeef_api = {
@@ -34,6 +36,8 @@ DB_functions_t deadbeef_api = {
.mutex_free = mutex_free,
.mutex_lock = mutex_lock,
.mutex_unlock = mutex_unlock,
+ .pl_find_meta = (const char *(*) (DB_playItem_t *song, const char *meta))pl_find_meta,
+ .show_uri = plug_show_uri,
};
void
@@ -49,7 +53,7 @@ plug_md5_to_str (char *str, const uint8_t sig[16]) {
// event handlers
typedef struct {
DB_plugin_t *plugin;
- db_callback_t callback;
+ DB_callback_t callback;
uintptr_t data;
} evhandler_t;
#define MAX_HANDLERS 100
@@ -64,7 +68,7 @@ typedef struct plugin_s {
plugin_t *plugins;
void
-plug_ev_subscribe (DB_plugin_t *plugin, int ev, db_callback_t callback, uintptr_t data) {
+plug_ev_subscribe (DB_plugin_t *plugin, int ev, DB_callback_t callback, uintptr_t data) {
assert (ev < DB_EV_MAX && ev >= 0);
for (int i = 0; i < MAX_HANDLERS; i++) {
if (!handlers[ev][i].plugin) {
@@ -78,7 +82,7 @@ plug_ev_subscribe (DB_plugin_t *plugin, int ev, db_callback_t callback, uintptr_
}
void
-plug_ev_unsubscribe (DB_plugin_t *plugin, int ev, db_callback_t callback, uintptr_t data) {
+plug_ev_unsubscribe (DB_plugin_t *plugin, int ev, DB_callback_t callback, uintptr_t data) {
assert (ev < DB_EV_MAX && ev >= 0);
for (int i = 0; i < MAX_HANDLERS; i++) {
if (handlers[ev][i].plugin == plugin) {
@@ -121,14 +125,39 @@ plug_quit (void) {
messagepump_push (M_TERMINATE, 0, 0, 0);
}
+int
+plug_show_uri (const char *uri) {
+ GError *error = NULL;
+ GDK_THREADS_ENTER();
+ gboolean ret = gtk_show_uri (NULL, uri, GDK_CURRENT_TIME, &error);
+ GDK_THREADS_LEAVE();
+ return ret;
+}
+
/////// non-api functions (plugin support)
void
plug_trigger_event (int ev) {
+ DB_event_t *event;
+ switch (ev) {
+ case DB_EV_SONGSTARTED:
+ case DB_EV_SONGFINISHED:
+ {
+ DB_event_song_t *pev = malloc (sizeof (DB_event_song_t));
+ pev->song = DB_PLAYITEM (&playlist_current);
+ event = DB_EVENT (pev);
+ }
+ break;
+ default:
+ event = malloc (sizeof (DB_event_t));
+ }
+ event->event = ev;
+ event->time = (double)clock () / CLOCKS_PER_SEC;
for (int i = 0; i < MAX_HANDLERS; i++) {
if (handlers[ev][i].plugin && !handlers[ev][i].plugin->inactive) {
- handlers[ev][i].callback (ev, handlers[ev][i].data);
+ handlers[ev][i].callback (event, handlers[ev][i].data);
}
}
+ free (event);
}
void
diff --git a/plugins.h b/plugins.h
index ef228b51..0525d9e4 100644
--- a/plugins.h
+++ b/plugins.h
@@ -3,10 +3,10 @@
#include "deadbeef.h"
void
-plug_ev_subscribe (DB_plugin_t *plugin, int ev, db_callback_t callback, uintptr_t data);
+plug_ev_subscribe (DB_plugin_t *plugin, int ev, DB_callback_t callback, uintptr_t data);
void
-plug_ev_unsubscribe (DB_plugin_t *plugin, int ev, db_callback_t callback, uintptr_t data);
+plug_ev_unsubscribe (DB_plugin_t *plugin, int ev, DB_callback_t callback, uintptr_t data);
void
plug_trigger_event (int ev);
@@ -41,4 +41,7 @@ plug_playback_play (void);
void
plug_quit (void);
+int
+plug_show_uri (const char *uri);
+
#endif // __PLUGINS_H
diff --git a/plugins/lastfm/lastfm.c b/plugins/lastfm/lastfm.c
index 4b6bc21e..afee5471 100644
--- a/plugins/lastfm/lastfm.c
+++ b/plugins/lastfm/lastfm.c
@@ -25,127 +25,293 @@
static DB_misc_t plugin;
static DB_functions_t *deadbeef;
-static char lastfm_login[50];
-static char lastfm_pass[50];
-#define SCROBBLER_URL "http://ws.audioscrobbler.com/2.0"
+#define SCROBBLER_URL_V1 "http://post.audioscrobbler.com"
+#define SCROBBLER_URL_V2 "http://ws.audioscrobbler.com/2.0"
#define LASTFM_API_KEY "6b33c8ae4d598a9aff8fe63e334e6e86"
#define LASTFM_API_SECRET "a9f5e17e358377d96e96477d870b2b18"
+char lfm_sess[33];
+char lfm_user[100];
+char lfm_pass[100];
+
DB_plugin_t *
lastfm_load (DB_functions_t *api) {
deadbeef = api;
return DB_PLUGIN (&plugin);
}
-static char *lastfm_srv_res;
-static char lastfm_srv_size;
-static char lastfm_curl_err[CURL_ERROR_SIZE];
+static char *lfm_reply;
+static char lfm_reply_sz;
+static char lfm_err[CURL_ERROR_SIZE];
static size_t
lastfm_curl_res (void *ptr, size_t size, size_t nmemb, void *stream)
{
int len = size * nmemb;
- lastfm_srv_res = realloc (lastfm_srv_res, lastfm_srv_size + len + 1);
- memcpy (lastfm_srv_res + lastfm_srv_size, ptr, len);
- lastfm_srv_size += len;
+ lfm_reply = realloc (lfm_reply, lfm_reply_sz + len + 1);
+ memcpy (lfm_reply + lfm_reply_sz, ptr, len);
+ lfm_reply_sz += len;
char s[size*nmemb+1];
memcpy (s, ptr, size*nmemb);
s[size*nmemb] = 0;
- printf ("%s\n", s);
return len;
}
-int
-lastfm_auth (void) {
- // auth
- char msg[4096];
- char sigstr[4096];
- uint8_t sig[16];
- snprintf (sigstr, sizeof (sigstr), "api_key%smethodauth.getToken%s", SCROBBLER_URL, LASTFM_API_KEY, LASTFM_API_SECRET);
- deadbeef->md5 (sig, sigstr, strlen (sigstr));
- deadbeef->md5_to_str (sigstr, sig);
- snprintf (msg, sizeof (msg), "%s/?method=auth.getToken&api_key=%s&api_sig=%s", SCROBBLER_URL, LASTFM_API_KEY, sigstr);
- printf ("sending request: %s\n", msg);
- // init curl
+static int
+curl_req_send (const char *req, const char *post) {
+ printf ("sending request: %s\n", req);
CURL *curl;
curl = curl_easy_init ();
if (!curl) {
fprintf (stderr, "lastfm: failed to init curl\n");
- return 0;
+ return -1;
}
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
- curl_easy_setopt(curl, CURLOPT_URL, msg);
+ curl_easy_setopt(curl, CURLOPT_URL, req);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, lastfm_curl_res);
- memset(lastfm_curl_err, 0, sizeof(lastfm_curl_err));
- curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, lastfm_curl_err);
- curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ memset(lfm_err, 0, sizeof(lfm_err));
+ curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, lfm_err);
+ curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ if (post) {
+ curl_easy_setopt(curl, CURLOPT_POST, 1);
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post);
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(post));
+ }
int status = curl_easy_perform(curl);
curl_easy_cleanup (curl);
+ if (!status) {
+ lfm_reply[lfm_reply_sz] = 0;
+ }
+ return status;
+}
+
+static void
+curl_req_cleanup (void) {
+ if (lfm_reply) {
+ free (lfm_reply);
+ lfm_reply = NULL;
+ lfm_reply_sz = 0;
+ }
+}
+
+// {{{ lastfm v2 get session
+#if 0
+int
+auth_v2 (void) {
+ if (lfm_sess[0]) {
+ return 0;
+ }
+ char msg[4096];
+ char sigstr[4096];
+ uint8_t sig[16];
+ snprintf (sigstr, sizeof (sigstr), "api_key%smethodauth.getToken%s", LASTFM_API_KEY, LASTFM_API_SECRET);
+ deadbeef->md5 (sig, sigstr, strlen (sigstr));
+ deadbeef->md5_to_str (sigstr, sig);
+ snprintf (msg, sizeof (msg), "%s/?api_key=%s&method=auth.getToken&api_sig=%s", SCROBBLER_URL, LASTFM_API_KEY, sigstr);
+ // get token
+ char lfm_token[33] = "";
+ int status = curl_req_send (msg, NULL);
if (!status) {
// parse output
- if (strstr (lastfm_srv_res, "<lfm status=\"ok\">")) {
- char *token = strstr (lastfm_srv_res, "<token>");
+ if (strstr (lfm_reply, "<lfm status=\"ok\">")) {
+ char *token = strstr (lfm_reply, "<token>");
if (token) {
token += 7;
char *end = strstr (token, "</token>");
if (end) {
*end = 0;
- printf ("token: %s\n", token);
- }
- else {
- printf ("no </token>\n");
+ snprintf (msg, sizeof (msg), "http://www.last.fm/api/auth/?api_key=%s&token=%s", LASTFM_API_KEY, token);
+ printf ("Dear user. Please visit this URL and authenticate deadbeef. Thanks.\n");
+
+ printf ("%s\n", msg);
+ strncpy (lfm_token, token, 32);
+ lfm_token[32] = 0;
}
}
- else {
- printf ("no <token>\n");
+ }
+ }
+ curl_req_cleanup ();
+ if (!lfm_token[0]) {
+ // total fail, give up
+ return -1;
+ }
+ // get session
+ snprintf (sigstr, sizeof (sigstr), "api_key%smethodauth.getSessiontoken%s%s", LASTFM_API_KEY, lfm_token, LASTFM_API_SECRET);
+ deadbeef->md5 (sig, sigstr, strlen (sigstr));
+ deadbeef->md5_to_str (sigstr, sig);
+ snprintf (msg, sizeof (msg), "method=auth.getSession&token=%s&api_key=%s&api_sig=%s", lfm_token, LASTFM_API_KEY, sigstr);
+ for (;;) {
+ status = curl_req_send (SCROBBLER_URL, msg);
+ if (!status) {
+ char *sess = strstr (lfm_reply, "<key>");
+ if (sess) {
+ sess += 5;
+ char *end = strstr (sess, "</key>");
+ if (end) {
+ *end = 0;
+ char config[1024];
+ snprintf (config, sizeof (config), "%s/.config/deadbeef/lastfmv2", getenv ("HOME"));
+ fprintf (stderr, "got session key %s\n", sess);
+ FILE *fp = fopen (config, "w+b");
+ if (!fp) {
+ fprintf (stderr, "lastfm: failed to write config file %s\n", config);
+ curl_req_cleanup ();
+ return -1;
+ }
+ if (fwrite (sess, 1, 32, fp) != 32) {
+ fclose (fp);
+ fprintf (stderr, "lastfm: failed to write config file %s\n", config);
+ curl_req_cleanup ();
+ return -1;
+ }
+ fclose (fp);
+ strcpy (lfm_sess, sess);
+ }
}
+// printf ("reply: %s\n", lfm_reply);
}
- else {
- printf ("not ok\n");
+ curl_req_cleanup ();
+ if (lfm_sess[0]) {
+ break;
}
+ sleep (5);
}
+ return 0;
+}
+#endif
+// }}}
+
- if (lastfm_srv_res) {
- free (lastfm_srv_res);
- lastfm_srv_res = NULL;
+int
+auth (void) {
+ char req[4096];
+ time_t timestamp = time(0);
+ uint8_t sig[16];
+ char passmd5[33];
+ char token[100];
+ printf (">> %s:%s <<\n", lfm_user, lfm_pass);
+ deadbeef->md5 (sig, lfm_pass, strlen (lfm_pass));
+ deadbeef->md5_to_str (passmd5, sig);
+ snprintf (token, sizeof (token), "%s%d", passmd5, timestamp);
+ deadbeef->md5 (sig, token, strlen (token));
+ deadbeef->md5_to_str (token, sig);
+
+ snprintf (req, sizeof (req), "%s/?hs=true&p=1.2.1&c=tst&v=1.0&u=%s&t=%d&a=%s", SCROBBLER_URL_V1, lfm_user, timestamp, token);
+ // handshake
+ int status = curl_req_send (req, NULL);
+ if (!status) {
+ printf ("%s\n", lfm_reply);
}
+ curl_req_cleanup ();
+ return 0;
}
static int
-lastfm_frameupdate (int ev, uintptr_t data) {
-// printf ("lastfm tick\n");
+lfm_fetch_song_info (DB_playItem_t *song, const char **a, const char **t, const char **b, float *l, const char **n, const char **m) {
+ *a = deadbeef->pl_find_meta (song, "artist");
+ if (!strcmp (*a, "?")) {
+ return -1;
+ }
+ *t = deadbeef->pl_find_meta (song, "title");
+ if (!strcmp (*t, "?")) {
+ return -1;
+ }
+ *b = deadbeef->pl_find_meta (song, "album");
+ if (!strcmp (*b, "?")) {
+ return -1;
+ }
+ *l = song->duration;
+ *n = deadbeef->pl_find_meta (song, "track");
+ if (!strcmp (*n, "?")) {
+ *n = "";
+ }
+ *m = deadbeef->pl_find_meta (song, "mbid");
+ if (!strcmp (*m, "?")) {
+ *m = "";
+ }
return 0;
}
static int
-lastfm_songchanged (int ev, uintptr_t data) {
- printf ("song changed\n");
+lastfm_songstarted (DB_event_song_t *ev, uintptr_t data) {
+ printf ("song started, info:\n");
+ const char *a; // artist
+ const char *t; // title
+ const char *b; // album
+ float l; // duration
+ const char *n; // tracknum
+ const char *m; // muzicbrainz id
+ if (lfm_fetch_song_info (ev->song, &a, &t, &b, &l, &n, &m) == 0) {
+ printf ("playtime: %f\nartist: %s\ntitle: %s\nalbum: %s\nduration: %f\ntracknum: %s\n---\n", ev->song->playtime, a, t, b, l, n);
+ }
+ else {
+ printf ("file %f doesn't have enough tags to submit to last.fm\n", ev->song->fname);
+ }
+
return 0;
}
static int
+lastfm_songfinished (DB_event_song_t *ev, uintptr_t data) {
+ printf ("song finished, info:\n");
+ const char *a; // artist
+ const char *t; // title
+ const char *b; // album
+ float l; // duration
+ const char *n; // tracknum
+ const char *m; // muzicbrainz id
+ if (lfm_fetch_song_info (ev->song, &a, &t, &b, &l, &n, &m) == 0) {
+ printf ("playtime: %f\nartist: %s\ntitle: %s\nalbum: %s\nduration: %f\ntracknum: %s\n---\n", ev->song->playtime, a, t, b, l, n);
+ }
+ else {
+ printf ("file %f doesn't have enough tags to submit to last.fm\n", ev->song->fname);
+ }
+
+ return 0;
+}
+static int
lastfm_start (void) {
// subscribe to frameupdate event
- deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_FRAMEUPDATE, lastfm_frameupdate, 0);
- deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_SONGCHANGED, lastfm_songchanged, 0);
+// deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_FRAMEUPDATE, lastfm_frameupdate, 0);
+// deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_SONGCHANGED, lastfm_songchanged, 0);
+ deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_SONGSTARTED, DB_CALLBACK (lastfm_songstarted), 0);
+ deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_SONGFINISHED, DB_CALLBACK (lastfm_songfinished), 0);
// load login/pass
char config[1024];
+
+// {{{ lastfm v2 auth
+#if 0
+ snprintf (config, 1024, "%s/.config/deadbeef/lastfmv2", getenv ("HOME"));
+ FILE *fp = fopen (config, "rt");
+ if (fp) {
+ if (fread (lfm_sess, 1, 32, fp) != 32) {
+ lfm_sess[0] = 0;
+ }
+ else {
+ lfm_sess[32] = 0;
+ }
+ fclose (fp);
+ }
+ auth_v2 ();
+#endif
+// }}}
+
snprintf (config, 1024, "%s/.config/deadbeef/lastfm", getenv ("HOME"));
FILE *fp = fopen (config, "rt");
if (!fp) {
fprintf (stderr, "lastfm: failed open %s\n", config);
return -1;
}
- if (!fgets (lastfm_login, 50, fp)) {
+ if (!fgets (lfm_user, 50, fp)) {
fprintf (stderr, "lastfm: failed to read login from %s\n", config);
fclose (fp);
return -1;
}
- if (!fgets (lastfm_pass, 50, fp)) {
+ if (!fgets (lfm_pass, 50, fp)) {
fprintf (stderr, "lastfm: failed to read pass from %s\n", config);
fclose (fp);
return -1;
@@ -154,32 +320,36 @@ lastfm_start (void) {
// remove trailing garbage
int l;
char *p;
- l = strlen (lastfm_login);
- p = lastfm_login+l-1;
- while (p >= lastfm_login && *p < 0x20) {
+ l = strlen (lfm_user);
+ p = lfm_user+l-1;
+ while (p >= lfm_user && *p < 0x20) {
p--;
}
+ p++;
*p = 0;
- l = strlen (lastfm_pass);
- p = lastfm_pass+l-1;
- while (p >= lastfm_login && *p < 0x20) {
+ l = strlen (lfm_pass);
+ p = lfm_pass+l-1;
+ while (p >= lfm_pass && *p < 0x20) {
p--;
}
+ p++;
*p = 0;
- lastfm_auth ();
+ auth ();
return 0;
}
static int
lastfm_stop (void) {
- deadbeef->ev_unsubscribe (DB_PLUGIN (&plugin), DB_EV_FRAMEUPDATE, lastfm_frameupdate, 0);
- deadbeef->ev_unsubscribe (DB_PLUGIN (&plugin), DB_EV_SONGCHANGED, lastfm_songchanged, 0);
+ deadbeef->ev_unsubscribe (DB_PLUGIN (&plugin), DB_EV_SONGSTARTED, DB_CALLBACK (lastfm_songstarted), 0);
+ deadbeef->ev_unsubscribe (DB_PLUGIN (&plugin), DB_EV_SONGFINISHED, DB_CALLBACK (lastfm_songfinished), 0);
return 0;
}
// define plugin interface
static DB_misc_t plugin = {
+ .plugin.version_major = 0,
+ .plugin.version_minor = 1,
.plugin.type = DB_PLUGIN_MISC,
.plugin.name = "last.fm scrobbler",
.plugin.descr = "sends played songs information to your last.fm account",
diff --git a/streamer.c b/streamer.c
index 06dd0e7f..56d86699 100644
--- a/streamer.c
+++ b/streamer.c
@@ -31,6 +31,7 @@
#include "messagepump.h"
#include "messages.h"
#include "conf.h"
+#include "plugins.h"
static SRC_STATE *src;
static SRC_DATA srcdata;
@@ -95,6 +96,7 @@ streamer_thread (uintptr_t ctx) {
badsong = -1;
continue;
}
+ plug_trigger_event (DB_EV_SONGFINISHED);
int ret = pl_set_current (pl_get_for_idx (sng));
if (ret < 0) {
//printf ("bad file in playlist, skipping...\n");
@@ -339,6 +341,10 @@ streamer_read (char *bytes, int size) {
}
streambuffer_fill -= sz;
playpos += (float)sz/p_get_rate ()/4.f;
+ playlist_current.playtime += (float)sz/p_get_rate ()/4.f;
+ if (playlist_current_ptr) {
+ playlist_current_ptr->playtime = playlist_current.playtime;
+ }
bytes_until_next_song -= sz;
if (bytes_until_next_song < 0) {
bytes_until_next_song = 0;