Skip to content

Instantly share code, notes, and snippets.

@shoban
Created February 25, 2011 17:37
Show Gist options
  • Save shoban/844161 to your computer and use it in GitHub Desktop.
Save shoban/844161 to your computer and use it in GitHub Desktop.
Patch for scrobbling songs played on Pandora.
diff --git a/chromescrobbler.js b/chromescrobbler.js
index 13f59d1..ce18132 100644
--- a/chromescrobbler.js
+++ b/chromescrobbler.js
@@ -5,6 +5,7 @@ var nowPlayingURL = "http://post.audioscrobbler.com:80/np_1.2";
var submissionURL = "http://post2.audioscrobbler.com:80/protocol_1.2";
function handshake() {
+ console.log('handshake(): ');
var username = localStorage.username;
var password = localStorage.password;
var currentTime = parseInt(new Date().getTime() / 1000.0);
@@ -12,6 +13,11 @@ function handshake() {
var http_request = new XMLHttpRequest();
http_request.onreadystatechange = function() {
if (http_request.readyState == 4 && http_request.status == 200) {
+ response = http_request.responseText.split("\n")[0];
+ console.log('handshake(): ' + http_request.responseText);
+ if (response != "OK") {
+ console.log('handshake(): failed. ' + response);
+ }
sessionID = http_request.responseText.split("\n")[1];
nowPlayingURL = http_request.responseText.split("\n")[2];
submissionURL = http_request.responseText.split("\n")[3];
@@ -26,10 +32,18 @@ function handshake() {
}
function nowPlaying(sender) {
- var params = "s=" + sessionID + "&a=" + song.artist + "&t=" + song.track + "&b=&l=" + song.duration + "&m=&n=";
+ var params = "s=" + sessionID + "&a=" + song.artist + "&t=" + song.track + "&b=";
+ if (song.duration != 0) {
+ params += "&l=" + song.duration;
+ } else {
+ params += "&l=";
+ }
+ params += "&m=&n=";
+ console.log('nowPlaying(): params=' + params);
var http_request = new XMLHttpRequest();
http_request.onreadystatechange = function() {
if (http_request.readyState == 4 && http_request.status == 200)
+ console.log('nowPlaying(): rsp=' + http_request.responseText);
if (http_request.responseText.split("\n")[0] == "BADSESSION") {handshake(); nowPlaying();}
else {
//Executes updateTitle function in youtube.js, only when there is a successfull session id. If user had wrong pass or uname, it will not update the title
@@ -45,10 +59,22 @@ function submit() {
nowPlayingTab = null;
var playTime = parseInt(new Date().getTime() / 1000.0) - song.startTime;
if (playTime > 30 && playTime > Math.min(240, song.duration / 2)) {
- var params = "s=" + sessionID + "&a[0]=" + song.artist + "&t[0]=" + song.track + "&i[0]=" + song.startTime + "&o[0]=P&r[0]=&l[0]=" + song.duration + "&b[0]=&m[0]=&n[0]=";
+ var params = "s=" + sessionID + "&a[0]=" + song.artist;
+ params += "&t[0]=" + song.track;
+ params += "&i[0]=" + song.startTime;
+ params += "&o[0]=" + song.source;
+ params += "&r[0]=";
+ if (song.duration != 0) {
+ params += "&l[0]=" + song.duration;
+ } else {
+ params += "&l[0]=";
+ }
+ params += "&b[0]=&m[0]=&n[0]=";
+ console.log('submit(): params=' + params);
var http_request = new XMLHttpRequest();
http_request.onreadystatechange = function() {
if (http_request.readyState == 4 && http_request.status == 200)
+ console.log('submit(): rsp=' + http_request.responseText);
if (http_request.responseText.split("\n")[0] == "BADSESSION") {handshake(); submit();}
};
http_request.open("POST", submissionURL, true);
@@ -57,8 +83,7 @@ function submit() {
}
}
-chrome.extension.onRequest.addListener(
- function(request, sender, sendResponse) {
+chrome.extension.onRequest.addListener(
function(request, sender, sendResponse) {
switch(request.type) {
case "nowPlaying":
if (nowPlayingTab != null) submit();
@@ -66,6 +91,7 @@ chrome.extension.onRequest.addListener(
song = { "artist" : request.artist,
"track" : request.track,
"duration" : request.duration,
+ "source" : request.source,
"startTime" : parseInt(new Date().getTime() / 1000.0)};
if (sessionID == "") handshake();
nowPlaying(sender);
diff --git a/manifest.json b/manifest.json
index 0c2dc53..fdbb7fa 100644
--- a/manifest.json
+++ b/manifest.json
@@ -17,6 +17,11 @@
"matches": ["http://www.youtube.com/watch?v=*"],
"js": ["youtube.js"],
"css": ["youtube.css"]
- }
+ },
+ {
+ "matches": ["http://www.pandora.com/*"],
+ "js": ["pandora.js"],
+ "run_at": "document_end"
+ }
]
}
diff --git a/pandora-lfm-inject.js b/pandora-lfm-inject.js
new file mode 100644
index 0000000..e041cc9
--- /dev/null
+++ b/pandora-lfm-inject.js
@@ -0,0 +1,81 @@
+// alert('pandora-lfm-inject.js load');
+
+var pandoraInjApiTries = 0;
+
+function pandoraInjApiLoaded()
+{
+ // alert('pandoraInjApiLoaded()');
+ if (pandoraInjApiTries < 30) {
+ if (typeof(Pandora) == "undefined") {
+ pandoraInjApiTries++;
+ window.setTimeout("pandoraInjApiLoaded()", 5000);
+ } else {
+ pandoraInjInitialize();
+ }
+ } else {
+ // error unable to register event handlers.
+ }
+}
+
+window.setTimeout("pandoraInjApiLoaded()", 5000);
+
+function pandoraInjInitialize()
+{
+ if (typeof(Pandora) == "undefined") {
+ // error unable to register event handlers.
+ return;
+ }
+ // alert('pandoraInjInitialize()');
+
+ Pandora.setEventHandler("SongPlayed", function(data) {
+ pandoraInjSongPlayEvent(data.songName, data.artistName);
+ });
+ Pandora.setEventHandler("SongPaused", function(data) {
+ pandoraInjSongPauseEvent(data.songName, data.artistName);
+ });
+ Pandora.setEventHandler("SongEnded", function(data) {
+ pandoraInjSongEndEvent(data.songName, data.artistName);
+ });
+}
+
+function pandoraInjSendEvent(e, song, artist)
+{
+ var comDiv = document.getElementById('pandoraInjEventsDiv');
+ if (!comDiv) {
+ // error unable to send event.
+ alert('ERROR: pandoraInjEventsDiv not found.');
+ return;
+ }
+
+ comDiv.setAttribute('song', song);
+ comDiv.setAttribute('artist', artist);
+ comDiv.dispatchEvent(e);
+}
+
+var pandoraInjPlayEventObj = document.createEvent('Event');
+var pandoraInjPauseEventObj = document.createEvent('Event');
+var pandoraInjEndEventObj = document.createEvent('Event');
+pandoraInjPlayEventObj.initEvent('pandoraInjPlayEvent', true, true);
+pandoraInjPauseEventObj.initEvent('pandoraInjPauseEvent', true, true);
+pandoraInjEndEventObj.initEvent('pandoraInjEndEvent', true, true);
+
+function pandoraInjSongPlayEvent(song, artist)
+{
+ // alert('PLAY: ' + artist + ' - ' + song);
+ pandoraInjSendEvent(pandoraInjPlayEventObj,
+ song, artist);
+}
+
+function pandoraInjSongPauseEvent(song, artist)
+{
+ // alert('PAUSE: ' + artist + ' - ' + song);
+ pandoraInjSendEvent(pandoraInjPauseEventObj,
+ song, artist);
+}
+
+function pandoraInjSongEndEvent(song, artist)
+{
+ // alert('END: ' + artist + ' - ' + song);
+ pandoraInjSendEvent(pandoraInjEndEventObj,
+ song, artist);
+}
diff --git a/pandora.js b/pandora.js
new file mode 100644
index 0000000..14da03a
--- /dev/null
+++ b/pandora.js
@@ -0,0 +1,174 @@
+function Log(type, str)
+{
+ console.log(type.toUpperCase() + ': ' + str);
+}
+function LogD(str) { Log('debug', str); }
+function LogE(str) { Log('error', str); }
+
+var g_song = "";
+var g_artist = "";
+var g_playedDuration = 0;
+var g_startTime = 0;
+var g_songPaused = false;
+
+function getTime()
+{
+ var d = new Date();
+ return d.getTime();
+}
+
+function pandoraClearSong()
+{
+ g_song = "";
+ g_artist = "";
+ g_playedDuration = 0;
+ g_startTime = 0;
+ g_songPaused = false;
+}
+
+function pandoraSongPauseEvent()
+{
+ LogD('PauseEvent: ');
+ var ev_div = document.getElementById('pandoraInjEventsDiv');
+ if (!ev_div) {
+ return;
+ }
+
+ song = ev_div.getAttribute('song');
+ artist = ev_div.getAttribute('artist');
+
+ LogD('PauseEvent: ' + artist + ' - ' + song);
+ if (song == g_song && artist == g_artist) {
+ g_songPaused = true;
+ g_playedDuration += getTime() - g_startTime;
+ g_startTime = 0;
+ }
+}
+
+function pandoraSongPlayEvent()
+{
+ LogD('PlayEvent: ');
+
+ var ev_div = document.getElementById('pandoraInjEventsDiv');
+ if (!ev_div) {
+ return;
+ }
+
+ song = ev_div.getAttribute('song');
+ artist = ev_div.getAttribute('artist');
+
+ LogD('PlayEvent: ' + artist + ' - ' + song);
+ if (g_song == "" && g_artist == "") {
+ // New song start.
+ g_song = song;
+ g_artist = artist;
+ g_playedDuration = 0;
+ g_startTime = getTime();
+ g_songPaused = false;
+ pandoraSendNowPlaying();
+ } else {
+ // Continuation of same song.
+ g_startTime = getTime();
+ }
+}
+
+function pandoraSongEndEvent()
+{
+ LogD('EndEvent: ');
+ var ev_div = document.getElementById('pandoraInjEventsDiv');
+ if (!ev_div) {
+ return;
+ }
+
+ song = ev_div.getAttribute('song');
+ artist = ev_div.getAttribute('artist');
+
+ LogD('EndEvent: ' + artist + ' - ' + song);
+
+ if (song == g_song && artist == g_artist) {
+ g_playedDuration += getTime() - g_startTime;
+
+ // Only submit songs which have played more than 2mins.
+ LogD('EndEvent: g_playedDuration=' + g_playedDuration);
+ if (g_playedDuration > 120000) {
+ pandoraSendPlayed();
+ }
+ }
+
+ pandoraClearSong();
+}
+
+function pandoraInitialize()
+{
+ LogD('pandoraInitialize(): ');
+ if (!document.getElementById("tunerEventListenerDiv")) {
+ var api = document.createElement('script');
+ api.setAttribute('language', 'javascript');
+ api.setAttribute('type', 'text/javascript');
+ api.setAttribute('src', 'http://www.pandora.com/include/PandoraAPIv2.js');
+ api.setAttribute('id', 'evntjs');
+ document.getElementsByTagName('head')[0].appendChild(api);
+ LogD('Injecting PandoraAPIv2.js');
+ }
+
+ var ev_div = document.createElement('div');
+ ev_div.setAttribute('style', 'display:none');
+ ev_div.setAttribute('id', 'pandoraInjEventsDiv');
+ document.getElementsByTagName('body')[0].appendChild(ev_div);
+ LogD('pandoraInjEventsDiv: created.');
+
+ ev_div.addEventListener('pandoraInjPlayEvent', function() {
+ pandoraSongPlayEvent();
+ });
+ ev_div.addEventListener('pandoraInjPauseEvent', function() {
+ pandoraSongPauseEvent();
+ });
+ ev_div.addEventListener('pandoraInjEndEvent', function() {
+ pandoraSongEndEvent();
+ });
+ LogD('pandoraInjEventsDiv: events registered.');
+
+ var lfm_inj = document.createElement('script');
+ lfm_inj.setAttribute('language', 'javascript');
+ lfm_inj.setAttribute('type', 'text/javascript');
+ lfm_inj.setAttribute('src',
+ chrome.extension.getURL('pandora-lfm-inject.js'));
+ lfm_inj.setAttribute('id', 'lfminjjs');
+ document.getElementsByTagName('head')[0].appendChild(lfm_inj);
+ LogD('Injecting pandora-lfm-inject.js');
+
+ pandoraClearSong();
+}
+
+
+function pandoraSendNowPlaying()
+{
+ var validationURL = "http://ws.audioscrobbler.com/2.0/?" +
+ "method=track.getinfo" +
+ "&api_key=44c7aeb27b91eb0e4e913098a9dc2378" +
+ "&artist="+ g_artist + "&track=" + g_song;
+ LogD('pandoraSendNowPlaying(): ');
+ LogD('pandoraSendNowPlaying(): validationURL=' + validationURL);
+
+ chrome.extension.sendRequest({type: "xhr", url: validationURL},
+ function(response) {
+ if (response.text != "You must supply either an artist and track name OR a musicbrainz id.") {
+ LogD('pandoraSendNowPlaying(): send nowPlaying.');
+ chrome.extension.sendRequest({type: "nowPlaying",
+ artist: g_artist, track: g_song, duration: 0,
+ source: "R"});
+ };
+ });
+ LogD('pandoraSendNowPlaying(): auth.');
+}
+
+function pandoraSendPlayed()
+{
+ LogD('pandoraSendPlayed(): ');
+ chrome.extension.sendRequest({type: "submit"},
+ function(r) {
+ LogD('pandoraSendPlayed(): submitted.');
+ });
+}
+
+pandoraInitialize();
diff --git a/youtube.js b/youtube.js
index 89cc246..70fc339 100644
--- a/youtube.js
+++ b/youtube.js
@@ -10,7 +10,8 @@ chrome.extension.sendRequest({type: "xhr", url: googleURL}, function(response) {
var validationURL = "http://ws.audioscrobbler.com/2.0/?method=track.getinfo&api_key=44c7aeb27b91eb0e4e913098a9dc2378&artist="+ artist + "&track=" + track;
chrome.extension.sendRequest({type: "xhr", url: validationURL}, function(response) {
if (response.text != "You must supply either an artist and track name OR a musicbrainz id.") {
- chrome.extension.sendRequest({type: "nowPlaying", artist: artist, track: track, duration: duration});
+ chrome.extension.sendRequest({type: "nowPlaying", artist: artist, track: track,
+ duration: duration, source: "P"});
};
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment