Gmail Last.fm Signature
By Henry Cooke
—
Last update Jun 9, 2008
—
Installed
222 times.
// ==UserScript==
// @name Gmail Last.fm Signature
// @description Automatically inserts a signature containing current listening information for a specified Last.fm user
// @namespace http://www.prehensile.co.uk/greasemonkey/lastfm
// @include http://mail.google.com/*
// @include https://mail.google.com/*
// ==/UserScript==
//
// Version: 0.31 (09/06/08)
// Version History:
// 0.31 Fixed a minor bug where artist / track name contains commas
// 0.3 First public release
// Based on: Gmail HTML Signatures 1.07 by Jerome Dane, http://blankcanvasweb.com/gmail2_html_sigs/
// Based on: Gmail: Random Signature Remote 1.0 by Stuart Langridge (sil at kryogenix dot org)
// Author: Henry Cooke
// Latest Information: http://prehensile.co.uk/blog/?cat=27
// --------------------------------------------------------------------------------------
// ---------- Do not edit below this line unless you really know what you are doing -----
// --------------------------------------------------------------------------------------
var version = '0.31';
var gmail = null;
var bodyArea = null;
var msg_retry;
var arrCurrentTrackData;
var context = "";
var lastfmUserName = "";
var sigFileURL = "";
var gmailAve;
var replyListening = false;
var inserted = false;
var initialised = false;
// begin the insert process by fetching last.fm data
function begin_insert(){
if( !inserted ){
inserted = true;
wrapper_getLastFmData();
}
}
function getLastFmData(){
checkLastfmUser();
GM_xmlhttpRequest({
method: 'GET',
url: 'http://ws.audioscrobbler.com/1.0/user/' + lastfmUserName + '/recenttracks.txt',
headers: {
'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey',
'Accept': 'text/plain',
},
onload: function( responseDetails ) {
onLastFmData( responseDetails );
}
});
}
function fetchSigFile() {
checkSigFileURL();
GM_xmlhttpRequest({
method: 'GET',
url: sigFileURL,
headers: {
'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey',
'Accept': 'text/plain',
},
onload: function(responseDetails) {
onSigFile( responseDetails );
}
});
}
// parse recieved last.fm data into an array. will need to change if last fm's recenttracks.txt data format changes
function onLastFmData( responseDetails ){
var arrEntries = responseDetails.responseText.split('\n');
var parts = arrEntries[0].split(",");
var trackData = "";
if( parts.length > 2 ) trackData = parts.slice( 1 ).join( "," ); //0.31 - deal with artist / track names that contain commas
else trackData = parts[1];
arrCurrentTrackData = trackData.split( " – " ); // save track data into an array to use later
fetchSigFile();
}
// response handler for receiving a sig file
function onSigFile( responseDetails ){
if( !checkText( bodyArea.value, responseDetails.responseText ) ){ // check message box doesn't already contain sig
var sig = parseSig( responseDetails.responseText, arrCurrentTrackData );
insertSig( sig );
}
}
// replace tokens in sig file with last.fm data
function parseSig( sigText, trackData ){
var parsed = "";
// insert data from array
parsed = sigText.replace( "%artist%", trackData[0] );
parsed = parsed.replace( "%track%", trackData[1] );
return( parsed );
}
// insert signature into gmail message body area
function insertSig( sigText ){
if( bodyArea ){
if( context == "Conversation" ) bodyArea.value = sigText + bodyArea.value;
else bodyArea.value = bodyArea.value + sigText;
inserted = true;
}
}
// event handler, used in conversation view to listen for user opening reply box
function onDOMNodeInserted( event ){
var eventContainsBody = getMessageTextarea( event.target );
if( eventContainsBody ){
bodyArea = eventContainsBody;
begin_insert();
}
}
// event handler, used in conversation view to listen for user closing reply box
function onDOMNodeRemoved( event ){
var eventContainsBody = getMessageTextarea( event.target );
if( eventContainsBody ) inserted = false;
}
function init(){
if( !initialised ){
if (unsafeWindow.gmonkey) {
unsafeWindow.gmonkey.load('1.0', function(gmail) {
function setViewType() {
var str = '';
switch (gmail.getActiveViewType()) {
case 'tl': str = 'Threadlist'; break;
case 'cv': str = 'Conversation'; break;
case 'co': str = 'Compose'; break;
case 'ct': str = 'Contacts'; break;
case 's': str = 'Settings'; break;
default: str = 'Unknown';
}
context = str;
bodyArea = false;
inserted = false;
if( gmailAve ) removeReplyListeners( gmailAve );
gmailAve = gmail.getActiveViewElement();
if( str == 'Compose' ) {
compose_context( gmailAve );
} else if( str == 'Conversation'){
conversation_context( gmailAve );
}
}
function message_box_listener( ave ) {
var gmt = getMessageTextarea( ave );
if( gmt ) {
bodyArea = gmt;
return true;
} else {
return false;
}
}
function compose_context( ave ) {
if( message_box_listener( ave ) ) {
begin_insert();
} else {
if( msg_retry-- > 0 ) setTimeout(compose_context, 500);
}
}
function conversation_context( ave ){
addReplyListeners( ave );
}
msg_retry = 2;
gmail.registerViewChangeCallback(setViewType);
setViewType();
});
}
initialised = true;
}
}
window.addEventListener('load', init, true );
window.addEventListener( 'unload', unInit, false );
// ***
// UTILITY FUNCTIONS
// ***
function unInit(){
removeReplyListeners( gmailAve );
window.removeEventListener( 'load', init, true );
window.removeEventListener( 'unload', unInit, false );
}
function addReplyListeners( ave ){
if( !replyListening ){
ave.addEventListener( "DOMNodeInserted", onDOMNodeInserted, false );
ave.addEventListener( "DOMNodeRemoved", onDOMNodeRemoved, false );
replyListening = true;
}
}
function removeReplyListeners( ave ){
if( replyListening ){
ave.removeEventListener( "DOMNodeInserted", onDOMNodeInserted, false );
ave.removeEventListener( "DOMNodeRemoved", onDOMNodeRemoved, false );
replyListening = false;
}
}
// check if bodyText contains sigText
function checkText( bodyText, sigText ){
var ret = false;
if( bodyText && sigText ){
var parts = sigText.split( "%" ); // split sig on token delimiter
var positives = 0;
for( var i=0; i< parts.length; i++ ){
if( i % 2 == 0 ){ // clever bit: in theory, if we split on the delimiter, even-numbered array entries will contain the plaintext portions of the sig ( & odd-numbered will contain token names )
var chunk = parts[ i ];
if( bodyText.indexOf( chunk ) > -1 ) positives ++;
}
}
if( positives >= (parts.length/2) ) ret = true;
}
return( ret );
}
// check if a last.fm username has been provided. if not, prompt user for it
function checkLastfmUser(){
var lfmu = GM_getValue( "lastfmUser" );
if( !lfmu ){
lfmu = prompt( "Please enter your last.fm user name");
GM_setValue( "lastfmUser", lfmu );
}
lastfmUserName = lfmu;
}
// check if a sigfile URL has been provided. if not, prompt user for it
function checkSigFileURL(){
var sfURL = GM_getValue( "sigFile" );
if( !sfURL ){
sfURL = prompt( "Please enter a sig file URL");
GM_setValue( "sigFile", sfURL );
}
sigFileURL = sfURL;
}
// get plaintext message input box from activeViewElement (ave)
function getMessageTextarea( ave ){
var ret = false;
//divine gmail message body area
var elems = document.evaluate( "//textarea[@name='body']", ave, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null );
if(elems.snapshotLength > 0 ) ret = elems.snapshotItem(0);
return( ret );
}
// workarounds for unsafewindow's xmlhttprequest security restriction
function wrapper_getLastFmData(){
window.setTimeout(function() {
getLastFmData();
}, 0);
}
function wrapper_fetchSigFile(){
window.setTimeout(function() {
fetchSigFile();
}, 0);
}