[rhythmbox] last.fm: update to protocol version 1.2
- From: Jonathan Matthew <jmatthew src gnome org>
- To: svn-commits-list gnome org
- Subject: [rhythmbox] last.fm: update to protocol version 1.2
- Date: Mon, 4 May 2009 23:41:41 -0400 (EDT)
commit da125fadfc4e0ff2852914a1167ddcdf70c0a405
Author: Matt Novenstern <fisxoj gmail com>
Date: Tue May 5 13:26:11 2009 +1000
last.fm: update to protocol version 1.2
v1.2 of the submission protocol uses a different authentication
scheme, has a different set of response messages, and doesn't
give any direction about delays between track submissions.
It also adds a 'now playing' submission, which we send from the
regular timeout (limiting it to once per 15 seconds).
Track submissions now include a 'source' parameter, which we don't
properly support yet.
We also implement the current recommendations for delays between
handshake requests when the handshake fails.
---
plugins/audioscrobbler/rb-audioscrobbler-entry.c | 75 ++--
plugins/audioscrobbler/rb-audioscrobbler-entry.h | 4 +
plugins/audioscrobbler/rb-audioscrobbler.c | 390 ++++++++++------------
3 files changed, 215 insertions(+), 254 deletions(-)
diff --git a/plugins/audioscrobbler/rb-audioscrobbler-entry.c b/plugins/audioscrobbler/rb-audioscrobbler-entry.c
index 885cb9f..e485ff0 100644
--- a/plugins/audioscrobbler/rb-audioscrobbler-entry.c
+++ b/plugins/audioscrobbler/rb-audioscrobbler-entry.c
@@ -43,9 +43,6 @@
#include "rb-audioscrobbler-entry.h"
-#define SCROBBLER_DATE_FORMAT "%Y%%2D%m%%2D%d%%20%H%%3A%M%%3A%S"
-
-
void
rb_audioscrobbler_entry_init (AudioscrobblerEntry *entry)
{
@@ -55,6 +52,7 @@ rb_audioscrobbler_entry_init (AudioscrobblerEntry *entry)
entry->length = 0;
entry->play_time = 0;
entry->mbid = g_strdup ("");
+ entry->source = g_strdup ("P");
}
void
@@ -64,6 +62,7 @@ rb_audioscrobbler_entry_free (AudioscrobblerEntry *entry)
g_free (entry->album);
g_free (entry->title);
g_free (entry->mbid);
+ g_free (entry->source);
g_free (entry);
}
@@ -76,6 +75,8 @@ rb_audioscrobbler_encoded_entry_free (AudioscrobblerEncodedEntry *entry)
g_free (entry->title);
g_free (entry->mbid);
g_free (entry->timestamp);
+ g_free (entry->source);
+ g_free (entry->track);
g_free (entry);
}
@@ -86,20 +87,30 @@ rb_audioscrobbler_entry_create (RhythmDBEntry *rb_entry)
{
AudioscrobblerEntry *as_entry = g_new0 (AudioscrobblerEntry, 1);
- as_entry->title = rhythmdb_entry_dup_string (rb_entry,
- RHYTHMDB_PROP_TITLE);
- as_entry->artist = rhythmdb_entry_dup_string (rb_entry,
- RHYTHMDB_PROP_ARTIST);
- as_entry->album = rhythmdb_entry_dup_string (rb_entry,
- RHYTHMDB_PROP_ALBUM);
+ as_entry->title = rhythmdb_entry_dup_string (rb_entry, RHYTHMDB_PROP_TITLE);
+ as_entry->track = rhythmdb_entry_get_ulong (rb_entry, RHYTHMDB_PROP_TRACK_NUMBER);
+ as_entry->artist = rhythmdb_entry_dup_string (rb_entry, RHYTHMDB_PROP_ARTIST);
+ as_entry->album = rhythmdb_entry_dup_string (rb_entry, RHYTHMDB_PROP_ALBUM);
if (strcmp (as_entry->album, _("Unknown")) == 0) {
g_free (as_entry->album);
as_entry->album = g_strdup ("");
}
- as_entry->length = rhythmdb_entry_get_ulong (rb_entry,
- RHYTHMDB_PROP_DURATION);
- as_entry->mbid = rhythmdb_entry_dup_string (rb_entry,
- RHYTHMDB_PROP_MUSICBRAINZ_TRACKID);
+
+ as_entry->length = rhythmdb_entry_get_ulong (rb_entry, RHYTHMDB_PROP_DURATION);
+ as_entry->mbid = rhythmdb_entry_dup_string (rb_entry, RHYTHMDB_PROP_MUSICBRAINZ_TRACKID);
+ if (strcmp (as_entry->mbid, _("Unknown")) == 0) {
+ g_free (as_entry->mbid);
+ as_entry->mbid = g_strdup ("");
+ }
+
+ /*
+ * TODO: identify the source type. we just use 'P' for everything for now.
+ * should use 'R' for iradio, 'P' for everything else except last.fm.
+ * for last.fm, we need to extract the recommendation key from the db entry's
+ * extra data (see RBLastfmTrackEntryData in rb-lastfm-source.c) and include
+ * that in the source info here.
+ */
+ as_entry->source = g_strdup ("P");
return as_entry;
}
@@ -112,19 +123,16 @@ rb_audioscrobbler_entry_encode (AudioscrobblerEntry *entry)
encoded = g_new0 (AudioscrobblerEncodedEntry, 1);
- encoded->artist = soup_uri_encode (entry->artist,
- EXTRA_URI_ENCODE_CHARS);
- encoded->title = soup_uri_encode (entry->title,
- EXTRA_URI_ENCODE_CHARS);
- encoded->album = soup_uri_encode (entry->album,
- EXTRA_URI_ENCODE_CHARS);
- encoded->mbid = soup_uri_encode (entry->mbid,
- EXTRA_URI_ENCODE_CHARS);
- encoded->timestamp = g_new0 (gchar, 30);
- strftime (encoded->timestamp, 30, SCROBBLER_DATE_FORMAT,
- gmtime (&entry->play_time));
+ encoded->artist = soup_uri_encode (entry->artist, EXTRA_URI_ENCODE_CHARS);
+ encoded->title = soup_uri_encode (entry->title, EXTRA_URI_ENCODE_CHARS);
+ encoded->album = soup_uri_encode (entry->album, EXTRA_URI_ENCODE_CHARS);
+ encoded->track = g_strdup_printf ("%lu", entry->track);
+
+ encoded->mbid = soup_uri_encode (entry->mbid, EXTRA_URI_ENCODE_CHARS);
+ encoded->timestamp = g_strdup_printf("%ld", entry->play_time);
encoded->length = entry->length;
+ encoded->source = g_strdup (entry->source);
return encoded;
}
@@ -164,14 +172,11 @@ rb_audioscrobbler_entry_load_from_string (const char *string)
if (g_str_has_prefix (breaks2[0], "l")) {
entry->length = atoi (breaks2[1]);
}
- if (g_str_has_prefix (breaks2[0], "i")) {
- struct tm tm;
- strptime (breaks2[1], SCROBBLER_DATE_FORMAT,
- &tm);
- entry->play_time = mktime (&tm);
- }
- /* slight format extension: time_t */
- if (g_str_has_prefix (breaks2[0], "I")) {
+ /* 'I' here is for backwards compatibility with queue files
+ * saved while we were using the 1.1 protocol. see bug 508895.
+ */
+ if (g_str_has_prefix (breaks2[0], "i") ||
+ g_str_has_prefix (breaks2[0], "I")) {
entry->play_time = strtol (breaks2[1], NULL, 10);
}
}
@@ -196,7 +201,7 @@ rb_audioscrobbler_entry_save_to_string (GString *string, AudioscrobblerEntry *en
encoded = rb_audioscrobbler_entry_encode (entry);
g_string_append_printf (string,
- "a=%s&t=%s&b=%s&m=%s&l=%d&I=%ld\n",
+ "a=%s&t=%s&b=%s&m=%s&l=%d&i=%ld\n",
encoded->artist,
encoded->title,
encoded->album,
@@ -209,14 +214,10 @@ rb_audioscrobbler_entry_save_to_string (GString *string, AudioscrobblerEntry *en
void
rb_audioscrobbler_entry_debug (AudioscrobblerEntry *entry, int index)
{
- char timestamp[30];
rb_debug ("%-3d artist: %s", index, entry->artist);
rb_debug (" album: %s", entry->album);
rb_debug (" title: %s", entry->title);
rb_debug (" length: %d", entry->length);
rb_debug (" playtime: %ld", entry->play_time);
- strftime (timestamp, 30, SCROBBLER_DATE_FORMAT,
- gmtime (&entry->play_time));
- rb_debug (" timestamp: %s", timestamp);
}
diff --git a/plugins/audioscrobbler/rb-audioscrobbler-entry.h b/plugins/audioscrobbler/rb-audioscrobbler-entry.h
index d25a50e..89ab70e 100644
--- a/plugins/audioscrobbler/rb-audioscrobbler-entry.h
+++ b/plugins/audioscrobbler/rb-audioscrobbler-entry.h
@@ -40,8 +40,10 @@ typedef struct
gchar *album;
gchar *title;
guint length;
+ gulong track;
gchar *mbid;
time_t play_time;
+ gchar *source;
} AudioscrobblerEntry;
typedef struct
@@ -52,6 +54,8 @@ typedef struct
guint length;
gchar *mbid;
gchar *timestamp;
+ gchar *source;
+ gchar *track;
} AudioscrobblerEncodedEntry;
diff --git a/plugins/audioscrobbler/rb-audioscrobbler.c b/plugins/audioscrobbler/rb-audioscrobbler.c
index 1953793..0b9d148 100644
--- a/plugins/audioscrobbler/rb-audioscrobbler.c
+++ b/plugins/audioscrobbler/rb-audioscrobbler.c
@@ -65,10 +65,14 @@
#define CLIENT_ID "rbx"
#define CLIENT_VERSION VERSION
+
#define MAX_QUEUE_SIZE 1000
-#define MAX_SUBMIT_SIZE 10
+#define MAX_SUBMIT_SIZE 50
+#define INITIAL_HANDSHAKE_DELAY 60
+#define MAX_HANDSHAKE_DELAY 120*60
+
#define SCROBBLER_URL "http://post.audioscrobbler.com/"
-#define SCROBBLER_VERSION "1.1"
+#define SCROBBLER_VERSION "1.2"
#define USER_AGENT "Rhythmbox/" VERSION
@@ -95,13 +99,10 @@ struct _RBAudioscrobblerPrivate
STATUS_OK = 0,
HANDSHAKING,
REQUEST_FAILED,
- BAD_USERNAME,
- BAD_PASSWORD,
- HANDSHAKE_FAILED,
- CLIENT_UPDATE_REQUIRED,
- SUBMIT_FAILED,
- QUEUE_TOO_LONG,
- GIVEN_UP,
+ BADAUTH,
+ BAD_TIMESTAMP,
+ CLIENT_BANNED,
+ GIVEN_UP
} status;
char *status_msg;
@@ -111,26 +112,27 @@ struct _RBAudioscrobblerPrivate
GQueue *submission;
guint failures;
+ guint handshake_delay;
/* Handshake has been done? */
gboolean handshake;
time_t handshake_next;
- time_t submit_next;
- time_t submit_interval;
/* Only write the queue to a file if it has been changed */
gboolean queue_changed;
/* Authentication cookie + authentication info */
- gchar *md5_challenge;
+ gchar *sessionid;
gchar *username;
gchar *password;
gchar *submit_url;
+ gchar *nowplaying_url;
/* Currently playing song info, if NULL this means the currently
* playing song isn't eligible to be queued
*/
AudioscrobblerEntry *currently_playing;
guint current_elapsed;
+ gboolean now_playing_updated;
/* Preference notifications */
guint notification_username_id;
@@ -171,7 +173,7 @@ static void rb_audioscrobbler_add_timeout (RBAudioscrobbler *audioscrobbler
static gboolean rb_audioscrobbler_timeout_cb (RBAudioscrobbler *audioscrobbler);
static gchar * mkmd5 (char *string);
-static void rb_audioscrobbler_parse_response (RBAudioscrobbler *audioscrobbler, SoupMessage *msg);
+static void rb_audioscrobbler_parse_response (RBAudioscrobbler *audioscrobbler, SoupMessage *msg, gboolean handshake);
static void rb_audioscrobbler_do_handshake (RBAudioscrobbler *audioscrobbler);
static void rb_audioscrobbler_submit_queue (RBAudioscrobbler *audioscrobbler);
@@ -181,6 +183,7 @@ static void rb_audioscrobbler_perform (RBAudioscrobbler *audioscrobbler,
SoupSessionCallback response_handler);
static void rb_audioscrobbler_do_handshake_cb (SoupSession *session, SoupMessage *msg, gpointer user_data);
static void rb_audioscrobbler_submit_queue_cb (SoupSession *session, SoupMessage *msg, gpointer user_data);
+static void rb_audioscrobbler_nowplaying_cb (SoupSession *session, SoupMessage *msg, gpointer user_data);
static void rb_audioscrobbler_import_settings (RBAudioscrobbler *audioscrobbler);
static void rb_audioscrobbler_preferences_sync (RBAudioscrobbler *audioscrobbler);
@@ -200,6 +203,9 @@ static void rb_audioscrobbler_offline_play_notify_cb (RhythmDB *db,
const GValue *metadata,
RBAudioscrobbler *audioscrobbler);
+static void rb_audioscrobbler_nowplaying (RBAudioscrobbler *audioscrobbler, AudioscrobblerEntry *entry);
+
+
enum
@@ -288,10 +294,11 @@ rb_audioscrobbler_init (RBAudioscrobbler *audioscrobbler)
audioscrobbler->priv->queue = g_queue_new();
audioscrobbler->priv->submission = g_queue_new();
- audioscrobbler->priv->md5_challenge = g_strdup ("");
+ audioscrobbler->priv->sessionid = g_strdup ("");
audioscrobbler->priv->username = NULL;
audioscrobbler->priv->password = NULL;
audioscrobbler->priv->submit_url = g_strdup ("");
+ audioscrobbler->priv->nowplaying_url = g_strdup ("");
rb_audioscrobbler_load_queue (audioscrobbler);
@@ -382,10 +389,12 @@ rb_audioscrobbler_finalize (GObject *object)
/* Save any remaining entries */
rb_audioscrobbler_save_queue (audioscrobbler);
- g_free (audioscrobbler->priv->md5_challenge);
+ g_free (audioscrobbler->priv->sessionid);
g_free (audioscrobbler->priv->username);
g_free (audioscrobbler->priv->password);
g_free (audioscrobbler->priv->submit_url);
+ g_free (audioscrobbler->priv->nowplaying_url);
+
if (audioscrobbler->priv->currently_playing != NULL) {
rb_audioscrobbler_entry_free (audioscrobbler->priv->currently_playing);
audioscrobbler->priv->currently_playing = NULL;
@@ -520,28 +529,6 @@ rb_audioscrobbler_is_queueable (RhythmDBEntry *entry)
return TRUE;
}
-static AudioscrobblerEntry *
-rb_audioscrobbler_create_entry (RhythmDBEntry *rb_entry)
-{
- AudioscrobblerEntry *as_entry = g_new0 (AudioscrobblerEntry, 1);
-
- as_entry->title = rhythmdb_entry_dup_string (rb_entry,
- RHYTHMDB_PROP_TITLE);
- as_entry->artist = rhythmdb_entry_dup_string (rb_entry,
- RHYTHMDB_PROP_ARTIST);
- as_entry->album = rhythmdb_entry_dup_string (rb_entry,
- RHYTHMDB_PROP_ALBUM);
- if (strcmp (as_entry->album, _("Unknown")) == 0) {
- g_free (as_entry->album);
- as_entry->album = g_strdup ("");
- }
- as_entry->length = rhythmdb_entry_get_ulong (rb_entry,
- RHYTHMDB_PROP_DURATION);
- as_entry->mbid = rhythmdb_entry_dup_string (rb_entry,
- RHYTHMDB_PROP_MUSICBRAINZ_TRACKID);
-
- return as_entry;
-}
static void
rb_audioscrobbler_add_to_queue (RBAudioscrobbler *audioscrobbler,
@@ -582,10 +569,9 @@ maybe_add_current_song_to_queue (RBAudioscrobbler *audioscrobbler)
if ((elapsed >= cur_entry->length / 2 || elapsed >= 240) && elapsed_delta < 20) {
rb_debug ("Adding currently playing song to queue");
- time (&cur_entry->play_time);
rb_audioscrobbler_add_to_queue (audioscrobbler, cur_entry);
audioscrobbler->priv->currently_playing = NULL;
-
+
rb_audioscrobbler_preferences_sync (audioscrobbler);
} else if (elapsed_delta > 20) {
rb_debug ("Skipping detected; not submitting current song");
@@ -594,7 +580,6 @@ maybe_add_current_song_to_queue (RBAudioscrobbler *audioscrobbler)
*/
rb_audioscrobbler_entry_free (audioscrobbler->priv->currently_playing);
audioscrobbler->priv->currently_playing = NULL;
-
}
}
}
@@ -608,12 +593,21 @@ rb_audioscrobbler_timeout_cb (RBAudioscrobbler *audioscrobbler)
/* do handshake if we need to */
rb_audioscrobbler_do_handshake (audioscrobbler);
+ if ((audioscrobbler->priv->now_playing_updated == FALSE) &&
+ (audioscrobbler->priv->currently_playing != NULL) &&
+ audioscrobbler->priv->handshake) {
+ rb_debug ("Sending now playing data");
+ audioscrobbler->priv->now_playing_updated = TRUE;
+ rb_audioscrobbler_nowplaying (audioscrobbler, audioscrobbler->priv->currently_playing);
+ }
+
/* if there's something in the queue, submit it if we can, save it otherwise */
if (!g_queue_is_empty(audioscrobbler->priv->queue)) {
- if (audioscrobbler->priv->handshake)
+ if (audioscrobbler->priv->handshake) {
rb_audioscrobbler_submit_queue (audioscrobbler);
- else
+ } else {
rb_audioscrobbler_save_queue (audioscrobbler);
+ }
}
return TRUE;
}
@@ -631,7 +625,7 @@ rb_audioscrobbler_offline_play_notify_cb (RhythmDB *db,
if (rb_audioscrobbler_is_queueable (rb_entry)) {
AudioscrobblerEntry *as_entry;
- as_entry = rb_audioscrobbler_create_entry (rb_entry);
+ as_entry = rb_audioscrobbler_entry_create (rb_entry);
as_entry->play_time = g_value_get_ulong (metadata);
rb_audioscrobbler_add_to_queue (audioscrobbler, as_entry);
}
@@ -656,88 +650,63 @@ mkmd5 (char *string)
}
static void
-rb_audioscrobbler_parse_response (RBAudioscrobbler *audioscrobbler, SoupMessage *msg)
+rb_audioscrobbler_parse_response (RBAudioscrobbler *audioscrobbler, SoupMessage *msg, gboolean handshake)
{
gboolean successful;
- rb_debug ("Parsing response, status=%d", msg->status_code);
-
+
+ rb_debug ("Parsing response, status=%d Reason: %s", msg->status_code, msg->reason_phrase);
+
successful = FALSE;
if (SOUP_STATUS_IS_SUCCESSFUL (msg->status_code) && msg->response_body->length != 0)
successful = TRUE;
+
if (successful) {
gchar **breaks;
- int i;
- breaks = g_strsplit (msg->response_body->data, "\n", 4);
+
+ breaks = g_strsplit (msg->response_body->data, "\n", 0);
g_free (audioscrobbler->priv->status_msg);
audioscrobbler->priv->status = STATUS_OK;
audioscrobbler->priv->status_msg = NULL;
- for (i = 0; breaks[i] != NULL; i++) {
- rb_debug ("RESPONSE: %s", breaks[i]);
- if (g_str_has_prefix (breaks[i], "UPTODATE")) {
- rb_debug ("UPTODATE");
-
- if (breaks[i+1] != NULL) {
- g_free (audioscrobbler->priv->md5_challenge);
- audioscrobbler->priv->md5_challenge = g_strdup (breaks[i+1]);
- rb_debug ("MD5 challenge: \"%s\"", audioscrobbler->priv->md5_challenge);
-
- if (breaks[i+2] != NULL) {
- g_free (audioscrobbler->priv->submit_url);
- audioscrobbler->priv->submit_url = g_strdup (breaks[i+2]);
- rb_debug ("Submit URL: \"%s\"", audioscrobbler->priv->submit_url);
- i++;
- }
- i++;
- }
-
- } else if (g_str_has_prefix (breaks[i], "UPDATE")) {
- rb_debug ("UPDATE");
- audioscrobbler->priv->status = CLIENT_UPDATE_REQUIRED;
-
- if (breaks[i+1] != NULL) {
- g_free (audioscrobbler->priv->md5_challenge);
- audioscrobbler->priv->md5_challenge = g_strdup (breaks[i+1]);
- rb_debug ("MD5 challenge: \"%s\"", audioscrobbler->priv->md5_challenge);
-
- if (breaks[i+2] != NULL) {
- g_free (audioscrobbler->priv->submit_url);
- audioscrobbler->priv->submit_url = g_strdup (breaks[i+2]);
- rb_debug ("Submit URL: \"%s\"", audioscrobbler->priv->submit_url);
- i++;
- }
- i++;
- }
-
- } else if (g_str_has_prefix (breaks[i], "FAILED")) {
- audioscrobbler->priv->status = HANDSHAKE_FAILED;
- if (strlen (breaks[i]) > 7) {
- rb_debug ("FAILED: \"%s\"", breaks[i] + 7);
- audioscrobbler->priv->status_msg = g_strdup (breaks[i] + 7);
+ if (g_str_has_prefix (breaks[0], "OK")) {
+ rb_debug ("OK");
+ if (handshake) {
+ if (g_strv_length (breaks) < 4) {
+ g_warning ("Unexpectedly short successful last.fm handshake response:\n%s",
+ msg->response_body->data);
+ audioscrobbler->priv->status = REQUEST_FAILED;
} else {
- rb_debug ("FAILED");
+ g_free (audioscrobbler->priv->sessionid);
+ g_free (audioscrobbler->priv->nowplaying_url);
+ g_free (audioscrobbler->priv->submit_url);
+ audioscrobbler->priv->sessionid = g_strdup (breaks[1]);
+ audioscrobbler->priv->nowplaying_url = g_strdup (breaks[2]);
+ audioscrobbler->priv->submit_url = g_strdup (breaks[3]);
}
-
-
- } else if (g_str_has_prefix (breaks[i], "BADUSER")) {
- rb_debug ("BADUSER");
- audioscrobbler->priv->status = BAD_USERNAME;
- } else if (g_str_has_prefix (breaks[i], "BADAUTH")) {
- rb_debug ("BADAUTH");
- audioscrobbler->priv->status = BAD_PASSWORD;
- } else if (g_str_has_prefix (breaks[i], "OK")) {
- rb_debug ("OK");
- } else if (g_str_has_prefix (breaks[i], "INTERVAL ")) {
- audioscrobbler->priv->submit_interval = g_ascii_strtod(breaks[i] + 9, NULL);
- rb_debug ("INTERVAL: %s", breaks[i] + 9);
}
+ } else if (g_str_has_prefix (breaks[0], "BANNED")) {
+ rb_debug ("Client banned");
+ audioscrobbler->priv->status = CLIENT_BANNED;
+ } else if (g_str_has_prefix (breaks[0], "BADAUTH")) {
+ rb_debug ("Bad authorization");
+ audioscrobbler->priv->status = BADAUTH;
+ } else if (g_str_has_prefix (breaks[0], "BADTIME")) {
+ rb_debug ("Bad timestamp");
+ audioscrobbler->priv->status = BAD_TIMESTAMP;
+ } else if (g_str_has_prefix (breaks[0], "FAILED")) {
+ rb_debug ("Server failure:\n \tMessage: %s", breaks[0]);
+ audioscrobbler->priv->status = REQUEST_FAILED;
+ /* this is probably going to be ugly, but there isn't much we can do */
+ if (strlen (breaks[0]) > strlen ("FAILED ")) {
+ audioscrobbler->priv->status_msg = g_strdup (breaks[0] + strlen ("FAILED "));
+ }
+ } else {
+ g_warning ("Unexpected last.fm response:\n%s",
+ msg->response_body->data);
+ audioscrobbler->priv->status = REQUEST_FAILED;
}
- /* respect the last submit interval we were given */
- if (audioscrobbler->priv->submit_interval > 0)
- audioscrobbler->priv->submit_next = time(NULL) + audioscrobbler->priv->submit_interval;
-
g_strfreev (breaks);
} else {
audioscrobbler->priv->status = REQUEST_FAILED;
@@ -829,6 +798,9 @@ rb_audioscrobbler_do_handshake (RBAudioscrobbler *audioscrobbler)
gchar *scrobbler_url;
gchar *username;
gchar *url;
+ gchar *auth;
+ gchar *autharg;
+ guint timestamp;
if (!rb_audioscrobbler_should_handshake (audioscrobbler)) {
return;
@@ -840,18 +812,24 @@ rb_audioscrobbler_do_handshake (RBAudioscrobbler *audioscrobbler)
}
username = soup_uri_encode (audioscrobbler->priv->username, EXTRA_URI_ENCODE_CHARS);
- url = g_strdup_printf ("%s?hs=true&p=%s&c=%s&v=%s&u=%s",
+ timestamp = time (NULL);
+
+ autharg = g_strdup_printf ("%s%d", mkmd5 (audioscrobbler->priv->password), timestamp);
+ auth = mkmd5 (autharg);
+
+ url = g_strdup_printf ("%s?hs=true&p=%s&c=%s&v=%s&u=%s&t=%d&a=%s",
scrobbler_url,
SCROBBLER_VERSION,
CLIENT_ID,
CLIENT_VERSION,
- username);
+ username,
+ timestamp,
+ auth);
+ g_free (auth);
+ g_free (autharg);
g_free (scrobbler_url);
g_free (username);
- /* Make sure we wait at least 30 minutes between handshakes. */
- audioscrobbler->priv->handshake_next = time (NULL) + 1800;
-
rb_debug ("Performing handshake with Audioscrobbler server: %s", url);
audioscrobbler->priv->status = HANDSHAKING;
@@ -872,120 +850,66 @@ rb_audioscrobbler_do_handshake_cb (SoupSession *session, SoupMessage *msg, gpoin
RBAudioscrobbler *audioscrobbler = RB_AUDIOSCROBBLER(user_data);
rb_debug ("Handshake response");
- rb_audioscrobbler_parse_response (audioscrobbler, msg);
+ rb_audioscrobbler_parse_response (audioscrobbler, msg, TRUE);
rb_audioscrobbler_preferences_sync (audioscrobbler);
switch (audioscrobbler->priv->status) {
case STATUS_OK:
- case CLIENT_UPDATE_REQUIRED:
audioscrobbler->priv->handshake = TRUE;
+ audioscrobbler->priv->handshake_delay = INITIAL_HANDSHAKE_DELAY;
audioscrobbler->priv->failures = 0;
break;
default:
rb_debug ("Handshake failed");
++audioscrobbler->priv->failures;
- break;
- }
-
- g_idle_add ((GSourceFunc) idle_unref_cb, audioscrobbler);
-}
-
-static gchar *
-rb_audioscrobbler_build_authentication_data (RBAudioscrobbler *audioscrobbler)
-{
- gchar *md5_password;
- gchar *md5_temp;
- gchar *md5_response;
- gchar *username;
- gchar *post_data;
- time_t now;
+ audioscrobbler->priv->handshake_next = time (NULL) + audioscrobbler->priv->handshake_delay;
- /* Conditions:
- * - Must have username and password
- * - Must have md5_challenge
- * - Queue must not be empty
- */
- if ((audioscrobbler->priv->username == NULL)
- || (*audioscrobbler->priv->username == '\0')) {
- rb_debug ("No username set");
- return NULL;
- }
-
- if ((audioscrobbler->priv->password == NULL)
- || (*audioscrobbler->priv->password == '\0')) {
- rb_debug ("No password set");
- return NULL;
- }
-
- if (*audioscrobbler->priv->md5_challenge == '\0') {
- rb_debug ("No md5 challenge");
- return NULL;
- }
-
- time(&now);
- if (now < audioscrobbler->priv->submit_next) {
- rb_debug ("Too soon (next submission in %ld seconds)",
- audioscrobbler->priv->submit_next - now);
- return NULL;
- }
-
- if (g_queue_is_empty (audioscrobbler->priv->queue)) {
- rb_debug ("No queued songs to submit");
- return NULL;
+ audioscrobbler->priv->handshake_delay *= 2;
+ if (audioscrobbler->priv->handshake_delay > MAX_HANDSHAKE_DELAY) {
+ audioscrobbler->priv->handshake_delay = MAX_HANDSHAKE_DELAY;
+ }
+ rb_debug ("handshake delay is now %d minutes", audioscrobbler->priv->handshake_delay/60);
+ break;
}
- md5_password = mkmd5 (audioscrobbler->priv->password);
- md5_temp = g_strconcat (md5_password,
- audioscrobbler->priv->md5_challenge,
- NULL);
- md5_response = mkmd5 (md5_temp);
-
- username = soup_uri_encode (audioscrobbler->priv->username,
- EXTRA_URI_ENCODE_CHARS);
- post_data = g_strdup_printf ("u=%s&s=%s&", username, md5_response);
-
- g_free (md5_password);
- g_free (md5_temp);
- g_free (md5_response);
- g_free (username);
-
- return post_data;
+ g_idle_add ((GSourceFunc) idle_unref_cb, audioscrobbler);
}
static gchar *
-rb_audioscrobbler_build_post_data (RBAudioscrobbler *audioscrobbler,
- const gchar *authentication_data)
+rb_audioscrobbler_build_post_data (RBAudioscrobbler *audioscrobbler)
{
- g_return_val_if_fail (!g_queue_is_empty (audioscrobbler->priv->queue),
- NULL);
+ g_return_val_if_fail (!g_queue_is_empty (audioscrobbler->priv->queue), NULL);
- gchar *post_data = g_strdup (authentication_data);
+ gchar *post_data = g_strdup_printf ("s=%s", audioscrobbler->priv->sessionid);
int i = 0;
do {
AudioscrobblerEntry *entry;
AudioscrobblerEncodedEntry *encoded;
gchar *new;
+
/* remove first queue entry */
entry = g_queue_pop_head (audioscrobbler->priv->queue);
encoded = rb_audioscrobbler_entry_encode (entry);
- new = g_strdup_printf ("%sa[%d]=%s&t[%d]=%s&b[%d]=%s&m[%d]=%s&l[%d]=%d&i[%d]=%s&",
+ new = g_strdup_printf ("%s&a[%d]=%s&t[%d]=%s&b[%d]=%s&m[%d]=%s&l[%d]=%d&i[%d]=%s&o[%d]=%s&n[%d]=%s&r[%d]=",
post_data,
i, encoded->artist,
i, encoded->title,
i, encoded->album,
i, encoded->mbid,
i, encoded->length,
- i, encoded->timestamp);
+ i, encoded->timestamp,
+ i, encoded->source,
+ i, encoded->track,
+ i);
rb_audioscrobbler_encoded_entry_free (encoded);
g_free (post_data);
post_data = new;
/* add to submission list */
- g_queue_push_tail (audioscrobbler->priv->submission,
- entry);
+ g_queue_push_tail (audioscrobbler->priv->submission, entry);
i++;
- } while ((!g_queue_is_empty(audioscrobbler->priv->queue)) && (i < MAX_SUBMIT_SIZE));
+ } while ((!g_queue_is_empty (audioscrobbler->priv->queue)) && (i < MAX_SUBMIT_SIZE));
return post_data;
}
@@ -993,15 +917,11 @@ rb_audioscrobbler_build_post_data (RBAudioscrobbler *audioscrobbler,
static void
rb_audioscrobbler_submit_queue (RBAudioscrobbler *audioscrobbler)
{
- gchar *auth_data;
-
- auth_data = rb_audioscrobbler_build_authentication_data (audioscrobbler);
- if (auth_data != NULL) {
+ if (audioscrobbler->priv->sessionid != NULL) {
gchar *post_data;
- post_data = rb_audioscrobbler_build_post_data (audioscrobbler,
- auth_data);
- g_free (auth_data);
+ post_data = rb_audioscrobbler_build_post_data (audioscrobbler);
+
rb_debug ("Submitting queue to Audioscrobbler");
rb_audioscrobbler_print_queue (audioscrobbler, TRUE);
@@ -1030,7 +950,7 @@ rb_audioscrobbler_submit_queue_cb (SoupSession *session, SoupMessage *msg, gpoin
RBAudioscrobbler *audioscrobbler = RB_AUDIOSCROBBLER (user_data);
rb_debug ("Submission response");
- rb_audioscrobbler_parse_response (audioscrobbler, msg);
+ rb_audioscrobbler_parse_response (audioscrobbler, msg, FALSE);
if (audioscrobbler->priv->status == STATUS_OK) {
rb_debug ("Queue submitted successfully");
@@ -1118,23 +1038,14 @@ rb_audioscrobbler_preferences_sync (RBAudioscrobbler *audioscrobbler)
case REQUEST_FAILED:
status = _("Request failed");
break;
- case BAD_USERNAME:
- status = _("Incorrect username");
- break;
- case BAD_PASSWORD:
- status = _("Incorrect password");
- break;
- case HANDSHAKE_FAILED:
- status = _("Handshake failed");
+ case BADAUTH:
+ status = _("Incorrect username or password");
break;
- case CLIENT_UPDATE_REQUIRED:
- status = _("Client update required");
+ case BAD_TIMESTAMP:
+ status = _("Clock is not set correctly");
break;
- case SUBMIT_FAILED:
- status = _("Track submission failed");
- break;
- case QUEUE_TOO_LONG:
- status = _("Queue is too long");
+ case CLIENT_BANNED:
+ status = _("This version of Rhythmbox has been banned from Last.fm.");
break;
case GIVEN_UP:
status = _("Track submission failed too many times");
@@ -1285,7 +1196,7 @@ rb_audioscrobbler_song_changed_cb (RBShellPlayer *player,
RBAudioscrobbler *audioscrobbler)
{
gboolean got_time;
- guint time;
+ guint playing_time;
if (audioscrobbler->priv->currently_playing != NULL) {
rb_audioscrobbler_entry_free (audioscrobbler->priv->currently_playing);
@@ -1299,23 +1210,25 @@ rb_audioscrobbler_song_changed_cb (RBShellPlayer *player,
rb_debug ("new entry: %s", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION));
got_time = rb_shell_player_get_playing_time (audioscrobbler->priv->shell_player,
- &time,
+ &playing_time,
NULL);
if (got_time) {
- audioscrobbler->priv->current_elapsed = (int) time;
+ audioscrobbler->priv->current_elapsed = (int) playing_time;
} else {
rb_debug ("didn't get playing time; assuming 0");
audioscrobbler->priv->current_elapsed = 0;
}
- if (rb_audioscrobbler_is_queueable (entry) && (got_time == FALSE || time < 15)) {
+ if (rb_audioscrobbler_is_queueable (entry) && (got_time == FALSE || playing_time < 15)) {
AudioscrobblerEntry *as_entry;
-
+
/* even if it's the same song, it's being played again from
* the start so we can queue it again.
*/
- as_entry = rb_audioscrobbler_create_entry (entry);
+ as_entry = rb_audioscrobbler_entry_create (entry);
+ as_entry->play_time = time (NULL);
audioscrobbler->priv->currently_playing = as_entry;
+ audioscrobbler->priv->now_playing_updated = FALSE;
}
}
@@ -1482,3 +1395,46 @@ rb_audioscrobbler_free_queue_entries (RBAudioscrobbler *audioscrobbler, GQueue *
audioscrobbler->priv->queue_changed = TRUE;
}
+
+static void
+rb_audioscrobbler_nowplaying (RBAudioscrobbler *audioscrobbler, AudioscrobblerEntry *entry)
+{
+ AudioscrobblerEncodedEntry *encoded;
+ gchar *post_data;
+
+ if (audioscrobbler->priv->handshake) {
+ encoded = rb_audioscrobbler_entry_encode (entry);
+
+ post_data = g_strdup_printf ("s=%s&a=%s&t=%s&b=%s&l=%d&n=%s&m=%s",
+ audioscrobbler->priv->sessionid,
+ encoded->artist,
+ encoded->title,
+ encoded->album,
+ encoded->length,
+ encoded->track,
+ encoded->mbid);
+
+ rb_audioscrobbler_perform (audioscrobbler,
+ audioscrobbler->priv->nowplaying_url,
+ post_data,
+ rb_audioscrobbler_nowplaying_cb);
+
+ rb_audioscrobbler_encoded_entry_free (encoded);
+ }
+}
+
+static void
+rb_audioscrobbler_nowplaying_cb (SoupSession *session, SoupMessage *msg, gpointer user_data)
+{
+ RBAudioscrobbler *audioscrobbler = RB_AUDIOSCROBBLER (user_data);
+ rb_debug ("Now playing response");
+ rb_audioscrobbler_parse_response (audioscrobbler, msg, FALSE);
+
+ if (audioscrobbler->priv->status == STATUS_OK) {
+ rb_debug("Submission success!");
+ } else {
+ rb_debug("Error submitting now playing information.");
+ }
+
+ g_idle_add ((GSourceFunc) idle_unref_cb, audioscrobbler);
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]