Mercurial > audlegacy-plugins
changeset 344:03c1ae10bc8d trunk
[svn] - Merge audacious-scrobbler III, new features include:
+ Gerpok support
+ Better queue management
author | nenolod |
---|---|
date | Fri, 08 Dec 2006 19:31:43 -0800 |
parents | 5d3f4b156197 |
children | 213ccf5b5ea5 |
files | ChangeLog src/scrobbler/Makefile src/scrobbler/config.h src/scrobbler/configure.c src/scrobbler/gerpok.c src/scrobbler/gerpok.h src/scrobbler/gtkstuff.c src/scrobbler/queue.c src/scrobbler/queue.h src/scrobbler/scrobbler.c src/scrobbler/settings.h src/scrobbler/xmms_scrobbler.c |
diffstat | 12 files changed, 1288 insertions(+), 227 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog Fri Dec 08 17:52:54 2006 -0800 +++ b/ChangeLog Fri Dec 08 19:31:43 2006 -0800 @@ -1,3 +1,11 @@ +2006-12-09 01:52:54 +0000 William Pitcock <nenolod@nenolod.net> + revision [750] + - mute the soundcard if volume is 0. + + trunk/src/alsa/audio.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + + 2006-12-08 11:27:31 +0000 William Pitcock <nenolod@nenolod.net> revision [748] - port from fmemopen() to vfs_buffer_new_from_string().
--- a/src/scrobbler/Makefile Fri Dec 08 17:52:54 2006 -0800 +++ b/src/scrobbler/Makefile Fri Dec 08 19:31:43 2006 -0800 @@ -19,8 +19,8 @@ configure.c \ gtkstuff.c \ md5.c \ - queue.c \ scrobbler.c \ + gerpok.c \ xmms_scrobbler.c CFLAGS += $(PICFLAGS) $(GTK_CFLAGS) $(BEEP_DEFINES) $(CURL_CFLAGS) -I../../intl -I../..
--- a/src/scrobbler/config.h Fri Dec 08 17:52:54 2006 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -#include "../../config.h" - -#ifndef __SCROBBLER_CONFIG_H__ -#define __SCROBBLER_CONFIG_H__ - -#define DEBUG 0 -#define META_DEBUG 0 -#define SUB_DEBUG 0 -#define CLIENT "Audacious" -#define USER_AGENT "AudioScrobbler/1.1" PACKAGE_NAME "/" PACKAGE_VERSION -#define MAKE_BMP -#define ALLOW_MULTIPLE - -#endif
--- a/src/scrobbler/configure.c Fri Dec 08 17:52:54 2006 -0800 +++ b/src/scrobbler/configure.c Fri Dec 08 19:31:43 2006 -0800 @@ -1,3 +1,5 @@ +#include "settings.h" + #ifdef HAVE_CONFIG_H # include <config.h> #endif @@ -21,7 +23,7 @@ #include "configure.h" -GtkWidget *entry1, *entry2, *cfgdlg; +GtkWidget *entry1, *entry2, *ge_entry1, *ge_entry2, *cfgdlg; static char *hexify(char *pass, int len) { @@ -46,13 +48,16 @@ const char *uid = gtk_entry_get_text(GTK_ENTRY(entry1)); const char *pwd = gtk_entry_get_text(GTK_ENTRY(entry2)); + const char *ge_uid = gtk_entry_get_text(GTK_ENTRY(entry1)); + const char *ge_pwd = gtk_entry_get_text(GTK_ENTRY(entry2)); if ((cfgfile = bmp_cfg_db_open())) { md5_state_t md5state; - unsigned char md5pword[16]; + unsigned char md5pword[16], ge_md5pword[16]; bmp_cfg_db_set_string(cfgfile, "audioscrobbler", "username", (char *)uid); + bmp_cfg_db_set_string(cfgfile, "audioscrobbler", "ge_username", (char *)ge_uid); if (pwd != NULL && pwd[0] != '\0') { @@ -62,6 +67,16 @@ bmp_cfg_db_set_string(cfgfile, "audioscrobbler", "password", hexify((char*)md5pword, sizeof(md5pword))); } + + if (ge_pwd != NULL && ge_pwd[0] != '\0') + { + md5_init(&md5state); + md5_append(&md5state, (unsigned const char *)ge_pwd, strlen(ge_pwd)); + md5_finish(&md5state, ge_md5pword); + bmp_cfg_db_set_string(cfgfile, "audioscrobbler", "ge_password", + hexify((char*)ge_md5pword, sizeof(ge_md5pword))); + } + bmp_cfg_db_close(cfgfile); } } @@ -78,16 +93,20 @@ GtkWidget *label2; GtkWidget *himage1; GtkWidget *align1; + GtkWidget *notebook1; vbox2 = gtk_vbox_new (FALSE, 0); - label1 = gtk_label_new (_("<b>Scrobbler Preferences</b>")); + label1 = gtk_label_new (_("<b>Services</b>")); gtk_widget_show (label1); gtk_label_set_use_markup (GTK_LABEL (label1), TRUE); gtk_misc_set_alignment (GTK_MISC (label1), 0, 0.5); gtk_box_pack_start (GTK_BOX (vbox2), label1, FALSE, FALSE, 0); + notebook1 = gtk_notebook_new(); + gtk_widget_show (notebook1); + align1 = gtk_alignment_new(0, 0, 0, 0); gtk_widget_show (align1); gtk_alignment_set_padding(GTK_ALIGNMENT(align1), 0, 0, 12, 0); @@ -95,7 +114,6 @@ table1 = gtk_table_new (2, 2, FALSE); gtk_widget_show (table1); gtk_container_add(GTK_CONTAINER(align1), table1); - gtk_box_pack_start (GTK_BOX (vbox2), align1, TRUE, TRUE, 0); gtk_table_set_row_spacings (GTK_TABLE(table1), 6); gtk_table_set_col_spacings (GTK_TABLE(table1), 6); @@ -123,6 +141,50 @@ gtk_table_attach_defaults (GTK_TABLE (table1), entry2, 1, 2, 3, 4); g_signal_connect(entry2, "changed", (GCallback) saveconfig, NULL); + label1 = gtk_label_new (_("<b>Last.FM</b>")); + gtk_label_set_use_markup (GTK_LABEL (label1), TRUE); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook1), GTK_WIDGET(align1), label1); + + align1 = gtk_alignment_new(0, 0, 0, 0); + gtk_widget_show (align1); + gtk_alignment_set_padding(GTK_ALIGNMENT(align1), 0, 0, 12, 0); + + table1 = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table1); + gtk_container_add(GTK_CONTAINER(align1), table1); + gtk_table_set_row_spacings (GTK_TABLE(table1), 6); + gtk_table_set_col_spacings (GTK_TABLE(table1), 6); + + label2 = gtk_label_new (_("Username:")); + gtk_widget_show (label2); + gtk_table_attach_defaults (GTK_TABLE (table1), label2, 0, 1, 2, 3); + gtk_label_set_justify (GTK_LABEL (label2), GTK_JUSTIFY_RIGHT); + gtk_misc_set_alignment (GTK_MISC (label2), 1, 0.5); + + label3 = gtk_label_new (_("Password:")); + gtk_widget_show (label3); + gtk_table_attach (GTK_TABLE (table1), label3, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_justify (GTK_LABEL (label3), GTK_JUSTIFY_RIGHT); + gtk_misc_set_alignment (GTK_MISC (label3), 1, 0.5); + + ge_entry1 = gtk_entry_new (); + gtk_widget_show (ge_entry1); + gtk_table_attach_defaults (GTK_TABLE (table1), ge_entry1, 1, 2, 2, 3); + + ge_entry2 = gtk_entry_new (); + gtk_entry_set_visibility(GTK_ENTRY(ge_entry2), FALSE); + gtk_widget_show (ge_entry2); + gtk_table_attach_defaults (GTK_TABLE (table1), ge_entry2, 1, 2, 3, 4); + g_signal_connect(ge_entry2, "changed", (GCallback) saveconfig, NULL); + + label1 = gtk_label_new (_("<b>Gerpok</b>")); + gtk_label_set_use_markup (GTK_LABEL (label1), TRUE); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook1), GTK_WIDGET(align1), label1); + + gtk_box_pack_start (GTK_BOX (vbox2), notebook1, TRUE, TRUE, 6); + himage1 = gtk_image_new_from_file (DATA_DIR "/images/audioscrobbler_badge.png"); gtk_widget_show (himage1); gtk_box_pack_start (GTK_BOX (vbox2), himage1, FALSE, FALSE, 0); @@ -139,6 +201,12 @@ gtk_entry_set_text(GTK_ENTRY(entry1), username); g_free(username); } + bmp_cfg_db_get_string(db, "audioscrobbler", "ge_username", + &username); + if (username) { + gtk_entry_set_text(GTK_ENTRY(ge_entry1), username); + g_free(username); + } bmp_cfg_db_close(db); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/scrobbler/gerpok.c Fri Dec 08 19:31:43 2006 -0800 @@ -0,0 +1,936 @@ +#include "settings.h" + +#include <pthread.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <curl/curl.h> +#include <stdio.h> +#include "fmt.h" +#include "md5.h" +#include "scrobbler.h" +#include "config.h" +#include <glib.h> + +#include <audacious/titlestring.h> + +#define SCROBBLER_HS_URL "http://post.gerpok.com" +#define SCROBBLER_CLI_ID "aud" +#define SCROBBLER_HS_WAIT 1800 +#define SCROBBLER_SB_WAIT 10 +#define SCROBBLER_VERSION "1.1" +#define SCROBBLER_IMPLEMENTATION "0.1" /* This is the implementation, not the player version. */ +#define SCROBBLER_SB_MAXLEN 1024 +#define CACHE_SIZE 1024 + +/* Scrobblerbackend for xmms plugin, first draft */ + +static int gerpok_sc_hs_status, + gerpok_sc_hs_timeout, + gerpok_sc_hs_errors, + gerpok_sc_sb_errors, + gerpok_sc_bad_users, + gerpok_sc_submit_interval, + gerpok_sc_submit_timeout, + gerpok_sc_srv_res_size, + gerpok_sc_giveup, + gerpok_sc_major_error_present; + +static char *gerpok_sc_submit_url, + *gerpok_sc_username, + *gerpok_sc_password, + *gerpok_sc_challenge_hash, + gerpok_sc_response_hash[33], + *gerpok_sc_srv_res, + gerpok_sc_curl_errbuf[CURL_ERROR_SIZE], + *gerpok_sc_major_error; + +static void dump_queue(); + +/**** Queue stuff ****/ + +#define I_ARTIST(i) i->artist +#define I_TITLE(i) i->title +#define I_TIME(i) i->utctime +#define I_LEN(i) i->len +#define I_MB(i) i->mb +#define I_ALBUM(i) i->album + +typedef struct { + char *artist, + *title, + *mb, + *album, + *utctime, + len[16]; + int numtries; + void *next; +} item_t; + +static item_t *q_queue = NULL; +static item_t *q_queue_last = NULL; +static int q_nitems; + +static void q_item_free(item_t *item) +{ + if (item == NULL) + return; + curl_free(item->artist); + curl_free(item->title); + curl_free(item->utctime); + curl_free(item->mb); + curl_free(item->album); + free(item); +} + +static void q_put(TitleInput *tuple, int len) +{ + item_t *item; + + item = malloc(sizeof(item_t)); + + item->artist = fmt_escape(tuple->performer); + item->title = fmt_escape(tuple->track_name); + item->utctime = fmt_escape(fmt_timestr(time(NULL), 1)); + snprintf(item->len, sizeof(item->len), "%d", len); + +#ifdef NOTYET + if(tuple->mb == NULL) +#endif + item->mb = fmt_escape(""); +#ifdef NOTYET + else + item->mb = fmt_escape((char*)tuple->mb); +#endif + + if(tuple->album_name == NULL) + item->album = fmt_escape(""); + else + item->album = fmt_escape((char*)tuple->album_name); + + q_nitems++; + + item->next = NULL; + + if(q_queue_last == NULL) + q_queue = q_queue_last = item; + else + { + q_queue_last->next = item; + q_queue_last = item; + } +} + +static item_t *q_put2(char *artist, char *title, char *len, char *time, + char *album, char *mb) +{ + char *temp = NULL; + item_t *item; + + item = calloc(1, sizeof(item_t)); + temp = fmt_unescape(artist); + item->artist = fmt_escape(temp); + curl_free(temp); + temp = fmt_unescape(title); + item->title = fmt_escape(temp); + curl_free(temp); + memcpy(item->len, len, sizeof(len)); + temp = fmt_unescape(time); + item->utctime = fmt_escape(temp); + curl_free(temp); + temp = fmt_unescape(album); + item->album = fmt_escape(temp); + curl_free(temp); + temp = fmt_unescape(mb); + item->mb = fmt_escape(temp); + curl_free(temp); + + q_nitems++; + + item->next = NULL; + if(q_queue_last == NULL) + q_queue = q_queue_last = item; + else + { + q_queue_last->next = item; + q_queue_last = item; + } + + return item; +} + +static item_t *q_peek(void) +{ + if (q_nitems == 0) + return NULL; + return q_queue; +} + +static item_t *q_peekall(int rewind) +{ + static item_t *citem = NULL; + item_t *temp_item; + + if (rewind) { + citem = q_queue; + return NULL; + } + + temp_item = citem; + + if(citem != NULL) + citem = citem->next; + + return temp_item; +} + +static int q_get(void) +{ + item_t *item; + + if (q_nitems == 0) + return 0; + + item = q_queue; + + if(item == NULL) + return 0; + + q_nitems--; + q_queue = q_queue->next; + + q_item_free(item); + + if (q_nitems == 0) + { + q_queue_last = NULL; + return 0; + } + + return -1; +} + +static void q_free(void) +{ + while (q_get()); +} + +static int q_len(void) +{ + return q_nitems; +} + +/* Error functions */ + +static void gerpok_sc_throw_error(char *errortxt) +{ + gerpok_sc_major_error_present = 1; + if(gerpok_sc_major_error == NULL) + gerpok_sc_major_error = strdup(errortxt); + + return; +} + +int gerpok_sc_catch_error(void) +{ + return gerpok_sc_major_error_present; +} + +char *gerpok_sc_fetch_error(void) +{ + return gerpok_sc_major_error; +} + +void gerpok_sc_clear_error(void) +{ + gerpok_sc_major_error_present = 0; + if(gerpok_sc_major_error != NULL) + free(gerpok_sc_major_error); + gerpok_sc_major_error = NULL; + + return; +} + +static size_t gerpok_sc_store_res(void *ptr, size_t size, + size_t nmemb, + void *stream __attribute__((unused))) +{ + int len = size * nmemb; + + gerpok_sc_srv_res = realloc(gerpok_sc_srv_res, gerpok_sc_srv_res_size + len + 1); + memcpy(gerpok_sc_srv_res + gerpok_sc_srv_res_size, + ptr, len); + gerpok_sc_srv_res_size += len; + return len; +} + +static void gerpok_sc_free_res(void) +{ + if(gerpok_sc_srv_res != NULL) + free(gerpok_sc_srv_res); + gerpok_sc_srv_res = NULL; + gerpok_sc_srv_res_size = 0; +} + +static int gerpok_sc_parse_hs_res(void) +{ + char *interval; + + if (!gerpok_sc_srv_res_size) { + pdebug("No reply from server", DEBUG); + return -1; + } + *(gerpok_sc_srv_res + gerpok_sc_srv_res_size) = 0; + + if (!strncmp(gerpok_sc_srv_res, "FAILED ", 7)) { + interval = strstr(gerpok_sc_srv_res, "INTERVAL"); + if(!interval) { + pdebug("missing INTERVAL", DEBUG); + } + else + { + *(interval - 1) = 0; + gerpok_sc_submit_interval = strtol(interval + 8, NULL, 10); + } + + /* Throwing a major error, just in case */ + /* gerpok_sc_throw_error(fmt_vastr("%s", gerpok_sc_srv_res)); + gerpok_sc_hs_errors++; */ + pdebug(fmt_vastr("error: %s", gerpok_sc_srv_res), DEBUG); + + return -1; + } + + if (!strncmp(gerpok_sc_srv_res, "UPDATE ", 7)) { + interval = strstr(gerpok_sc_srv_res, "INTERVAL"); + if(!interval) + { + pdebug("missing INTERVAL", DEBUG); + } + else + { + *(interval - 1) = 0; + gerpok_sc_submit_interval = strtol(interval + 8, NULL, 10); + } + + gerpok_sc_submit_url = strchr(strchr(gerpok_sc_srv_res, '\n') + 1, '\n') + 1; + *(gerpok_sc_submit_url - 1) = 0; + gerpok_sc_submit_url = strdup(gerpok_sc_submit_url); + gerpok_sc_challenge_hash = strchr(gerpok_sc_srv_res, '\n') + 1; + *(gerpok_sc_challenge_hash - 1) = 0; + gerpok_sc_challenge_hash = strdup(gerpok_sc_challenge_hash); + + /* Throwing major error. Need to alert client to update. */ + gerpok_sc_throw_error(fmt_vastr("Please update Audacious.\n" + "Update available at: http://audacious-media-player.org")); + pdebug(fmt_vastr("update client: %s", gerpok_sc_srv_res + 7), DEBUG); + + /* + * Russ isn't clear on whether we can submit with a not-updated + * client. Neither is RJ. I use what we did before. + */ + gerpok_sc_giveup = -1; + return -1; + } + if (!strncmp(gerpok_sc_srv_res, "UPTODATE\n", 9)) { + gerpok_sc_bad_users = 0; + + interval = strstr(gerpok_sc_srv_res, "INTERVAL"); + if (!interval) { + pdebug("missing INTERVAL", DEBUG); + /* + * This is probably a bad thing, but Russ seems to + * think its OK to assume that an UPTODATE response + * may not have an INTERVAL... We return -1 anyway. + */ + return -1; + } + else + { + *(interval - 1) = 0; + gerpok_sc_submit_interval = strtol(interval + 8, NULL, 10); + } + + gerpok_sc_submit_url = strchr(strchr(gerpok_sc_srv_res, '\n') + 1, '\n') + 1; + *(gerpok_sc_submit_url - 1) = 0; + gerpok_sc_submit_url = strdup(gerpok_sc_submit_url); + gerpok_sc_challenge_hash = strchr(gerpok_sc_srv_res, '\n') + 1; + *(gerpok_sc_challenge_hash - 1) = 0; + gerpok_sc_challenge_hash = strdup(gerpok_sc_challenge_hash); + + return 0; + } + if(!strncmp(gerpok_sc_srv_res, "BADUSER", 7)) { + /* Throwing major error. */ + gerpok_sc_throw_error("Incorrect username/password.\n" + "Please fix in configuration."); + pdebug("incorrect username/password", DEBUG); + + interval = strstr(gerpok_sc_srv_res, "INTERVAL"); + if(!interval) + { + pdebug("missing INTERVAL", DEBUG); + } + else + { + *(interval - 1) = 0; + gerpok_sc_submit_interval = strtol(interval + 8, NULL, 10); + } + + return -1; + } + + pdebug(fmt_vastr("unknown server-reply '%s'", gerpok_sc_srv_res), DEBUG); + return -1; +} + +static void hexify(char *pass, int len) +{ + char *bp = gerpok_sc_response_hash; + char hexchars[] = "0123456789abcdef"; + int i; + + memset(gerpok_sc_response_hash, 0, sizeof(gerpok_sc_response_hash)); + + for(i = 0; i < len; i++) { + *(bp++) = hexchars[(pass[i] >> 4) & 0x0f]; + *(bp++) = hexchars[pass[i] & 0x0f]; + } + *bp = 0; + + return; +} + +static int gerpok_sc_handshake(void) +{ + int status; + char buf[4096]; + CURL *curl; + + snprintf(buf, sizeof(buf), "%s/?hs=true&p=%s&c=%s&v=%s&u=%s", + SCROBBLER_HS_URL, SCROBBLER_VERSION, + SCROBBLER_CLI_ID, SCROBBLER_IMPLEMENTATION, gerpok_sc_username); + + curl = curl_easy_init(); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); + curl_easy_setopt(curl, CURLOPT_URL, buf); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, + gerpok_sc_store_res); + memset(gerpok_sc_curl_errbuf, 0, sizeof(gerpok_sc_curl_errbuf)); + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, gerpok_sc_curl_errbuf); + curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + status = curl_easy_perform(curl); + curl_easy_cleanup(curl); + + gerpok_sc_hs_timeout = time(NULL) + SCROBBLER_HS_WAIT; + + if (status) { + pdebug(gerpok_sc_curl_errbuf, DEBUG); + gerpok_sc_hs_errors++; + gerpok_sc_free_res(); + return -1; + } + + if (gerpok_sc_parse_hs_res()) { + gerpok_sc_hs_errors++; + gerpok_sc_free_res(); + return -1; + } + + if (gerpok_sc_challenge_hash != NULL) { + md5_state_t md5state; + unsigned char md5pword[16]; + + md5_init(&md5state); + /*pdebug(fmt_vastr("Pass Hash: %s", gerpok_sc_password), DEBUG);*/ + md5_append(&md5state, (unsigned const char *)gerpok_sc_password, + strlen(gerpok_sc_password)); + /*pdebug(fmt_vastr("Challenge Hash: %s", gerpok_sc_challenge_hash), DEBUG);*/ + md5_append(&md5state, (unsigned const char *)gerpok_sc_challenge_hash, + strlen(gerpok_sc_challenge_hash)); + md5_finish(&md5state, md5pword); + hexify((char*)md5pword, sizeof(md5pword)); + /*pdebug(fmt_vastr("Response Hash: %s", gerpok_sc_response_hash), DEBUG);*/ + } + + gerpok_sc_hs_errors = 0; + gerpok_sc_hs_status = 1; + + gerpok_sc_free_res(); + + pdebug(fmt_vastr("submiturl: %s - interval: %d", + gerpok_sc_submit_url, gerpok_sc_submit_interval), DEBUG); + + return 0; +} + +static int gerpok_sc_parse_sb_res(void) +{ + char *ch, *ch2; + + if (!gerpok_sc_srv_res_size) { + pdebug("No response from server", DEBUG); + return -1; + } + *(gerpok_sc_srv_res + gerpok_sc_srv_res_size) = 0; + + if (!strncmp(gerpok_sc_srv_res, "OK", 2)) { + if ((ch = strstr(gerpok_sc_srv_res, "INTERVAL"))) { + gerpok_sc_submit_interval = strtol(ch + 8, NULL, 10); + pdebug(fmt_vastr("got new interval: %d", + gerpok_sc_submit_interval), DEBUG); + } + + pdebug(fmt_vastr("submission ok: %s", gerpok_sc_srv_res), DEBUG); + + return 0; + } + + if (!strncmp(gerpok_sc_srv_res, "BADAUTH", 7)) { + if ((ch = strstr(gerpok_sc_srv_res, "INTERVAL"))) { + gerpok_sc_submit_interval = strtol(ch + 8, NULL, 10); + pdebug(fmt_vastr("got new interval: %d", + gerpok_sc_submit_interval), DEBUG); + } + + pdebug("incorrect username/password", DEBUG); + + gerpok_sc_giveup = 0; + + /* + * We obviously aren't authenticated. The server might have + * lost our handshake status though, so let's try + * re-handshaking... This might not be proper. + * (we don't give up) + */ + gerpok_sc_hs_status = 0; + + if(gerpok_sc_challenge_hash != NULL) + free(gerpok_sc_challenge_hash); + if(gerpok_sc_submit_url != NULL) + free(gerpok_sc_submit_url); + + gerpok_sc_challenge_hash = gerpok_sc_submit_url = NULL; + gerpok_sc_bad_users++; + + if(gerpok_sc_bad_users > 2) + { + pdebug("3 BADAUTH returns on submission. Halting " + "submissions until login fixed.", DEBUG) + gerpok_sc_throw_error("Incorrect username/password.\n" + "Please fix in configuration."); + } + + return -1; + } + + if (!strncmp(gerpok_sc_srv_res, "FAILED", 6)) { + if ((ch = strstr(gerpok_sc_srv_res, "INTERVAL"))) { + gerpok_sc_submit_interval = strtol(ch + 8, NULL, 10); + pdebug(fmt_vastr("got new interval: %d", + gerpok_sc_submit_interval), DEBUG); + } + + /* This could be important. (Such as FAILED - Get new plugin) */ + /*gerpok_sc_throw_error(fmt_vastr("%s", gerpok_sc_srv_res));*/ + + pdebug(gerpok_sc_srv_res, DEBUG); + + return -1; + } + + if (!strncmp(gerpok_sc_srv_res, "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">", 50)) { + ch = strstr(gerpok_sc_srv_res, "<TITLE>") + 7; + ch2 = strstr(gerpok_sc_srv_res, "</TITLE>"); + *ch2 = '\0'; + + pdebug(fmt_vastr("HTTP Error (%d): '%s'", + atoi(ch), ch + 4), DEBUG); + *ch2 = '<'; + + return -1; + } + + pdebug(fmt_vastr("unknown server-reply %s", gerpok_sc_srv_res), DEBUG); + + return -1; +} + +static gchar *gerpok_sc_itemtag(char c, int n, char *str) +{ + static char buf[SCROBBLER_SB_MAXLEN]; + snprintf(buf, SCROBBLER_SB_MAXLEN, "&%c[%d]=%s", c, n, str); + return buf; +} + +#define cfa(f, l, n, v) \ +curl_formadd(f, l, CURLFORM_COPYNAME, n, \ + CURLFORM_PTRCONTENTS, v, CURLFORM_END) + +static int gerpok_sc_generateentry(GString *submission) +{ + int i; + item_t *item; + + i = 0; +#ifdef ALLOW_MULTIPLE + q_peekall(1); + while ((item = q_peekall(0)) && i < 10) { +#else + item = q_peek(); +#endif + if (!item) + return i; + + g_string_append(submission,gerpok_sc_itemtag('a',i,I_ARTIST(item))); + g_string_append(submission,gerpok_sc_itemtag('t',i,I_TITLE(item))); + g_string_append(submission,gerpok_sc_itemtag('l',i,I_LEN(item))); + g_string_append(submission,gerpok_sc_itemtag('i',i,I_TIME(item))); + g_string_append(submission,gerpok_sc_itemtag('m',i,I_MB(item))); + g_string_append(submission,gerpok_sc_itemtag('b',i,I_ALBUM(item))); + + pdebug(fmt_vastr("a[%d]=%s t[%d]=%s l[%d]=%s i[%d]=%s m[%d]=%s b[%d]=%s", + i, I_ARTIST(item), + i, I_TITLE(item), + i, I_LEN(item), + i, I_TIME(item), + i, I_MB(item), + i, I_ALBUM(item)), DEBUG); +#ifdef ALLOW_MULTIPLE + i++; + } +#endif + + return i; +} + +static int gerpok_sc_submitentry(gchar *entry) +{ + CURL *curl; + /* struct HttpPost *post = NULL , *last = NULL; */ + int status; + GString *submission; + + curl = curl_easy_init(); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); + curl_easy_setopt(curl, CURLOPT_URL, gerpok_sc_submit_url); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, + gerpok_sc_store_res); + curl_easy_setopt(curl, CURLOPT_USERAGENT, USER_AGENT); + curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + /*cfa(&post, &last, "debug", "failed");*/ + + /*pdebug(fmt_vastr("Username: %s", gerpok_sc_username), DEBUG);*/ + submission = g_string_new("u="); + g_string_append(submission,(gchar *)gerpok_sc_username); + + /*pdebug(fmt_vastr("Response Hash: %s", gerpok_sc_response_hash), DEBUG);*/ + g_string_append(submission,"&s="); + g_string_append(submission,(gchar *)gerpok_sc_response_hash); + + g_string_append(submission, entry); + + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, (char *)submission->str); + memset(gerpok_sc_curl_errbuf, 0, sizeof(gerpok_sc_curl_errbuf)); + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, gerpok_sc_curl_errbuf); + + /* + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, SCROBBLER_SB_WAIT); + */ + + status = curl_easy_perform(curl); + + curl_easy_cleanup(curl); + + g_string_free(submission,TRUE); + + if (status) { + pdebug(gerpok_sc_curl_errbuf, DEBUG); + gerpok_sc_sb_errors++; + gerpok_sc_free_res(); + return -1; + } + + if (gerpok_sc_parse_sb_res()) { + gerpok_sc_sb_errors++; + gerpok_sc_free_res(); + pdebug(fmt_vastr("Retrying in %d secs, %d elements in queue", + gerpok_sc_submit_interval, q_len()), DEBUG); + return -1; + } + gerpok_sc_free_res(); + return 0; +} + +static void gerpok_sc_handlequeue(GMutex *mutex) +{ + GString *submitentry; + int nsubmit; + int wait; + + if(gerpok_sc_submit_timeout < time(NULL) && gerpok_sc_bad_users < 3) + { + submitentry = g_string_new(""); + + g_mutex_lock(mutex); + + nsubmit = gerpok_sc_generateentry(submitentry); + + g_mutex_unlock(mutex); + + if (nsubmit > 0) + { + pdebug(fmt_vastr("Number submitting: %d", nsubmit), DEBUG); + pdebug(fmt_vastr("Submission: %s", submitentry->str), DEBUG); + + if(!gerpok_sc_submitentry(submitentry->str)) + { + g_mutex_lock(mutex); + +#ifdef ALLOW_MULTIPLE + q_free(); +#else + q_get(); +#endif + /* + * This should make sure that the queue doesn't + * get submitted multiple times on a nasty + * segfault... + */ + dump_queue(); + + g_mutex_unlock(mutex); + + gerpok_sc_sb_errors = 0; + } + if(gerpok_sc_sb_errors) + { + if(gerpok_sc_sb_errors < 5) + /* Retry after 1 min */ + wait = 60; + else + wait = /* gerpok_sc_submit_interval + */ + ( ((gerpok_sc_sb_errors - 5) < 7) ? + (60 << (gerpok_sc_sb_errors-5)) : + 7200 ); + + gerpok_sc_submit_timeout = time(NULL) + wait; + + pdebug(fmt_vastr("Error while submitting. " + "Retrying after %d seconds.", wait), + DEBUG); + } + } + + g_string_free(submitentry, TRUE); + } +} + +static void read_cache(void) +{ + FILE *fd; + char buf[PATH_MAX], *cache = NULL, *ptr1, *ptr2; + int cachesize, written, i = 0; + item_t *item; + + cachesize = written = 0; + + snprintf(buf, sizeof(buf), "%s/.audacious/gerpokqueue.txt", g_get_home_dir()); + + if (!(fd = fopen(buf, "r"))) + return; + pdebug(fmt_vastr("Opening %s", buf), DEBUG); + while(!feof(fd)) + { + cachesize += CACHE_SIZE; + cache = realloc(cache, cachesize + 1); + written += fread(cache + written, 1, CACHE_SIZE, fd); + cache[written] = '\0'; + } + fclose(fd); + ptr1 = cache; + while(ptr1 < cache + written - 1) + { + char *artist, *title, *len, *time, *album, *mb; + + pdebug("Pushed:", DEBUG); + ptr2 = strchr(ptr1, ' '); + artist = calloc(1, ptr2 - ptr1 + 1); + strncpy(artist, ptr1, ptr2 - ptr1); + ptr1 = ptr2 + 1; + ptr2 = strchr(ptr1, ' '); + title = calloc(1, ptr2 - ptr1 + 1); + strncpy(title, ptr1, ptr2 - ptr1); + ptr1 = ptr2 + 1; + ptr2 = strchr(ptr1, ' '); + len = calloc(1, ptr2 - ptr1 + 1); + strncpy(len, ptr1, ptr2 - ptr1); + ptr1 = ptr2 + 1; + ptr2 = strchr(ptr1, ' '); + time = calloc(1, ptr2 - ptr1 + 1); + strncpy(time, ptr1, ptr2 - ptr1); + ptr1 = ptr2 + 1; + ptr2 = strchr(ptr1, ' '); + album = calloc(1, ptr2 - ptr1 + 1); + strncpy(album, ptr1, ptr2 - ptr1); + ptr1 = ptr2 + 1; + ptr2 = strchr(ptr1, '\n'); + if(ptr2 != NULL) + *ptr2 = '\0'; + mb = calloc(1, strlen(ptr1) + 1); + strncpy(mb, ptr1, strlen(ptr1)); + if(ptr2 != NULL) + *ptr2 = '\n'; + /* Why is our save printing out CR/LF? */ + ptr1 = ptr2 + 1; + + item = q_put2(artist, title, len, time, album, mb); + pdebug(fmt_vastr("a[%d]=%s t[%d]=%s l[%d]=%s i[%d]=%s m[%d]=%s b[%d]=%s", + i, I_ARTIST(item), + i, I_TITLE(item), + i, I_LEN(item), + i, I_TIME(item), + i, I_MB(item), + i, I_ALBUM(item)), DEBUG); + free(artist); + free(title); + free(len); + free(time); + free(album); + free(mb); + + i++; + } + pdebug("Done loading cache.", DEBUG); + free(cache); +} + +static void dump_queue(void) +{ + FILE *fd; + item_t *item; + char *home, buf[PATH_MAX]; + + /*pdebug("Entering dump_queue();", DEBUG);*/ + + if (!(home = getenv("HOME"))) + { + pdebug("No HOME directory found. Cannot dump queue.", DEBUG); + return; + } + + snprintf(buf, sizeof(buf), "%s/.audacious/gerpokqueue.txt", home); + + if (!(fd = fopen(buf, "w"))) + { + pdebug(fmt_vastr("Failure opening %s", buf), DEBUG); + return; + } + + pdebug(fmt_vastr("Opening %s", buf), DEBUG); + + q_peekall(1); + + while ((item = q_peekall(0))) { + fprintf(fd, "%s %s %s %s %s %s\n", + I_ARTIST(item), + I_TITLE(item), + I_LEN(item), + I_TIME(item), + I_ALBUM(item), + I_MB(item)); + } + + fclose(fd); +} + +/* This was made public */ + +void gerpok_sc_cleaner(void) +{ + if(gerpok_sc_submit_url != NULL) + free(gerpok_sc_submit_url); + if(gerpok_sc_username != NULL) + free(gerpok_sc_username); + if(gerpok_sc_password != NULL) + free(gerpok_sc_password); + if(gerpok_sc_challenge_hash != NULL) + free(gerpok_sc_challenge_hash); + if(gerpok_sc_srv_res != NULL) + free(gerpok_sc_srv_res); + if(gerpok_sc_major_error != NULL) + free(gerpok_sc_major_error); + dump_queue(); + q_free(); + pdebug("scrobbler shutting down", DEBUG); +} + +static void gerpok_sc_checkhandshake(void) +{ + int wait; + + if (gerpok_sc_hs_status) + return; + if (gerpok_sc_hs_timeout < time(NULL)) + { + gerpok_sc_handshake(); + + if(gerpok_sc_hs_errors) + { + if(gerpok_sc_hs_errors < 5) + /* Retry after 60 seconds */ + wait = 60; + else + wait = /* gerpok_sc_submit_interval + */ + ( ((gerpok_sc_hs_errors - 5) < 7) ? + (60 << (gerpok_sc_hs_errors-5)) : + 7200 ); + gerpok_sc_hs_timeout = time(NULL) + wait; + pdebug(fmt_vastr("Error while handshaking. Retrying " + "after %d seconds.", wait), DEBUG); + } + } +} + +/**** Public *****/ + +/* Called at session startup*/ + +void gerpok_sc_init(char *uname, char *pwd) +{ + gerpok_sc_hs_status = gerpok_sc_hs_timeout = gerpok_sc_hs_errors = gerpok_sc_submit_timeout = + gerpok_sc_srv_res_size = gerpok_sc_giveup = gerpok_sc_major_error_present = + gerpok_sc_bad_users = gerpok_sc_sb_errors = 0; + gerpok_sc_submit_interval = 100; + + gerpok_sc_submit_url = gerpok_sc_username = gerpok_sc_password = gerpok_sc_srv_res = + gerpok_sc_challenge_hash = gerpok_sc_major_error = NULL; + gerpok_sc_username = strdup(uname); + gerpok_sc_password = strdup(pwd); + read_cache(); + pdebug("scrobbler starting up", DEBUG); +} + +void gerpok_sc_addentry(GMutex *mutex, TitleInput *tuple, int len) +{ + g_mutex_lock(mutex); + q_put(tuple, len); + /* + * This will help make sure the queue will be saved on a nasty + * segfault... + */ + dump_queue(); + g_mutex_unlock(mutex); +} + +/* Call periodically from the plugin */ +int gerpok_sc_idle(GMutex *mutex) +{ + gerpok_sc_checkhandshake(); + if (gerpok_sc_hs_status) + gerpok_sc_handlequeue(mutex); + + return gerpok_sc_giveup; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/scrobbler/gerpok.h Fri Dec 08 19:31:43 2006 -0800 @@ -0,0 +1,13 @@ +#ifndef G_NET_H +#define G_NET_H 1 + +#include "audacious/titlestring.h" + +int gerpok_sc_idle(GMutex *); +void gerpok_sc_init(char *, char *); +void gerpok_sc_addentry(GMutex *, TitleInput *, int); +void gerpok_sc_cleaner(void); +int gerpok_sc_catch_error(void); +char *gerpok_sc_fetch_error(void); +void gerpok_sc_clear_error(void); +#endif
--- a/src/scrobbler/gtkstuff.c Fri Dec 08 17:52:54 2006 -0800 +++ b/src/scrobbler/gtkstuff.c Fri Dec 08 19:31:43 2006 -0800 @@ -6,6 +6,7 @@ #include <stdio.h> #include <string.h> +#include "settings.h" #include "config.h" #include "md5.h"
--- a/src/scrobbler/queue.c Fri Dec 08 17:52:54 2006 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,159 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <curl/curl.h> -#include "queue.h" -#include "fmt.h" - -static item_t *q_queue = NULL; -static item_t *q_queue_last = NULL; -static int q_nitems; - -static void q_item_free(item_t *item) -{ - if (item == NULL) - return; - curl_free(item->artist); - curl_free(item->title); - curl_free(item->utctime); - curl_free(item->mb); - curl_free(item->album); - free(item); -} - -void q_put(TitleInput *tuple, int len) -{ - item_t *item; - - item = malloc(sizeof(item_t)); - - item->artist = fmt_escape(tuple->performer); - item->title = fmt_escape(tuple->track_name); - item->utctime = fmt_escape(fmt_timestr(time(NULL), 1)); - snprintf(item->len, sizeof(item->len), "%d", len); - -#ifdef NOTYET - if(tuple->mb == NULL) -#endif - item->mb = fmt_escape(""); -#ifdef NOTYET - else - item->mb = fmt_escape((char*)tuple->mb); -#endif - - if(tuple->album_name == NULL) - item->album = fmt_escape(""); - else - item->album = fmt_escape((char*)tuple->album_name); - - q_nitems++; - - item->next = NULL; - - if(q_queue_last == NULL) - q_queue = q_queue_last = item; - else - { - q_queue_last->next = item; - q_queue_last = item; - } -} - -item_t *q_put2(char *artist, char *title, char *len, char *time, - char *album, char *mb) -{ - char *temp = NULL; - item_t *item; - - item = calloc(1, sizeof(item_t)); - temp = fmt_unescape(artist); - item->artist = fmt_escape(temp); - curl_free(temp); - temp = fmt_unescape(title); - item->title = fmt_escape(temp); - curl_free(temp); - memcpy(item->len, len, sizeof(len)); - temp = fmt_unescape(time); - item->utctime = fmt_escape(temp); - curl_free(temp); - temp = fmt_unescape(album); - item->album = fmt_escape(temp); - curl_free(temp); - temp = fmt_unescape(mb); - item->mb = fmt_escape(temp); - curl_free(temp); - - q_nitems++; - - item->next = NULL; - if(q_queue_last == NULL) - q_queue = q_queue_last = item; - else - { - q_queue_last->next = item; - q_queue_last = item; - } - - return item; -} - -item_t *q_peek(void) -{ - if (q_nitems == 0) - return NULL; - return q_queue; -} - -item_t *q_peekall(int rewind) -{ - static item_t *citem = NULL; - item_t *temp_item; - - if (rewind) { - citem = q_queue; - return NULL; - } - - temp_item = citem; - - if(citem != NULL) - citem = citem->next; - - return temp_item; -} - -int q_get(void) -{ - item_t *item; - - if (q_nitems == 0) - return 0; - - item = q_queue; - - if(item == NULL) - return 0; - - q_nitems--; - q_queue = q_queue->next; - - q_item_free(item); - - if (q_nitems == 0) - { - q_queue_last = NULL; - return 0; - } - - return -1; -} - -void q_free(void) -{ - while (q_get()); -} - -int q_len(void) -{ - return q_nitems; -}
--- a/src/scrobbler/queue.h Fri Dec 08 17:52:54 2006 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -#ifndef QUEUE_H -#define QUEUE_H 1 - -#include "audacious/titlestring.h" - -#define I_ARTIST(i) i->artist -#define I_TITLE(i) i->title -#define I_TIME(i) i->utctime -#define I_LEN(i) i->len -#define I_MB(i) i->mb -#define I_ALBUM(i) i->album - -typedef struct { - char *artist, - *title, - *mb, - *album, - *utctime, - len[16]; - int numtries; - void *next; -} item_t; -void q_put(TitleInput *, int); -item_t *q_put2(char *, char *, char *, char *, char *, char *); -item_t *q_peek(void); -item_t *q_peekall(int); -int q_get(void); -void q_free(void); -int q_len(void); -#endif
--- a/src/scrobbler/scrobbler.c Fri Dec 08 17:52:54 2006 -0800 +++ b/src/scrobbler/scrobbler.c Fri Dec 08 19:31:43 2006 -0800 @@ -7,11 +7,13 @@ #include <stdio.h> #include "fmt.h" #include "md5.h" -#include "queue.h" #include "scrobbler.h" #include "config.h" +#include "settings.h" #include <glib.h> +#include <audacious/titlestring.h> + #define SCROBBLER_HS_URL "http://post.audioscrobbler.com" #define SCROBBLER_CLI_ID "aud" #define SCROBBLER_HS_WAIT 1800 @@ -45,6 +47,179 @@ static void dump_queue(); +/**** Queue stuff ****/ + +#define I_ARTIST(i) i->artist +#define I_TITLE(i) i->title +#define I_TIME(i) i->utctime +#define I_LEN(i) i->len +#define I_MB(i) i->mb +#define I_ALBUM(i) i->album + +typedef struct { + char *artist, + *title, + *mb, + *album, + *utctime, + len[16]; + int numtries; + void *next; +} item_t; + +static item_t *q_queue = NULL; +static item_t *q_queue_last = NULL; +static int q_nitems; + +static void q_item_free(item_t *item) +{ + if (item == NULL) + return; + curl_free(item->artist); + curl_free(item->title); + curl_free(item->utctime); + curl_free(item->mb); + curl_free(item->album); + free(item); +} + +static void q_put(TitleInput *tuple, int len) +{ + item_t *item; + + item = malloc(sizeof(item_t)); + + item->artist = fmt_escape(tuple->performer); + item->title = fmt_escape(tuple->track_name); + item->utctime = fmt_escape(fmt_timestr(time(NULL), 1)); + snprintf(item->len, sizeof(item->len), "%d", len); + +#ifdef NOTYET + if(tuple->mb == NULL) +#endif + item->mb = fmt_escape(""); +#ifdef NOTYET + else + item->mb = fmt_escape((char*)tuple->mb); +#endif + + if(tuple->album_name == NULL) + item->album = fmt_escape(""); + else + item->album = fmt_escape((char*)tuple->album_name); + + q_nitems++; + + item->next = NULL; + + if(q_queue_last == NULL) + q_queue = q_queue_last = item; + else + { + q_queue_last->next = item; + q_queue_last = item; + } +} + +static item_t *q_put2(char *artist, char *title, char *len, char *time, + char *album, char *mb) +{ + char *temp = NULL; + item_t *item; + + item = calloc(1, sizeof(item_t)); + temp = fmt_unescape(artist); + item->artist = fmt_escape(temp); + curl_free(temp); + temp = fmt_unescape(title); + item->title = fmt_escape(temp); + curl_free(temp); + memcpy(item->len, len, sizeof(len)); + temp = fmt_unescape(time); + item->utctime = fmt_escape(temp); + curl_free(temp); + temp = fmt_unescape(album); + item->album = fmt_escape(temp); + curl_free(temp); + temp = fmt_unescape(mb); + item->mb = fmt_escape(temp); + curl_free(temp); + + q_nitems++; + + item->next = NULL; + if(q_queue_last == NULL) + q_queue = q_queue_last = item; + else + { + q_queue_last->next = item; + q_queue_last = item; + } + + return item; +} + +static item_t *q_peek(void) +{ + if (q_nitems == 0) + return NULL; + return q_queue; +} + +static item_t *q_peekall(int rewind) +{ + static item_t *citem = NULL; + item_t *temp_item; + + if (rewind) { + citem = q_queue; + return NULL; + } + + temp_item = citem; + + if(citem != NULL) + citem = citem->next; + + return temp_item; +} + +static int q_get(void) +{ + item_t *item; + + if (q_nitems == 0) + return 0; + + item = q_queue; + + if(item == NULL) + return 0; + + q_nitems--; + q_queue = q_queue->next; + + q_item_free(item); + + if (q_nitems == 0) + { + q_queue_last = NULL; + return 0; + } + + return -1; +} + +static void q_free(void) +{ + while (q_get()); +} + +static int q_len(void) +{ + return q_nitems; +} + /* Error functions */ static void sc_throw_error(char *errortxt)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/scrobbler/settings.h Fri Dec 08 19:31:43 2006 -0800 @@ -0,0 +1,14 @@ +#include "../../config.h" + +#ifndef __SCROBBLER_CONFIG_H__ +#define __SCROBBLER_CONFIG_H__ + +#define DEBUG 3 +#define META_DEBUG 3 +#define SUB_DEBUG 3 +#define CLIENT "Audacious" +#define USER_AGENT "AudioScrobbler/1.1" PACKAGE_NAME "/" PACKAGE_VERSION +#define MAKE_BMP +#define ALLOW_MULTIPLE + +#endif
--- a/src/scrobbler/xmms_scrobbler.c Fri Dec 08 17:52:54 2006 -0800 +++ b/src/scrobbler/xmms_scrobbler.c Fri Dec 08 19:31:43 2006 -0800 @@ -1,3 +1,4 @@ +#include "settings.h" #include "config.h" #include <glib.h> @@ -21,6 +22,7 @@ #include <sys/time.h> #include "scrobbler.h" +#include "gerpok.h" #include "gtkstuff.h" #include "config.h" #include "fmt.h" @@ -37,7 +39,7 @@ static void cleanup(void); static void *xs_thread(void *); static void *hs_thread(void *); -static int going; +static int sc_going, ge_going; static GtkWidget *cfgdlg; static GThread *pt_scrobbler; @@ -59,40 +61,68 @@ static void init(void) { char *username = NULL, *password = NULL; + char *ge_username = NULL, *ge_password = NULL; ConfigDb *cfgfile; - going = 1; + sc_going = 1; + ge_going = 1; GError **moo = NULL; cfgdlg = create_cfgdlg(); - prefswin_page_new(cfgdlg, "Last.FM", DATA_DIR "/images/audioscrobbler.png"); + prefswin_page_new(cfgdlg, "Scrobbler", DATA_DIR "/images/audioscrobbler.png"); if ((cfgfile = bmp_cfg_db_open()) != NULL) { bmp_cfg_db_get_string(cfgfile, "audioscrobbler", "username", &username); bmp_cfg_db_get_string(cfgfile, "audioscrobbler", "password", &password); + bmp_cfg_db_get_string(cfgfile, "audioscrobbler", "ge_username", + &ge_username); + bmp_cfg_db_get_string(cfgfile, "audioscrobbler", "ge_password", + &ge_password); bmp_cfg_db_close(cfgfile); } - if ((!username || !password) || (!*username || !*password)) { - pdebug("username/password not found - not starting", + + if ((!username || !password) || (!*username || !*password)) + { + pdebug("username/password not found - not starting last.fm support", DEBUG); - going = 0; - return; + sc_going = 0; } - sc_init(username, password); + else + sc_init(username, password); + g_free(username); g_free(password); + + if ((!ge_username || !ge_password) || (!*ge_username || !*ge_password)) + { + pdebug("username/password not found - not starting Gerpok support", + DEBUG); + ge_going = 0; + } + else + gerpok_sc_init(ge_username, ge_password); + + g_free(ge_username); + g_free(ge_password); + m_scrobbler = g_mutex_new(); - if ((pt_scrobbler = g_thread_create(xs_thread, m_scrobbler, TRUE, moo)) == NULL) { + if ((pt_scrobbler = g_thread_create(xs_thread, m_scrobbler, TRUE, moo)) == NULL) + { pdebug(fmt_vastr("Error creating scrobbler thread: %s", moo), DEBUG); - going = 0; + sc_going = 0; + ge_going = 0; return; } - if ((pt_handshake = g_thread_create(hs_thread, m_scrobbler, TRUE, NULL)) == NULL) { - pdebug("Error creating handshake thread", DEBUG); - going = 0; + + if ((pt_handshake = g_thread_create(hs_thread, m_scrobbler, TRUE, NULL)) == NULL) + { + pdebug(fmt_vastr("Error creating handshake thread: %s", moo), DEBUG); + sc_going = 0; + ge_going = 0; return; } + pdebug("plugin started", DEBUG); } @@ -103,12 +133,13 @@ prefswin_page_destroy(cfgdlg); - if (!going) + if (!sc_going && !ge_going) return; pdebug("about to lock mutex", DEBUG); g_mutex_lock(m_scrobbler); pdebug("locked mutex", DEBUG); - going = 0; + sc_going = 0; + ge_going = 0; g_mutex_unlock(m_scrobbler); pdebug("joining threads", DEBUG); g_thread_join(pt_scrobbler); @@ -116,6 +147,7 @@ g_thread_join(pt_handshake); sc_cleaner(); + gerpok_sc_cleaner(); } static char ishttp(const char *a) @@ -377,6 +409,12 @@ sc_clear_error(); } + if(gerpok_sc_catch_error()) + { + errorbox_show(gerpok_sc_fetch_error()); + gerpok_sc_clear_error(); + } + /* Check for ability to submit */ dosubmit = get_song_status(); @@ -397,12 +435,14 @@ tuple->performer, tuple->track_name), DEBUG); sc_addentry(m_scrobbler, tuple, dosubmit.len/1000); + gerpok_sc_addentry(m_scrobbler, tuple, + dosubmit.len/1000); } else pdebug("tuple does not contain an artist or a title, not submitting.", DEBUG); } g_mutex_lock(m_scrobbler); - run = going; + run = (sc_going != 0 || ge_going != 0); g_mutex_unlock(m_scrobbler); g_usleep(100000); } @@ -422,11 +462,20 @@ { pdebug("Giving up due to fatal error", DEBUG); g_mutex_lock(m_scrobbler); - going = 0; + sc_going = 0; g_mutex_lock(m_scrobbler); } + + if(gerpok_sc_idle(m_scrobbler)) + { + pdebug("Giving up due to fatal error", DEBUG); + g_mutex_lock(m_scrobbler); + ge_going = 0; + g_mutex_lock(m_scrobbler); + } + g_mutex_lock(m_scrobbler); - run = going; + run = (sc_going != 0 || ge_going != 0); g_mutex_unlock(m_scrobbler); g_usleep(1000000); }