Patch updated, thanks for your remark !<br><br><div class="gmail_quote">On Sun, Mar 11, 2012 at 12:05 PM, <span dir="ltr"><<a href="mailto:samuel.pitoiset@gmail.com">samuel.pitoiset@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
From: Samuel Pitoiset <<a href="mailto:samuel.pitoiset@gmail.com">samuel.pitoiset@gmail.com</a>><br>
<div class="im"><br>
---<br>
modules/misc/audioscrobbler.c | 268 +++++++++++++++++++++++++++++++++++++++++<br>
1 file changed, 268 insertions(+)<br>
<br>
diff --git a/modules/misc/audioscrobbler.c b/modules/misc/audioscrobbler.c<br>
</div>index 0da533e..28d5a80 100644<br>
<div><div class="h5">--- a/modules/misc/audioscrobbler.c<br>
+++ b/modules/misc/audioscrobbler.c<br>
@@ -1154,6 +1154,274 @@ static void HandleInterval(mtime_t *next, unsigned int *i_interval)<br>
}<br>
<br>
/*****************************************************************************<br>
+ * Scrobble : scrobble songs<br>
+ *****************************************************************************/<br>
+static int Scrobble(intf_thread_t *p_this)<br>
+{<br>
+ intf_sys_t *p_sys = p_this->p_sys;<br>
+ xml_reader_t *p_xml_reader = NULL;<br>
+ vlc_array_t p_params;<br>
+ stream_t *p_stream;<br>
+ uint8_t p_buf[1024];<br>
+ char *psz_request;<br>
+ int i_song;<br>
+<br>
+ vlc_array_init(&p_params);<br>
+<br>
+ vlc_mutex_lock(&p_sys->lock);<br>
+ for (i_song = 0 ; i_song < p_sys->i_songs ; i_song++)<br>
+ {<br>
+ audioscrobbler_song_t *p_song = &p_sys->p_queue[i_song];<br>
+ char psz_key[1024], psz_val[1024];<br>
+<br>
+ /* album */<br>
+ sprintf(psz_key, "album[%d]", i_song);<br>
+ snprintf(psz_val, 1024, "%s", p_song->psz_b);<br>
+ AddParam(&p_params, strdup(psz_key), strdup(psz_val));<br>
+<br>
+ /* artist */<br>
+ sprintf(psz_key, "artist[%d]", i_song);<br>
+ snprintf(psz_val, 1024, "%s", p_song->psz_a);<br>
+ AddParam(&p_params, strdup(psz_key), strdup(psz_val));<br>
+<br>
+ /* track */<br>
+ sprintf(psz_key, "track[%d]", i_song);<br>
+ snprintf(psz_val, 1024, "%s", p_song->psz_t);<br>
+ AddParam(&p_params, strdup(psz_key), strdup(psz_val));<br>
+<br>
+ /* timestamp */<br>
+ sprintf(psz_key, "timestamp[%d]", i_song);<br>
+ sprintf(psz_val, "%u", (unsigned)p_song->date);<br>
+ AddParam(&p_params, strdup(psz_key), strdup(psz_val));<br>
+<br>
+ /* duration */<br>
+ sprintf(psz_key, "duration[%d]", i_song);<br>
+ sprintf(psz_val, "%d", p_song->i_l);<br>
+ AddParam(&p_params, strdup(psz_key), strdup(psz_val));<br>
+<br>
+ /* track number */<br>
+ sprintf(psz_key, "trackNumber[%d]", i_song);<br>
+ snprintf(psz_val, 1024, "%s", p_song->psz_n);<br>
+ AddParam(&p_params, strdup(psz_key), strdup(psz_val));<br>
+<br>
+ /* MusicBrainz track ID */<br>
+ sprintf(psz_key, "mbid[%d]", i_song);<br>
+ snprintf(psz_val, 1024, "%s", p_song->psz_m);<br>
+ AddParam(&p_params, strdup(psz_key), strdup(psz_val));<br>
+ }<br>
+ vlc_mutex_unlock(&p_sys->lock);<br>
+<br>
+ /* add the method name to the parameters list */<br>
+ AddParam(&p_params, "method", "track.scrobble");<br>
+<br>
+ /* build the HTTP request */<br>
+ psz_request = BuildSignedRequest(p_this, &p_params, POST);<br>
+ vlc_array_clear(&p_params);<br>
+<br>
+ if (!psz_request)<br>
+ return VLC_ENOMEM;<br>
+<br>
+ /* initialize the connection */<br>
+ int i_sock = net_ConnectTCP(p_this, p_sys->p_submit_url.psz_host, 80);<br>
+ if (i_sock == -1)<br>
+ {<br>
+ free(psz_request);<br>
+ return VLC_EGENERIC;<br>
+ }<br>
</div></div><div class="im">+<br>
+ /* transmit the request */<br>
</div>+ int i_net_ret = net_Printf(p_this, i_sock, NULL, "%s", psz_request);<br>
<div class="HOEnZb"><div class="h5">+ free(psz_request);<br>
+<br>
+ if (i_net_ret == -1)<br>
+ goto proto;<br>
+<br>
+ /* read the answer */<br>
+ int i_read = net_Read(p_this, i_sock, NULL, p_buf, sizeof(p_buf) - 1, false);<br>
+ if (i_read <= 0)<br>
+ goto proto;<br>
+<br>
+ /* close the connection */<br>
+ net_Close(i_sock);<br>
+ p_buf[i_read] = '\0';<br>
+<br>
+ /* remove answer headers */<br>
+ char *psz_xml = strstr((const char*) p_buf, "<?xml");<br>
+ if (!psz_xml)<br>
+ goto proto;<br>
+<br>
+ /* create a stream reading answer */<br>
+ p_stream = stream_MemoryNew(p_this, (uint8_t*) psz_xml, strlen(psz_xml), true);<br>
+ if (!p_stream)<br>
+ goto proto;<br>
+<br>
+ /* create an XML reader */<br>
+ p_xml_reader = xml_ReaderCreate(p_this, p_stream);<br>
+ if (!p_xml_reader)<br>
+ goto proto;<br>
+<br>
+ /* check root node */<br>
+ const char *node;<br>
+ if (xml_ReaderNextNode(p_xml_reader, &node) != XML_READER_STARTELEM)<br>
+ {<br>
+ msg_Err(p_this, "invalid file (no root node)");<br>
+ goto proto;<br>
+ }<br>
+<br>
+ if (strcasecmp(node, "lfm"))<br>
+ {<br>
+ msg_Err(p_this, "invalid root node <%s>", node);<br>
+ goto proto;<br>
+ }<br>
+<br>
+ /* check response status */<br>
+ const char *attr, *value;<br>
+ if ((attr = xml_ReaderNextAttr(p_xml_reader, &value)))<br>
+ {<br>
+ if (strcasecmp(attr, "status"))<br>
+ {<br>
+ msg_Err(p_this, "invalid attribute \"%s\"", attr);<br>
+ goto proto;<br>
+ }<br>
+<br>
+ if (strcasecmp(value, "ok"))<br>
+ {<br>
+ /* an error occured */<br>
+ if (!strcasecmp(value, "4"))<br>
+ {<br>
+ /* authentication failed, bad username/password combination */<br>
+ msg_Err(p_this, "<a href="http://last.fm" target="_blank">last.fm</a> username or password is incorrect.");<br>
+ }<br>
+<br>
+ if (!strcasecmp(value, "10"))<br>
+ {<br>
+ /* invalid API key */<br>
+ msg_Err(p_this, "You must be granted a valid key by <a href="http://last.fm" target="_blank">last.fm</a>");<br>
+ }<br>
+<br>
+ if (!strcasecmp(value, "26"))<br>
+ {<br>
+ /* suspend API key */<br>
+ msg_Err(p_this, "Access for your account has been suspended.");<br>
+ }<br>
+<br>
+ goto proto;<br>
+ }<br>
+ }<br>
+<br>
+ stream_Delete(p_stream);<br>
+ xml_ReaderDelete(p_xml_reader);<br>
+<br>
+ return VLC_SUCCESS;<br>
+<br>
+proto:<br>
+ net_Close(i_sock);<br>
+ if (p_stream)<br>
+ stream_Delete(p_stream);<br>
+ if (p_xml_reader)<br>
+ xml_ReaderDelete(p_xml_reader);<br>
+<br>
+ return VLC_EGENERIC;<br>
+}<br>
+<br>
+/*****************************************************************************<br>
+ * Run : call Handshake() then submit songs<br>
+ *****************************************************************************/<br>
+static void NewRun(intf_thread_t *p_this)<br>
+{<br>
+ int canc = vlc_savecancel();<br>
+ bool b_handshaked = false;<br>
+<br>
+ /* data about audioscrobbler session */<br>
+ mtime_t next_exchange; /**< when can we send data */<br>
+ unsigned int i_interval; /**< waiting interval (secs)*/<br>
+<br>
+ intf_sys_t *p_sys = p_this->p_sys;<br>
+<br>
+ /* main loop */<br>
+ for (;;)<br>
+ {<br>
+ vlc_restorecancel(canc);<br>
+ vlc_mutex_lock(&p_sys->lock);<br>
+ mutex_cleanup_push(&p_sys->lock);<br>
+<br>
+ do<br>
+ vlc_cond_wait(&p_sys->wait, &p_sys->lock);<br>
+ while (mdate() < next_exchange);<br>
+<br>
+ vlc_cleanup_run();<br>
+ canc = vlc_savecancel();<br>
+<br>
+ /* handshake if needed */<br>
+ if (!b_handshaked)<br>
+ {<br>
+ msg_Dbg(p_this, "Handshaking with <a href="http://last.fm" target="_blank">last.fm</a> ...");<br>
+<br>
+ switch(Handshake(p_this))<br>
+ {<br>
+ case VLC_ENOMEM:<br>
+ return;<br>
+<br>
+ case VLC_ENOVAR:<br>
+ /* username not set */<br>
+ dialog_Fatal(p_this,<br>
+ _("Last.fm username not set"),<br>
+ "%s", _("Please set a username or disable the "<br>
+ "audioscrobbler plugin, and restart VLC.\n"<br>
+ "Visit <a href="http://www.last.fm/join/" target="_blank">http://www.last.fm/join/</a> to get an account.")<br>
+ );<br>
+ return;<br>
+<br>
+ case VLC_SUCCESS:<br>
+ msg_Dbg(p_this, "Handshake successfull :)");<br>
+ b_handshaked = true;<br>
+ i_interval = 0;<br>
+ next_exchange = mdate();<br>
+ break;<br>
+<br>
+ case VLC_AUDIOSCROBBLER_EFATAL:<br>
+ msg_Warn(p_this, "Exiting...");<br>
+ return;<br>
+<br>
+ case VLC_EGENERIC:<br>
+ default:<br>
+ /* protocol error : we'll try later */<br>
+ HandleInterval(&next_exchange, &i_interval);<br>
+ break;<br>
+ }<br>
+ /* if handshake failed let's restart the loop */<br>
+ if (!b_handshaked)<br>
+ continue;<br>
+ }<br>
+<br>
+ msg_Dbg(p_this, "Going to submit some data...");<br>
+<br>
+ switch (Scrobble(p_this))<br>
+ {<br>
+ case VLC_SUCCESS:<br>
+ /* submission successful */<br>
+ for (int i = 0; i < p_sys->i_songs; i++)<br>
+ DeleteSong(&p_sys->p_queue[i]);<br>
+ p_sys->i_songs = 0;<br>
+ i_interval = 0;<br>
+ next_exchange = mdate();<br>
+ msg_Dbg(p_this, "Submission successful!");<br>
+ break;<br>
+ case VLC_EGENERIC:<br>
+ /* protocol error : we'll try later */<br>
+ HandleInterval(&next_exchange, &i_interval);<br>
+ b_handshaked = false;<br>
+ break;<br>
+ case VLC_ENOMEM:<br>
+ default:<br>
+ return;<br>
+ break;<br>
+ }<br>
+ }<br>
+ vlc_restorecancel(canc);<br>
+}<br>
+<br>
+/*****************************************************************************<br>
* Run : call Handshake() then submit songs<br>
*****************************************************************************/<br>
static void Run(intf_thread_t *p_intf)<br>
--<br>
1.7.9.3<br>
<br>
</div></div></blockquote></div><br><br clear="all"><br>-- <br><div>Best regards,</div>Samuel Pitoiset.<br><br>