/* MusicInfo plugin for gaim Displays whatever is currently playing in Winamp in the user's profile in Gaim Written by Reuben Balik Copyright 2005 By Reuben Balik I'll add an official license later, but for now, please ask permission before using any of this code for any other project/product. Last Update: November 14, 2005 */ #include "internal.h" #include "connection.h" //#include "pluginpref.h" #include "signals.h" #include "version.h" //#include "notify.h" #include #include static const int maxLen = 2048; //the maximum profile length (I'm not actually sure what the official max AIM profile size is) static const int namesize = 256; //string size for artist and title static const int interval = 30 * 1000; //how often to check the winamp window (milleseconds) //these are all the strings that the plugin searches for static char artist_replace[] = "%ar%"; static char title_replace[] = "%so%"; static char start_songText[] = "(mi)"; static char end_songText[] = "(/mi)"; static char start_noSongText[] = "(ns)"; static char end_noSongText[] = "(/ns)"; static int timeoutint = 0; static GaimConnection* curgc; static char* prevInfo; // getSong gets the name of the song and artist from the title of the winamp window // and puts them in the buffers pointed to by title and artist // len is the size of the title and artist buffers // getSong returns FALSE if Winamp is closed or not playing, TRUE if it successfully got a song static gboolean getSong(char* title, char* artist, int len) { //get a handle to the Winamp window (thanks to winamp dev forum) HWND hwndWinamp = FindWindow("Winamp v1.x",NULL); char this_title[len*2]; int ret = GetWindowText(hwndWinamp,this_title,sizeof(this_title)); if(ret != 0) { if(strstr(this_title, "[Stopped]") != NULL) return FALSE; if(strstr(this_title, "[Paused]") != NULL) return FALSE; char temp[len]; char *firsthyphen, *secondhyphen, *period, *ptr; firsthyphen = strchr(this_title, '-'); if(firsthyphen == NULL) //when winamp starts up without playing it doesn't display the song name return FALSE; secondhyphen = strrchr(this_title, '-'); period = strchr(this_title, '.'); ptr = period+2; int count = 0; if(firsthyphen != secondhyphen) //there's two hyphens so we have an artist { while(ptr != firsthyphen && count < len) { temp[count] = *ptr; ptr++; count++; } temp[count-1] = '\0'; ptr+=2; strcpy(artist, temp); } else //no artist { strcpy(artist, "Unknown"); } count=0; while(ptr != secondhyphen && count < len) { temp[count] = *ptr; ptr++; count++; } temp[count-1] = '\0'; strcpy(title, temp); return TRUE; } else { return FALSE; } } // replaces the first instance of replaceStr in text with replaceWith // max is the size of text static gboolean replaceText(char* text, char* replaceStr, char* replaceWith, int max) { char* pos = text; char* foundAt = strstr(text, replaceStr); char newString[max]; if(foundAt == NULL) return FALSE; int cur = 0; while(pos != foundAt && cur < max) { newString[cur] = *pos; pos++; cur++; } char* replacePos = replaceWith; while(*replacePos != '\0' && cur < max) { newString[cur] = *replacePos; replacePos++; cur++; } pos+=strlen(replaceStr); while(*pos != '\0' && cur < max) { newString[cur] = *pos; pos++; cur++; } newString[cur] = '\0'; strncpy(text, newString, max); return TRUE; } // update the info for the connection gc static void updateInfo(GaimConnection *gc) { GaimAccount* account; account = gaim_connection_get_account(gc); char curAcct[maxLen]; if(gaim_account_get_user_info(account) != NULL) { g_strlcpy(curAcct, gaim_account_get_user_info(account), sizeof(curAcct)); char title[namesize]; char artist[namesize]; char hideThis[maxLen]; char* hidepos; char* endhidepos; if(getSong(title, artist, namesize)) { //replace the appropriate text replaceText(curAcct, start_songText, "\0", maxLen); replaceText(curAcct, end_songText, "\0", maxLen); replaceText(curAcct, artist_replace, artist, maxLen); replaceText(curAcct, title_replace, title, maxLen); //hide the text that gets displayed when we're not listening hidepos = strstr(curAcct, start_noSongText); endhidepos = strstr(curAcct, end_noSongText); endhidepos+= strlen(end_noSongText); if(hidepos != NULL && endhidepos != NULL && endhidepos > hidepos) { int i = 0; while(hidepos != endhidepos && i < maxLen) { hideThis[i] = *hidepos; hidepos++; i++; } hideThis[i] = '\0'; replaceText(curAcct, hideThis, "\0", maxLen); } } else { //replace the appropriate text replaceText(curAcct, start_noSongText, "\0", maxLen); replaceText(curAcct, end_noSongText, "\0", maxLen); //hide the text that gets displayed when we're listening hidepos = strstr(curAcct, start_songText); endhidepos = strstr(curAcct, end_songText); endhidepos+= strlen(end_songText); if(hidepos != NULL && endhidepos != NULL && endhidepos > hidepos) { int i = 0; while(hidepos != endhidepos && i < maxLen) { hideThis[i] = *hidepos; hidepos++; i++; } hideThis[i] = '\0'; replaceText(curAcct, hideThis, "\0", maxLen); } } //this is so we don't update the server if we don't have to if(strcmp(curAcct, prevInfo) != 0) { serv_set_info(gc, curAcct); strncpy(prevInfo, curAcct, maxLen); } } } static gboolean callUpdateInfo(gpointer gc) { updateInfo((GaimConnection*) gc); return TRUE; } //this is only called for the first update. it has to return FALSE to kill the timer //and reset prevInfo static gboolean callFirstUpdate(gpointer gc) { *prevInfo = '\0'; updateInfo((GaimConnection*) gc); return FALSE; } static void online(GaimConnection *gc) { //doesn't run on two connections at once at the moment if(timeoutint == 0) { curgc = gc; //a slight delay is needed for the first update because gaim already updates the server when you sign on g_timeout_add(2200, callFirstUpdate, (gpointer)gc); timeoutint = g_timeout_add(interval, callUpdateInfo, (gpointer)gc); } } static void signoff(GaimConnection *gc) { //this should only remove if the account signing off is the one that we're updating if(gc == curgc) { g_source_remove(timeoutint); timeoutint = 0; } } static gboolean plugin_load(GaimPlugin *plugin) { prevInfo = (char*) malloc(sizeof(char) * maxLen); *prevInfo = '\0'; gaim_signal_connect(gaim_connections_get_handle(), "signed-on", plugin, GAIM_CALLBACK(online), NULL); gaim_signal_connect(gaim_connections_get_handle(), "signing-off", plugin, GAIM_CALLBACK(signoff), NULL); return TRUE; } static gboolean plugin_unload(GaimPlugin *plugin) { free(prevInfo); gaim_signal_disconnect(gaim_connections_get_handle(), "signed-on", plugin, GAIM_CALLBACK(online)); gaim_signal_disconnect(gaim_connections_get_handle(), "signing-off", plugin, GAIM_CALLBACK(signoff)); return TRUE; } static GaimPluginInfo info = { GAIM_PLUGIN_MAGIC, GAIM_MAJOR_VERSION, GAIM_MINOR_VERSION, GAIM_PLUGIN_STANDARD, /**< type */ NULL, /**< ui_requirement */ 0, /**< flags */ NULL, /**< dependencies */ GAIM_PRIORITY_DEFAULT, /**< priority */ "core-cybrguyrsb-musicinfo", /**< id */ N_("MusicInfo"), /**< name */ "0.3.2", /**< version */ /** summary */ N_("Displays the current song in Winamp in your user info"), /** description */ N_("Displays the current song in Winamp in your user info"), "Reuben Balik ", /**< author */ "http://www.ews.uiuc.edu/~rbalik2/musicinfo/", /**< homepage */ plugin_load, /**< load */ plugin_unload, /**< unload */ NULL, /**< destroy */ NULL, /**< ui_info */ NULL, /**< extra_info */ NULL, /**< prefs_info */ NULL }; static void init_plugin(GaimPlugin *plugin) { } GAIM_INIT_PLUGIN(mig, init_plugin, info)