summaryrefslogtreecommitdiff
path: root/plugins/lastfm
diff options
context:
space:
mode:
authorGravatar waker <wakeroid@gmail.com>2009-08-29 18:53:30 +0200
committerGravatar waker <wakeroid@gmail.com>2009-08-29 19:56:49 +0200
commit003a54afeba00597fd2f50e38ccd35c7cd5e4e39 (patch)
tree53e0b9b839dbf4de9daa9dd354d423aa01b81052 /plugins/lastfm
parent335bec105eea648030f55282479fe509cc1bfa9d (diff)
lastfm plugin uri-encoding, batch-sending and other improvements
Diffstat (limited to 'plugins/lastfm')
-rw-r--r--plugins/lastfm/lastfm.c272
1 files changed, 207 insertions, 65 deletions
diff --git a/plugins/lastfm/lastfm.c b/plugins/lastfm/lastfm.c
index 6c8b2896..4a276916 100644
--- a/plugins/lastfm/lastfm.c
+++ b/plugins/lastfm/lastfm.c
@@ -23,15 +23,14 @@
#include <curl/curl.h>
#include "../../deadbeef.h"
-#define TESTMODE 1
+#define LFM_TESTMODE 0
#define LFM_IGNORE_RULES 0
+#define LFM_NOSEND 0
static DB_misc_t plugin;
static DB_functions_t *deadbeef;
#define LFM_CLIENTID "ddb"
-#define LFM_MAJORVER 0
-#define LFM_MINORVER 1
#define SCROBBLER_URL_V1 "http://post.audioscrobbler.com"
#define SCROBBLER_URL_V2 "http://ws.audioscrobbler.com/2.0"
#define LFM_API_KEY "6b33c8ae4d598a9aff8fe63e334e6e86"
@@ -60,9 +59,10 @@ static char lfm_reply[MAX_REPLY];
static char lfm_reply_sz;
static char lfm_err[CURL_ERROR_SIZE];
-#define LFM_SUBMISSION_QUEUE_SIZE 5
static char lfm_nowplaying[2048]; // packet for nowplaying, or ""
-static char lfm_subm_queue[LFM_SUBMISSION_QUEUE_SIZE][2048];
+#define LFM_SUBMISSION_QUEUE_SIZE 50
+//static char lfm_subm_queue[LFM_SUBMISSION_QUEUE_SIZE][2048];
+static DB_playItem_t *lfm_subm_queue[LFM_SUBMISSION_QUEUE_SIZE];
static size_t
lastfm_curl_res (void *ptr, size_t size, size_t nmemb, void *stream)
@@ -117,8 +117,13 @@ curl_req_cleanup (void) {
lfm_reply_sz = 0;
}
-int
+static int
auth (void) {
+ static int count = 5;
+ if (count > 0) {
+ count--;
+ return -1;
+ }
if (lfm_sess[0]) {
return 0;
}
@@ -133,10 +138,10 @@ auth (void) {
deadbeef->md5 (sig, token, strlen (token));
deadbeef->md5_to_str (token, sig);
-#if TESTMODE
+#if LFM_TESTMODE
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);
#else
- snprintf (req, sizeof (req), "%s/?hs=true&p=1.2.1&c=%s&v=%d.%d&u=%s&t=%d&a=%s", SCROBBLER_URL_V1, LFM_CLIENTID, LFM_MAJORVER, LFM_MINORVER, lfm_user, timestamp, token);
+ snprintf (req, sizeof (req), "%s/?hs=true&p=1.2.1&c=%s&v=%d.%d&u=%s&t=%d&a=%s", SCROBBLER_URL_V1, LFM_CLIENTID, plugin.plugin.version_major, plugin.plugin.version_minor, lfm_user, timestamp, token);
#endif
// handshake
int status = curl_req_send (req, NULL);
@@ -251,48 +256,168 @@ lfm_fetch_song_info (DB_playItem_t *song, const char **a, const char **t, const
return 0;
}
+// returns number of encoded chars on success, or -1 in case of error
static int
-lastfm_songstarted (DB_event_song_t *ev, uintptr_t data) {
- fprintf (stderr, "song started, info:\n");
+lfm_uri_encode (char *out, int outl, const char *str) {
+ int l = outl;
+ static const char echars[] = " ;/?:@=#&";
+ //fprintf (stderr, "lfm_uri_encode %p %d %s\n", out, outl, str);
+ while (*str) {
+ if (outl <= 1) {
+ //fprintf (stderr, "no space left for 1 byte in buffer\n");
+ return -1;
+ }
+ if (strchr (echars, *str)) {
+ if (outl <= 3) {
+ //fprintf (stderr, "no space left for 3 bytes in the buffer\n");
+ return -1;
+ }
+ //fprintf (stderr, "adding escaped value for %c\n", *str);
+ snprintf (out, outl, "%%%02x", (int)*str);
+ outl -= 3;
+ str++;
+ out += 3;
+ }
+ else {
+ *out = *str;
+ out++;
+ str++;
+ outl--;
+ }
+ }
+ *out = 0;
+ return l - outl;
+}
+
+// returns number of encoded chars on success
+// or -1 on error
+static int
+lfm_add_keyvalue_uri_encoded (char **out, int *outl, const char *key, const char *value) {
+ int ll = *outl;
+ int keyl = strlen (key);
+ if (*outl <= keyl+1) {
+ return -1;
+ }
+ // append key and '=' sign
+ memcpy (*out, key, keyl);
+ (*out)[keyl] = '=';
+ *out += keyl+1;
+ *outl -= keyl+1;
+ // encode and append value
+ int l = lfm_uri_encode (*out, *outl, value);
+ if (l < 0) {
+ return -1;
+ }
+ *out += l;
+ *outl -= l;
+ // append '&'
+ if (*outl <= 1) {
+ return -1;
+ }
+ strcpy (*out, "&");
+ *out += 1;
+ *outl -= 1;
+ return ll - *outl;
+}
+
+// subm is submission idx, or -1 for nowplaying
+// returns number of bytes added, or -1
+static int
+lfm_format_uri (int subm, DB_playItem_t *song, char *out, int outl) {
+ if (subm > 50) {
+ fprintf (stderr, "lastfm: it's only allowed to send up to 50 submissions at once (got idx=%d)\n", subm);
+ return -1;
+ }
+ int sz = outl;
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) {
- fprintf (stderr, "playtime: %f\nartist: %s\ntitle: %s\nalbum: %s\nduration: %f\ntracknum: %s\n---\n", ev->song->playtime, a, t, b, l, n);
+
+ char ka[6] = "a";
+ char kt[6] = "t";
+ char kb[6] = "b";
+ char kl[6] = "l";
+ char kn[6] = "n";
+ char km[6] = "m";
+
+ if (subm >= 0) {
+ snprintf (ka+1, 5, "[%d]", subm);
+ strcpy (kt+1, ka+1);
+ strcpy (kb+1, ka+1);
+ strcpy (kl+1, ka+1);
+ strcpy (kn+1, ka+1);
+ strcpy (km+1, ka+1);
+ }
+
+ if (lfm_fetch_song_info (song, &a, &t, &b, &l, &n, &m) == 0) {
+ fprintf (stderr, "playtime: %f\nartist: %s\ntitle: %s\nalbum: %s\nduration: %f\ntracknum: %s\n---\n", song->playtime, a, t, b, l, n);
}
else {
- fprintf (stderr, "file %s doesn't have enough tags to submit to last.fm\n", ev->song->fname);
- return 0;
+ fprintf (stderr, "file %s doesn't have enough tags to submit to last.fm\n", song->fname);
+ return -1;
+ }
+
+ if (lfm_add_keyvalue_uri_encoded (&out, &outl, ka, a) < 0) {
+// fprintf (stderr, "failed to add %s=%s\n", ka, a);
+ return -1;
+ }
+ if (lfm_add_keyvalue_uri_encoded (&out, &outl, kt, t) < 0) {
+// fprintf (stderr, "failed to add %s=%s\n", kt, t);
+ return -1;
+ }
+ if (lfm_add_keyvalue_uri_encoded (&out, &outl, kb, b) < 0) {
+// fprintf (stderr, "failed to add %s=%s\n", kb, b);
+ return -1;
+ }
+ if (lfm_add_keyvalue_uri_encoded (&out, &outl, kn, n) < 0) {
+// fprintf (stderr, "failed to add %s=%s\n", kn, n);
+ return -1;
+ }
+ if (lfm_add_keyvalue_uri_encoded (&out, &outl, km, m) < 0) {
+// fprintf (stderr, "failed to add %s=%s\n", km, m);
+ return -1;
+ }
+ int processed;
+ processed = snprintf (out, outl, "%s=%d&", kl, (int)l);
+ if (processed > outl) {
+// fprintf (stderr, "failed to add %s=%d\n", kl, (int)l);
+ return -1;
+ }
+ out += processed;
+ outl -= processed;
+ if (subm >= 0) {
+ processed = snprintf (out, outl, "i[%d]=%d&o[%d]=P&r[%d]=&", subm, (int)song->started_timestamp, subm, subm);
+ if (processed > outl) {
+// fprintf (stderr, "failed to add i[%d]=%d&o[%d]=P&r[%d]=&\n", subm, (int)song->started_timestamp, subm, subm);
+ return -1;
+ }
+ out += processed;
+ outl -= processed;
}
+ return sz - outl;
+}
+
+static int
+lastfm_songstarted (DB_event_song_t *ev, uintptr_t data) {
deadbeef->mutex_lock (lfm_mutex);
- snprintf (lfm_nowplaying, sizeof (lfm_nowplaying), "a=%s&t=%s&b=%s&l=%d&n=%s&m=%s", a, t, b, (int)l, n, m);
+ if (lfm_format_uri (-1, ev->song, lfm_nowplaying_url, sizeof (lfm_nowplaying_url)) < 0) {
+ lfm_nowplaying_url[0] = 0;
+ }
+ fprintf (stderr, "%s\n", lfm_nowplaying_url);
deadbeef->mutex_unlock (lfm_mutex);
- deadbeef->cond_signal (lfm_cond);
+ if (lfm_nowplaying_url[0]) {
+ deadbeef->cond_signal (lfm_cond);
+ }
return 0;
}
static int
lastfm_songfinished (DB_event_song_t *ev, uintptr_t data) {
- fprintf (stderr, "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) {
- fprintf (stderr, "playtime: %f\nartist: %s\ntitle: %s\nalbum: %s\nduration: %f\ntracknum: %s\n---\n", ev->song->playtime, a, t, b, l, n);
- }
- else {
- fprintf (stderr, "file %s doesn't have enough tags to submit to last.fm\n", ev->song->fname);
- return 0;
- }
-
#if !LFM_IGNORE_RULES
// check submission rules
// must be played for >=240sec of half the total time
@@ -309,8 +434,9 @@ lastfm_songfinished (DB_event_song_t *ev, uintptr_t data) {
deadbeef->mutex_lock (lfm_mutex);
// find free place in queue
for (int i = 0; i < LFM_SUBMISSION_QUEUE_SIZE; i++) {
- if (!lfm_subm_queue[i][0]) {
- snprintf (lfm_subm_queue[i], sizeof (lfm_subm_queue[i]), "a[0]=%s&t[0]=%s&i[0]=%d&o[0]=P&r[0]=&b[0]=%s&l[0]=%d&n[0]=%s&m[0]=%s", a, t, ev->song->started_timestamp, b, (int)l, n, m);
+ if (!lfm_subm_queue[i]) {
+ lfm_subm_queue[i] = deadbeef->pl_item_alloc ();
+ deadbeef->pl_item_copy (lfm_subm_queue[i], ev->song);
break;
}
}
@@ -328,8 +454,9 @@ lfm_send_nowplaying (void) {
}
fprintf (stderr, "auth successful! setting nowplaying\n");
char s[100];
- snprintf (s, sizeof (s), "&s=%s", lfm_sess);
+ snprintf (s, sizeof (s), "s=%s&", lfm_sess);
strcat (lfm_nowplaying, s);
+#if !LFM_NOSEND
int status = curl_req_send (lfm_nowplaying_url, lfm_nowplaying);
if (!status) {
if (strncmp (lfm_reply, "OK", 2)) {
@@ -338,50 +465,65 @@ lfm_send_nowplaying (void) {
}
}
curl_req_cleanup ();
+#endif
lfm_nowplaying[0] = 0;
}
static void
lfm_send_submissions (void) {
- for (;;) {
- int i;
-// deadbeef->mutex_lock (lfm_mutex);
- for (i = 0; i < LFM_SUBMISSION_QUEUE_SIZE; i++) {
- if (lfm_subm_queue[i][0]) {
- break;
+ int i;
+ char req[1024*50];
+ int idx = 0;
+ char *r = req;
+ int len = sizeof (req);
+ int res;
+ deadbeef->mutex_lock (lfm_mutex);
+ for (i = 0; i < LFM_SUBMISSION_QUEUE_SIZE; i++) {
+ if (lfm_subm_queue[i]) {
+ res = lfm_format_uri (idx, lfm_subm_queue[i], r, len);
+ if (res < 0) {
+ return;
}
+ len -= res;
+ r += res;
+ idx++;
}
-// deadbeef->mutex_unlock (lfm_mutex);
- if (i == LFM_SUBMISSION_QUEUE_SIZE) {
- break;
- }
- if (auth () < 0) {
- break;
+ }
+ deadbeef->mutex_unlock (lfm_mutex);
+ if (!idx) {
+ return;
+ }
+ if (auth () < 0) {
+ return;
+ }
+ res = snprintf (r, len, "s=%s&", lfm_sess);
+ if (res > len) {
+ return;
+ }
+ fprintf (stderr, "submission req string:\n%s\n", req);
+#if !LFM_NOSEND
+ int status = curl_req_send (lfm_submission_url, req);
+ if (!status) {
+ if (strncmp (lfm_reply, "OK", 2)) {
+ fprintf (stderr, "submission failed, response:\n%s\n", lfm_reply);
}
- char s[100];
- snprintf (s, sizeof (s), "&s=%s", lfm_sess);
- strcat (lfm_subm_queue[i], s);
- int status = curl_req_send (lfm_submission_url, lfm_subm_queue[i]);
- if (!status) {
- if (strncmp (lfm_reply, "OK", 2)) {
- fprintf (stderr, "submission failed, response:\n%s\n", lfm_reply);
- lfm_sess[0] = 0;
- }
- else {
- fprintf (stderr, "submission successful, response:\n%s\n", lfm_reply);
-// deadbeef->mutex_lock (lfm_mutex);
- lfm_subm_queue[i][0] = 0;
-// deadbeef->mutex_unlock (lfm_mutex);
+ else {
+ fprintf (stderr, "submission successful, response:\n%s\n", lfm_reply);
+ deadbeef->mutex_lock (lfm_mutex);
+ for (i = 0; i < LFM_SUBMISSION_QUEUE_SIZE; i++) {
+ if (lfm_subm_queue[i]) {
+ deadbeef->pl_item_free (lfm_subm_queue[i]);
+ lfm_subm_queue[i] = NULL;
+ }
}
- }
- curl_req_cleanup ();
- if (!lfm_sess[0]) {
- break;
+ deadbeef->mutex_unlock (lfm_mutex);
}
}
+ curl_req_cleanup ();
+#endif
}
-void
+static void
lfm_thread (uintptr_t ctx) {
//fprintf (stderr, "lfm_thread started\n");
for (;;) {