Guest User

Untitled

a guest
Dec 5th, 2015
1,899
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 28.34 KB | None | 0 0
  1. // ==UserScript==
  2. // @name scRYMble
  3. // @namespace http://bluetshirt.ca/scrymble
  4. // @description Visit a release page on rateyourmusic.com and scrobble the songs you see!
  5. // @include http://rateyourmusic.com/release/*
  6. // @include https://rateyourmusic.com/release/*
  7. // @version 0.0.1.20140717152423
  8. // @grant GM_getValue
  9. // @grant GM_setValue
  10. // @grant GM_xmlhttpRequest
  11. // @require http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js
  12.  
  13. // ==/UserScript==
  14.  
  15. //THANK YOU FOR THE NAME, LYNKALI!
  16. //THANKS TO 5thEye, AnniesBoobs, BruceWayne, and _Andrew_ for some useful tweaks and bug fixes.
  17.  
  18.  
  19. /*
  20. * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
  21. * Digest Algorithm, as defined in RFC 1321.
  22. * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
  23. * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
  24. * Distributed under the BSD License
  25. * See http://pajhome.org.uk/crypt/md5 for more info.
  26. */
  27.  
  28. /*
  29. * Configurable variables. You may need to tweak these to be compatible with
  30. * the server-side, but the defaults work in most cases.
  31. */
  32. var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
  33. var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
  34. var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
  35.  
  36. /*
  37. * These are the functions you'll usually want to call
  38. * They take string arguments and return either hex or base-64 encoded strings
  39. */
  40. function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
  41. function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}
  42. function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));}
  43. function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }
  44. function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }
  45. function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }
  46.  
  47.  
  48. /*
  49. * Perform a simple self-test to see if the VM is working
  50. */
  51. function md5_vm_test()
  52. {
  53. return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
  54. }
  55.  
  56. /*
  57. * Calculate the MD5 of an array of little-endian words, and a bit length
  58. */
  59. function core_md5(x, len)
  60. {
  61. /* append padding */
  62. x[len >> 5] |= 0x80 << ((len) % 32);
  63. x[(((len + 64) >>> 9) << 4) + 14] = len;
  64.  
  65. var a = 1732584193;
  66. var b = -271733879;
  67. var c = -1732584194;
  68. var d = 271733878;
  69.  
  70. for(var i = 0; i < x.length; i += 16)
  71. {
  72. var olda = a;
  73. var oldb = b;
  74. var oldc = c;
  75. var oldd = d;
  76.  
  77. a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
  78. d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
  79. c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
  80. b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
  81. a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
  82. d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
  83. c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
  84. b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
  85. a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
  86. d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
  87. c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
  88. b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
  89. a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
  90. d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
  91. c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
  92. b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
  93.  
  94. a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
  95. d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
  96. c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);
  97. b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
  98. a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
  99. d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
  100. c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
  101. b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
  102. a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
  103. d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
  104. c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
  105. b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
  106. a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
  107. d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
  108. c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
  109. b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
  110.  
  111. a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
  112. d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
  113. c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
  114. b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
  115. a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
  116. d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
  117. c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
  118. b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
  119. a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
  120. d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
  121. c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
  122. b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
  123. a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
  124. d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
  125. c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);
  126. b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
  127.  
  128. a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
  129. d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
  130. c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
  131. b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
  132. a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
  133. d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
  134. c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
  135. b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
  136. a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
  137. d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
  138. c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
  139. b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
  140. a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
  141. d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
  142. c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
  143. b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
  144.  
  145. a = safe_add(a, olda);
  146. b = safe_add(b, oldb);
  147. c = safe_add(c, oldc);
  148. d = safe_add(d, oldd);
  149. }
  150. return Array(a, b, c, d);
  151.  
  152. }
  153.  
  154. /*
  155. * These functions implement the four basic operations the algorithm uses.
  156. */
  157. function md5_cmn(q, a, b, x, s, t)
  158. {
  159. return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
  160. }
  161. function md5_ff(a, b, c, d, x, s, t)
  162. {
  163. return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
  164. }
  165. function md5_gg(a, b, c, d, x, s, t)
  166. {
  167. return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
  168. }
  169. function md5_hh(a, b, c, d, x, s, t)
  170. {
  171. return md5_cmn(b ^ c ^ d, a, b, x, s, t);
  172. }
  173. function md5_ii(a, b, c, d, x, s, t)
  174. {
  175. return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
  176. }
  177.  
  178. /*
  179. * Calculate the HMAC-MD5, of a key and some data
  180. */
  181. function core_hmac_md5(key, data)
  182. {
  183. var bkey = str2binl(key);
  184. if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);
  185.  
  186. var ipad = Array(16), opad = Array(16);
  187. for(var i = 0; i < 16; i++)
  188. {
  189. ipad[i] = bkey[i] ^ 0x36363636;
  190. opad[i] = bkey[i] ^ 0x5C5C5C5C;
  191. }
  192.  
  193. var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
  194. return core_md5(opad.concat(hash), 512 + 128);
  195. }
  196.  
  197. /*
  198. * Add integers, wrapping at 2^32. This uses 16-bit operations internally
  199. * to work around bugs in some JS interpreters.
  200. */
  201. function safe_add(x, y)
  202. {
  203. var lsw = (x & 0xFFFF) + (y & 0xFFFF);
  204. var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
  205. return (msw << 16) | (lsw & 0xFFFF);
  206. }
  207.  
  208. /*
  209. * Bitwise rotate a 32-bit number to the left.
  210. */
  211. function bit_rol(num, cnt)
  212. {
  213. return (num << cnt) | (num >>> (32 - cnt));
  214. }
  215.  
  216. /*
  217. * Convert a string to an array of little-endian words
  218. * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
  219. */
  220. function str2binl(str)
  221. {
  222. var bin = Array();
  223. var mask = (1 << chrsz) - 1;
  224. for(var i = 0; i < str.length * chrsz; i += chrsz)
  225. bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
  226. return bin;
  227. }
  228.  
  229. /*
  230. * Convert an array of little-endian words to a string
  231. */
  232. function binl2str(bin)
  233. {
  234. var str = "";
  235. var mask = (1 << chrsz) - 1;
  236. for(var i = 0; i < bin.length * 32; i += chrsz)
  237. str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
  238. return str;
  239. }
  240.  
  241. /*
  242. * Convert an array of little-endian words to a hex string.
  243. */
  244. function binl2hex(binarray)
  245. {
  246. var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
  247. var str = "";
  248. for(var i = 0; i < binarray.length * 4; i++)
  249. {
  250. str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
  251. hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF);
  252. }
  253. return str;
  254. }
  255.  
  256. /*
  257. * Convert an array of little-endian words to a base-64 string
  258. */
  259. function binl2b64(binarray)
  260. {
  261. var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  262. var str = "";
  263. for(var i = 0; i < binarray.length * 4; i += 3)
  264. {
  265. var triplet = (((binarray[i >> 2] >> 8 * ( i %4)) & 0xFF) << 16)
  266. | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
  267. | ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
  268. for(var j = 0; j < 4; j++)
  269. {
  270. if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
  271. else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
  272. }
  273. }
  274. return str;
  275. }
  276.  
  277. function getElementsByClassName(node, classname)
  278. {
  279. var a = [];
  280. var re = new RegExp('\\b' + classname + '\\b');
  281. var els = node.getElementsByTagName("*");
  282. for(var i=0,j=els.length; i<j; i++)
  283. if(re.test(els[i].className))a.push(els[i]);
  284. return a;
  285. }
  286.  
  287. String.prototype.trim = function() {
  288. return this.replace(/^\s+|\s+$/g,"");
  289. }
  290. String.prototype.ltrim = function() {
  291. return this.replace(/^\s+/,"");
  292. }
  293. String.prototype.rtrim = function() {
  294. return this.replace(/\s+$/,"");
  295. }
  296.  
  297. toScrobble = new Array();
  298. var currentlyScrobbling = -1;
  299. var sessID = false;
  300. var submitURL = false;
  301. var npURL = false;
  302. var currTrackDuration = false;
  303. var currTrackPlaytime = false;
  304. var numChecks = 0;
  305.  
  306.  
  307. function confirmBrowseAway(oEvent)
  308. {
  309. if (currentlyScrobbling != -1)
  310. oEvent.returnValue = "You are currently scrobbling a record. Leaving the page now will prevent future tracks from this release from scrobbling.";
  311.  
  312. }
  313.  
  314. function getPageArtist()
  315. {
  316. byartist = $('span[itemprop="byArtist"]');
  317. art_cred = $(byartist).find('.credited_name:eq(0) > span[itemprop="name"]');
  318. if ($(art_cred).length > 0){
  319. return $(art_cred).text();
  320. } else {
  321. return $(byartist).text();
  322. }
  323. }
  324.  
  325. function getAlbum()
  326. {
  327. return(($('.release_page meta[itemprop="name"]').attr("content"))).trim();
  328. }
  329. function isVariousArtists()
  330. {
  331. var artist = getPageArtist();
  332. return ((artist.indexOf("Various Artists") > -1) || (artist.indexOf(" / ") > -1));
  333. }
  334.  
  335. function ScrobbleRecord(trackName, artist, duration)
  336. {
  337. this.artist = artist;
  338. this.trackName = trackName;
  339.  
  340. var durastr = duration.trim();
  341.  
  342. var colon = duration.indexOf(":");
  343. if (colon != -1)
  344. {
  345. var minutes = duration.substring(0, colon);
  346. var seconds = duration.substring(colon+1);
  347.  
  348. this.duration = (minutes * 60) + (seconds * 1);
  349. } else
  350. {
  351. this.duration = 180;
  352. }
  353.  
  354. this.time = 0;
  355.  
  356. }
  357.  
  358. fetch_unix_timestamp = function()
  359. {
  360. return parseInt(new Date().getTime().toString().substring(0, 10))
  361. }
  362.  
  363. function acceptSubmitResponse(responseDetails, isBatch)
  364. {
  365.  
  366. if (responseDetails.status == 200)
  367. {
  368. if (responseDetails.responseText.indexOf("OK") == -1)
  369. {
  370. alert("track submit failed: " + responseDetails.status +
  371. ' ' + responseDetails.statusText + '\n\n' +
  372. 'Data:\n' + responseDetails.responseText);
  373. } else
  374. {
  375. //alert("OK!");
  376. }
  377. } else
  378. {
  379.  
  380. alert("track submit failed: " + responseDetails.status +
  381. ' ' + responseDetails.statusText + '\n\n' +
  382. 'Data:\n' + responseDetails.responseText);
  383. }
  384.  
  385. if (isBatch)
  386. {
  387. document.getElementById("scrymblemarquee").innerHTML = "Scrobbled OK!";
  388. } else
  389. {
  390. scrobbleNextSong();
  391. }
  392. }
  393.  
  394. function acceptSubmitResponseSingle(responseDetails)
  395. {
  396. acceptSubmitResponse(responseDetails, false);
  397. }
  398.  
  399. function acceptSubmitResponseBatch(responseDetails)
  400. {
  401. acceptSubmitResponse(responseDetails, true);
  402. }
  403.  
  404.  
  405. function acceptNPResponse(responseDetails)
  406. {
  407. if (responseDetails.status == 200)
  408. {
  409. if (responseDetails.responseText.indexOf("OK") == -1)
  410. {
  411. alert("track submit failed: " + responseDetails.status +
  412. ' ' + responseDetails.statusText + '\n\n' +
  413. 'Data:\n' + responseDetails.responseText);
  414. } else
  415. {
  416. //alert("OK!");
  417. }
  418. } else
  419. {
  420.  
  421. alert("track submit failed: " + responseDetails.status +
  422. ' ' + responseDetails.statusText + '\n\n' +
  423. 'Data:\n' + responseDetails.responseText);
  424. }
  425.  
  426.  
  427. }
  428.  
  429. function buildListOfSongsToScrobble()
  430. {
  431. toScrobble = new Array();
  432.  
  433. var canscrobble = 1;
  434. $.each($('.scrymblechk'), function(){
  435. if ($(this).is(':checked')){
  436. song = $(this).parent().parent();
  437. var songTitle = $(song).find('span[itemprop="name"]').text();
  438. var artist = getPageArtist();
  439. var length = $(song).find('.tracklist_duration').text();
  440.  
  441. ////
  442.  
  443. if (isVariousArtists())
  444. {
  445. var firstDash = songTitle.indexOf(" - ");
  446. if(firstDash == -1) // no dash exists! must be a single artist with " / " in the name or v/a with unscrobbleable list
  447. {
  448. artist = getPageArtist();
  449. if (artist.indexOf("Various Artists") > -1)
  450. {
  451. artist = $(".album_title:eq(0)").text()
  452. //canscrobble = 0;
  453. }
  454. }
  455. else
  456. {
  457. artist = songTitle.substring(0, firstDash);
  458. songTitle = songTitle.substring(firstDash + 3);
  459. }
  460. }
  461. else
  462. {
  463. artist = getPageArtist()
  464. title = $(song).find('span[itemprop="name"]');
  465. if ($(title).html().indexOf('<a title="[Artist') == 0 && $(title).text().indexOf(' - ') > 0){
  466. var firstDash = songTitle.indexOf(" - ");
  467. artist = songTitle.substring(0, firstDash);
  468. songTitle = songTitle.substring(firstDash + 3);
  469. }
  470. }
  471.  
  472. if((songTitle.toLowerCase() == "untitled") || (songTitle.toLowerCase() == "untitled track") || (songTitle == ""))
  473. {
  474. songTitle = "[untitled]";
  475. }
  476.  
  477. ////
  478. while (songTitle.indexOf(' ') > 0){songTitle = songTitle.replace(' ', ' ')}
  479. toScrobble[toScrobble.length] = new ScrobbleRecord(songTitle, artist, length);
  480. }
  481. });
  482.  
  483. }
  484.  
  485. function submitTracksBatch(sessID, submitURL)
  486. {
  487. buildListOfSongsToScrobble();
  488.  
  489. if(toScrobble != null)
  490. {
  491. var currTime = fetch_unix_timestamp();
  492. var hoursFudge = prompt("How many hours ago did you listen to this?");
  493. if(hoursFudge != null)
  494. {
  495. var album = getAlbum();
  496.  
  497. hoursFudge = parseFloat(hoursFudge);
  498.  
  499. if (!isNaN(hoursFudge))
  500. {
  501. //alert(currTime);
  502. currTime = currTime - (hoursFudge * 60 * 60);
  503. //alert(currTime);
  504. }
  505.  
  506. for (var i= (toScrobble.length)-1; i>=0; i--)
  507. {
  508. currTime = (currTime * 1) - (toScrobble[i].duration * 1);
  509. toScrobble[i].time = currTime;
  510. }
  511.  
  512. var outstr = "Artist: " + getPageArtist() + "\nAlbum: " + album + "\n";
  513.  
  514. for (var i=0; i<toScrobble.length; i++)
  515. {
  516. outstr += toScrobble[i].trackName + "(" + toScrobble[i].duration + ")\n";
  517. }
  518. //alert(outstr);
  519.  
  520. var postdata = new Array();
  521.  
  522. for (var i=0; i<toScrobble.length; i++)
  523. {
  524. postdata["a[" + i + "]"] = toScrobble[i].artist;
  525. postdata["t[" + i + "]"] = toScrobble[i].trackName;
  526. postdata["b[" + i + "]"] = album;
  527. postdata["n[" + i + "]"] = (i+1);
  528. postdata["l[" + i + "]"] = toScrobble[i].duration;
  529. postdata["i[" + i + "]"] = toScrobble[i].time;
  530. postdata["o[" + i + "]"] = "P";
  531. postdata["r[" + i + "]"] = "";
  532. postdata["m[" + i + "]"] = "";
  533. }
  534.  
  535. postdata["s"] = sessID;
  536.  
  537. var postdataStr = "";
  538. var firstTime = true;
  539. for (currKey in postdata)
  540. {
  541. if (firstTime)
  542. {
  543. firstTime = false;
  544. } else
  545. {
  546. postdataStr = postdataStr + "&";
  547. }
  548. postdataStr = postdataStr + encodeURIComponent(currKey) + "=" + encodeURIComponent(postdata[currKey]);
  549. }
  550.  
  551. //alert(submitURL);
  552. GM_xmlhttpRequest({
  553. method: 'POST',
  554. url: submitURL,
  555. data: postdataStr,
  556. headers: {
  557. 'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey',
  558. 'Content-type': 'application/x-www-form-urlencoded',
  559. },
  560. onload: acceptSubmitResponseBatch
  561. });
  562. }
  563. }
  564. }
  565.  
  566. function elementsOnAndOff(state)
  567. {
  568.  
  569. document.getElementById("scrobblenow").disabled = !state;
  570. document.getElementById("scrobblepassword").disabled = !state;
  571. document.getElementById("scrobbleusername").disabled = !state;
  572. document.getElementById("scrobblepassword").disabled = !state;
  573.  
  574.  
  575. //var eleTrackTable = document.getElementById('tracks');
  576.  
  577. //var rows = eleTrackTable.tBodies[0].rows;
  578.  
  579.  
  580. $.each($(".scrymblechk"), function() {
  581. try{
  582. $(this).disabled = !state;
  583. } catch (e)
  584. {
  585.  
  586. }
  587. });
  588. }
  589.  
  590. function elementsOff()
  591. {
  592. elementsOnAndOff(false);
  593. }
  594.  
  595. function elementsOn()
  596. {
  597. elementsOnAndOff(true);
  598. }
  599.  
  600. function startScrobble()
  601. {
  602.  
  603. currentlyScrobbling = -1;
  604. currTrackDuration = 0;
  605. currTrackPlayTime = 0;
  606.  
  607. elementsOff();
  608.  
  609. buildListOfSongsToScrobble();
  610.  
  611. scrobbleNextSong();
  612. }
  613.  
  614.  
  615. function resetScrobbler()
  616. {
  617. currentlyScrobbling = -1;
  618. currTrackDuration = 0;
  619. currTrackPlayTime = 0;
  620. document.getElementById("scrymblemarquee").innerHTML = "&nbsp;";
  621. document.getElementById("progbar").style.width = "0%";
  622.  
  623. toScrobble = new Array();
  624.  
  625. elementsOn();
  626.  
  627. numChecks = 0;
  628.  
  629. }
  630.  
  631. function scrobbleNextSong()
  632. {
  633.  
  634. currentlyScrobbling++;
  635.  
  636. if(currentlyScrobbling == toScrobble.length)
  637. {
  638. resetScrobbler();
  639. } else
  640. {
  641. window.setTimeout(timertick, 10);
  642.  
  643. handshake();
  644. }
  645. }
  646.  
  647. function submitThisTrack()
  648. {
  649. var postdata = new Array();
  650.  
  651. var i = 0;
  652.  
  653. var currTime = fetch_unix_timestamp();
  654.  
  655. postdata["a[" + i + "]"] = toScrobble[currentlyScrobbling].artist;
  656. postdata["t[" + i + "]"] = toScrobble[currentlyScrobbling].trackName;
  657. postdata["b[" + i + "]"] = getAlbum();
  658. postdata["n[" + i + "]"] = (currentlyScrobbling+1);
  659. postdata["l[" + i + "]"] = toScrobble[currentlyScrobbling].duration;
  660. postdata["i[" + i + "]"] = currTime-toScrobble[currentlyScrobbling].duration;
  661. postdata["o[" + i + "]"] = "P";
  662. postdata["r[" + i + "]"] = "";
  663. postdata["m[" + i + "]"] = "";
  664.  
  665.  
  666. postdata["s"] = sessID;
  667.  
  668. var postdataStr = "";
  669. var firstTime = true;
  670. for (currKey in postdata)
  671. {
  672. if (firstTime)
  673. {
  674. firstTime = false;
  675. } else
  676. {
  677. postdataStr = postdataStr + "&";
  678. }
  679. postdataStr = postdataStr + encodeURIComponent(currKey) + "=" + encodeURIComponent(postdata[currKey]);
  680. }
  681.  
  682. GM_xmlhttpRequest({
  683. method: 'POST',
  684. url: submitURL,
  685. data: postdataStr,
  686. headers: {
  687. 'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey',
  688. 'Content-type': 'application/x-www-form-urlencoded',
  689. },
  690. onload: acceptSubmitResponseSingle
  691. });
  692. }
  693.  
  694.  
  695.  
  696. function npNextTrack()
  697. {
  698.  
  699. var postdata = new Array();
  700.  
  701. var i = 0;
  702.  
  703. var currTime = fetch_unix_timestamp();
  704.  
  705. postdata["a"] = toScrobble[currentlyScrobbling].artist;
  706. postdata["t"] = toScrobble[currentlyScrobbling].trackName;
  707. postdata["b"] = getAlbum();
  708. postdata["n"] = (currentlyScrobbling+1);
  709. postdata["l"] = toScrobble[currentlyScrobbling].duration;
  710. postdata["m"] = "";
  711. postdata["s"] = sessID;
  712.  
  713. currTrackDuration = toScrobble[currentlyScrobbling].duration;
  714. currTrackPlayTime = 0;
  715.  
  716. document.getElementById("scrymblemarquee").innerHTML = toScrobble[currentlyScrobbling].trackName;
  717.  
  718.  
  719. var postdataStr = "";
  720. var firstTime = true;
  721. for (currKey in postdata)
  722. {
  723. if (firstTime)
  724. {
  725. firstTime = false;
  726. } else
  727. {
  728. postdataStr = postdataStr + "&";
  729. }
  730. postdataStr = postdataStr + encodeURIComponent(currKey) + "=" + encodeURIComponent(postdata[currKey]);
  731. }
  732.  
  733. GM_xmlhttpRequest({
  734. method: 'POST',
  735. url: npURL,
  736. data: postdataStr,
  737. headers: {
  738. 'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey',
  739. 'Content-type': 'application/x-www-form-urlencoded',
  740. },
  741. onload: acceptNPResponse
  742. });
  743. }
  744.  
  745. function timertick()
  746. {
  747. var again = true;
  748. if (currentlyScrobbling != -1)
  749. {
  750. var progbar = document.getElementById("progbar");
  751. if (currTrackDuration != 0)
  752. {
  753. progbar.style.width = "" + (100*currTrackPlayTime/currTrackDuration) + "%";
  754. }
  755.  
  756. currTrackPlayTime++;
  757.  
  758. if (currTrackPlayTime == currTrackDuration)
  759. {
  760. submitThisTrack();
  761.  
  762. again = false;
  763. }
  764.  
  765. }
  766. if (again)
  767. {
  768. window.setTimeout(timertick,1000);
  769. }
  770.  
  771. }
  772.  
  773. function acceptHandshakeSingle(responseDetails)
  774. {
  775. acceptHandshake(responseDetails, false);
  776. }
  777.  
  778. function acceptHandshakeBatch(responseDetails)
  779. {
  780. acceptHandshake(responseDetails, true);
  781. }
  782.  
  783. function acceptHandshake(responseDetails, isBatch)
  784. {
  785. if (responseDetails.status == 200)
  786. {
  787. var lines = responseDetails.responseText.split("\n");
  788. if (lines[0].indexOf("OK") == -1)
  789. {
  790. alert("handshake failed: " + responseDetails.status +
  791. ' ' + responseDetails.statusText + '\n\n' +
  792. 'Data:\n' + responseDetails.responseText);
  793. } else
  794. {
  795. sessID = lines[1];
  796. npURL = lines[2];
  797. submitURL = lines[3];
  798.  
  799. if (isBatch)
  800. {
  801. submitTracksBatch(sessID, submitURL);
  802. } else
  803. {
  804. npNextTrack();
  805. }
  806. }
  807. } else
  808. {
  809. alert("handshake failed: " + responseDetails.status +
  810. ' ' + responseDetails.statusText + '\n\n' +
  811. 'Data:\n' + responseDetails.responseText);
  812.  
  813. }
  814. }
  815.  
  816. function handshake(isBatch)
  817. {
  818. var user = document.getElementById("scrobbleusername").value;
  819. var password = document.getElementById("scrobblepassword").value;
  820. GM_setValue("user", user);
  821. GM_setValue("pass", password);
  822.  
  823. var timestamp = fetch_unix_timestamp();
  824. var auth = hex_md5(hex_md5(password) + timestamp);
  825.  
  826. var handshakeURL = "http://post.audioscrobbler.com/?hs=true&p=1.2&c=scr&v=1.0&u=" + user + "&t=" + timestamp + "&a=" + auth;
  827.  
  828.  
  829. GM_xmlhttpRequest({
  830. method: 'GET',
  831. url: handshakeURL,
  832. headers: {
  833. 'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey'
  834. },
  835. onload: (isBatch) ? acceptHandshakeBatch : acceptHandshakeSingle
  836. });
  837.  
  838. }
  839.  
  840. function handshakeSingle()
  841. {
  842. handshake(false);
  843. }
  844.  
  845. function handshakeBatch()
  846. {
  847. handshake(true);
  848. }
  849.  
  850. var eleTrackTable, eleButtonDiv, eleScrobbleNow, eleAllOrNone;
  851. eleTrackTable = document.getElementById('tracks');
  852.  
  853.  
  854. if (eleTrackTable) {
  855.  
  856. var n = 0;
  857. chkbox = '<span style="float:left;"><input type="checkbox" class="scrymblechk" id="chktrackNUM" checked="checked"></span>';
  858. $.each($("#tracks > .track > .tracklist_line"), function(){
  859. if ($(this).find('.tracklist_num:eq(0)').text() != '\n \n '){
  860. n++;
  861. $(this).prepend(chkbox.replace('NUM',n));
  862. }
  863. });
  864. }
  865.  
  866. eleButtonDiv = document.createElement('DIV');
  867. eleButtonDiv.innerHTML = "<table border='0' cellpadding='0' cellspacing='2'><tr><td width='105' ><input type='checkbox' name='allornone' id='allornone' style='vertical-align:middle' checked='checked'>&nbsp;<label for='allornone' style='font-size:60%'>select&nbsp;all/none</label><br/><table border='2' cellpadding='0' cellspacing='0'><tr><td style='height:50px;width:103px;background:url(http://cdn.last.fm/flatness/logo_black.3.png) no-repeat;color:#fff'><marquee scrollamount='3' scrolldelay='200' behavior='alternate' style='font-size:80%;font-family:sans-serif;position:relative;top:17px' id='scrymblemarquee'>&nbsp;</marquee></td></tr><tr><td style='background-color:#000033'><div style='position:relative;background-color:#ff0000;width:0%;max-height:5px;left:0px;top:0px;' id='progbar'>&nbsp;</div></td></tr></table></td><td>user: <input type='text' size='16' id='scrobbleusername' value = '"+ GM_getValue("user", "") + "' /><br />pass: <input type='password' size='16' id='scrobblepassword' value = '" + GM_getValue("pass", "") + "'></input><br /><input type='button' id='scrobblenow' value = 'Scrobble in real-time' /> <input type='button' id='scrobblethen' value = 'Scrobble a previous play' /></td></tr></table>";
  868. //eleButtonDiv.innerHTML = "<table border='2' cellpadding='0' cellspacing='2'><tr><td><img src='http://cdn.last.fm/flatness/logo_black.3.png'></td><td>user: <input type='text' size='10' id='scrobbleusername' value = '" + GM_getValue("user", "") + "'/><br />pass: <input type='password' size='10' id='scrobblepassword' value = '" + GM_getValue("pass", "") + "'/><br /><input type='button' id='scrobblenow' value='Scrobble!' /></td></tr></table>"
  869. eleButtonDiv.style.textAlign = "right";
  870.  
  871. var buttonDivParent = document.getElementById("h_album");
  872. //buttonDivParent.appendChild(eleButtonDiv);
  873. $(eleTrackTable).after(eleButtonDiv);
  874.  
  875. eleScrobbleNow = document.getElementById("scrobblenow");
  876. eleScrobbleNow.addEventListener("click", startScrobble, true);
  877.  
  878. eleAllOrNone = document.getElementById("allornone");
  879. eleAllOrNone.addEventListener("click", allOrNoneClick, true);
  880.  
  881. document.getElementById("scrobblethen").addEventListener("click", handshakeBatch, true);
  882.  
  883. window.addEventListener("beforeunload", confirmBrowseAway, true);
  884.  
  885.  
  886.  
  887.  
  888. function allOrNoneClick()
  889. {
  890. window.setTimeout(allOrNoneAction, 10);
  891. }
  892.  
  893. function allOrNoneAction()
  894. {
  895. var allnone = $("#allornone").is(':checked');
  896. $.each($(".scrymblechk"), function(){
  897. $(this).prop('checked', allnone);
  898. });
  899.  
  900. }
Add Comment
Please, Sign In to add comment