Pastebin is 300% more awesome when you are logged in. Sign Up, it's FREE!
Guest

Untitled

By: a guest on Dec 13th, 2010  |  syntax: JavaScript  |  size: 58.30 KB  |  hits: 55  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. // ==PREPROCESSOR==
  2. // @import "%fb2k_profile_path%scripts\common.js"
  3. // @import "%fb2k_profile_path%scripts\md5.js"
  4. // @import "%fb2k_profile_path%scripts\utf8encode.js"
  5. // @name "Biography, Last.fm main panel"
  6. // Required for other Last.fm panels
  7. // ==/PREPROCESSOR==
  8.  
  9. var username = utils.ReadINI(inifile, "default", "username", "");
  10. var api_key = utils.ReadINI(inifile, "default", "api_key", "");
  11. var lfm_secret = utils.ReadINI(inifile, "default", "secret", "");
  12. var lfm_sk = utils.ReadINI(inifile, "default", "session_key", "");
  13. var cache_life = utils.ReadINI(inifile, "default", "cache_life", 0);
  14. var data_folder = utils.ReadINI(inifile, "default", "data_folder", "/");
  15. var proxy_file = script_path + "wget.ini";
  16. var languages = new Array("English", "日本語", "Deutsch", "Español", "Français", "Italiano", "Polski", "Português", "Руccкий", "Türkçe", "Svenska", "简体中文");
  17. var langs = new Array("en", "jp", "de", "es", "fr", "it", "pl", "pt", "ru", "tr", "sv", "zh");
  18. var lang = langs[window.GetProperty("language",100) - 100];
  19. var artist = alartist = album = title = lastfm_artist = lastfm_artist_url = p_title = '';
  20. var p_title_width = 0;
  21. var p_title_need_calc = true;
  22. var lfm_token = '';
  23. var g_text = '';
  24. var trackxml = '';
  25. var working = 0;
  26. var simartist_height = 0;
  27. var simartists_height = 0;
  28. var simartists = [];
  29. var simartist_widths = [];
  30. var simartist_urls = [];
  31. var simartist_urls_ori = [];
  32. var sc_cache = [];
  33. var scrobbling = lfm_np_updating = false;
  34. var sc_np_timer = null;
  35. var sc_cache_file = fb.ProfilePath + "wsh_lfm_scrobble_cache.txt";
  36. var need_calc_simartists_dim = true;
  37. var g_drag = false;
  38. var g_drag_y = 0;
  39. var g_need_calc = true;
  40. var g_offset = 0;
  41. var g_textheight = 0;
  42. var defoffset = 51;
  43. var start_y = 0;
  44. var dlartistart = false;
  45. var startplay = true;
  46. var token_timer = null;
  47. var pf = fb.CreateProfiler("");
  48. var pb_time = 0;
  49. var playing = pausing = false;
  50. var useragent = "thuan's foobar2000 lastfm wsh panels";
  51. var g_tooltip = window.CreateTooltip();
  52. var sc_hint_font = gdi.Font(font, 9, 0);
  53. var p_title_font = gdi.Font(font, 16, 1);
  54. g_tooltip.SetMaxWidth(600);
  55.  
  56. window.GetProperty("auto", true);
  57. window.GetProperty("artistartcacherefresh", true);
  58. window.GetProperty("offline", false);
  59.  
  60. window.GetProperty("scrobble", false);
  61. window.GetProperty("onlymlfile", false);
  62. window.GetProperty("walbum", true);
  63. window.GetProperty("walbumartist", true);
  64. window.GetProperty("wduration", true);
  65. window.GetProperty("wtracknumber", true);
  66.  
  67. var limit = window.GetProperty("limit", 305) - 300;
  68. var artistartsizes = ["Original", "Small", "Medium", "Large square", "Large", "Extra large"];
  69. var artistartsizetext = ["original", "small", "medium", "largesquare", "large", "extralarge"];
  70. var artistartsize = artistartsizetext[window.GetProperty("artistartsize",400) - 400];
  71.  
  72. var tf_artist = utils.ReadINI(inifile, "scrobbler", "tf_artist", "%artist%");
  73. var tf_title = utils.ReadINI(inifile, "scrobbler", "tf_title", "$meta(title)");
  74.  
  75. cache_life = (!cache_life.match(/^(\d+)$/)) ? 0 : (parseInt(cache_life) * 86400000);
  76.  
  77. if (window.GetProperty("scrobble")) sc_cache_restore();
  78.  
  79. function on_notify_data(name, data) {
  80.     if (name == "getplayinginfo" && !window.GetProperty("offline")) {
  81.         get_playing_track_info(data[0], data[1]);
  82.     }
  83.     if (name == "getlastfmchart") {
  84.         refreshlastfmchart = false;
  85.         get_lastfm_chart(data[0], data[1], data[2], data[3]);
  86.     }
  87.     if (name == "refreshlastfmchart") {
  88.         refreshlastfmchart = true;
  89.         get_lastfm_chart(data[0], data[1], data[2], data[3]);
  90.     }
  91.     if (name == "getrecenttracks") {
  92.         if (!window.GetProperty("offline"))
  93.         get_recent_tracks();
  94.         else
  95.         window.NotifyOthers("recenttracks", "offline");
  96.     }
  97.     if (name == "getartistart") {
  98.         dlartistart = true;
  99.         load();
  100.         dlartistart = false;
  101.     }
  102.     if (name == "altlastfmlovedstate") {
  103.         alt_lastfm_loved_state(data[0], data[1], data[2]);
  104.     }
  105. }
  106.  
  107. function on_timer(timer_id) {
  108.     if (token_timer && token_timer.ID == timer_id) {
  109.         window.KillTimer(token_timer) && token_timer.Dispose();
  110.         lfm_token = "";
  111.     }
  112.     if (sc_np_timer && sc_np_timer.ID == timer_id) {
  113.         window.KillTimer(sc_np_timer) && sc_np_timer.Dispose();
  114.         /*fb.trace("NP Total " + sc_cache.length + ":")
  115.         for (i in sc_cache) {
  116.             fb.trace(i + ":")
  117.             fb.trace(sc_cache[i].join("\n"));
  118.         }*/
  119.         if (fb.IsPlaying && !lfm_np_updating && !window.GetProperty("offline")) {
  120.             lfm_np_updating = true;
  121.             set_lfm_np(sc_cache.slice());
  122.         }
  123.     }
  124. }
  125.  
  126. function on_size() {
  127.     ww = window.Width;
  128.     wh = window.Height;
  129.     reset();
  130. }
  131.  
  132. function on_script_unload() {
  133.     if (window.GetProperty("scrobble")) sc_cache_save();
  134. }
  135.  
  136. function on_paint(gr) {
  137.     gr.FillSolidRect( 0, 0, ww, wh, g_backcolor);
  138.     if(username.length == 0 || api_key.length != 32) {
  139.         gr.GdiDrawText("Please use the context menu to set your Last.fm username and API KEY.", g_font, g_textcolor, 0, 0, ww, wh, DT_VCENTER | DT_CENTER | DT_WORDBREAK | DT_CALCRECT | DT_NOPREFIX);
  140.     } else if(fb.IsPlaying) {
  141.         if (g_need_calc) {
  142.             calc(g_text, g_font, 6, 40, ww-16, wh - defoffset);
  143.         }
  144.         if (need_calc_simartists_dim) calc_simartists_dim();
  145.         if (simartists_height > 0) {
  146.             start_y = 40 + g_textheight - simartists_height + g_offset;
  147.         }
  148.         gr.GdiDrawText(g_text, g_font, g_textcolor, 6, g_offset + 40, ww-16, wh - g_offset - defoffset, DT_WORDBREAK | DT_NOPREFIX);
  149.         gr.FillSolidRect(0, 0, ww, 40, g_backcolor);
  150.         gr.FillSolidRect(0, wh-11, ww, 11, g_backcolor);
  151.         if (g_textheight > wh - defoffset) {
  152.             if (g_offset == 0) {
  153.                 gr.GdiDrawText("▼", sc_hint_font, g_textcolor, 0, wh-12, ww, 12, DT_TOP | DT_CENTER | DT_NOPREFIX);
  154.             }
  155.             if (g_offset < 0 && g_offset > -g_textheight + wh - defoffset) {
  156.                 gr.GdiDrawText("▲", sc_hint_font, g_textcolor, 0, 28, ww, 12, DT_TOP | DT_CENTER);
  157.                 gr.GdiDrawText("▼", sc_hint_font, g_textcolor, 0, wh-12, ww, 12, DT_TOP | DT_CENTER);
  158.             }
  159.             if (g_offset == -g_textheight + wh - defoffset) {
  160.                 gr.GdiDrawText("▲", sc_hint_font, g_textcolor, 0, 28, ww, 12, DT_TOP | DT_CENTER);
  161.             }
  162.         }
  163.         if (p_title_need_calc) {
  164.             p_title_width = gr.CalcTextWidth(p_title, p_title_font);
  165.             p_title_width = (p_title_width > ww-12) ? ww-12 : p_title_width;
  166.             p_title_need_calc = false;
  167.         }
  168.         gr.GdiDrawText(p_title, p_title_font, g_textcolor_hl, 6, 6, ww-12, 24, DT_VCENTER  | DT_END_ELLIPSIS | DT_CALCRECT | DT_NOPREFIX);
  169.         gr.DrawLine(10, 29, ww-20, 29, 1, g_textcolor_hl);
  170.         gr.FillGradRect(5, 29,10, 1, 0, RGB(255,255,255), g_textcolor_hl);
  171.         gr.FillGradRect(ww-20, 29,10, 1, 0, g_textcolor_hl,RGB(255,255,255));
  172.     } else {
  173.         gr.GdiDrawText("[playback stopped]", g_font, g_textcolor, 0, 0, ww, wh, DT_VCENTER | DT_CENTER | DT_WORDBREAK | DT_CALCRECT | DT_NOPREFIX);
  174.     }
  175. }
  176.  
  177. function on_playback_new_track(mdb) {
  178.     playing = true;
  179.     if (!pausing) pb_time += pf.Time;
  180.     pausing = false;
  181.     pb_time = Math.round(pb_time / 1000);
  182.     if (sc_cache.length > 0) {
  183.         if (window.GetProperty("scrobble")) {
  184.             entry = sc_cache[sc_cache.length-1];
  185.             if (pb_time <= 5 || entry[0] == -1)
  186.             sc_cache.pop();
  187.             else {
  188.                 if (entry.length == 9) entry.push(pb_time);
  189.                 if (!scrobbling && !window.GetProperty("offline")) {
  190.                     //fb.trace("==============scrobble=======");
  191.                     scrobbling = true;
  192.                     lastfm_scrobble(get_sc_list());
  193.                 }
  194.             }
  195.         } else sc_cache.pop();
  196.     }
  197.     pb_time = 0;
  198.     pf.Reset();
  199.     sc_cache_add(mdb, pb_start_time = Math.round(Date.parse(Date()) / 1000));
  200.  
  201.     g_metadb && g_metadb.Dispose();
  202.     g_metadb = mdb;
  203.     alartist = fb.TitleFormat("%album artist%").EvalWithMetadb(g_metadb);
  204.     album = fb.TitleFormat("%album%").EvalWithMetadb(g_metadb);
  205.     title = fb.TitleFormat("%title%").EvalWithMetadb(g_metadb);
  206.     if (startplay) {
  207.         artist = fb.TitleFormat("%artist%").EvalWithMetadb(g_metadb);
  208.         load();
  209.         return;
  210.     }
  211.     if (artist == fb.TitleFormat("%artist%").EvalWithMetadb(g_metadb)) return;
  212.     artist = fb.TitleFormat("%artist%").EvalWithMetadb(g_metadb);
  213.     load();
  214. }
  215.  
  216. function on_playback_seek() {
  217.     pb_time += pf.Time;
  218.     pf.Reset();
  219. }
  220.  
  221. function on_playback_pause(state) {
  222.     if (state) {
  223.         pb_time += pf.Time;
  224.         if (pb_time <= 5000)
  225.             sc_np_timer && window.KillTimer(sc_np_timer) && sc_np_timer.Dispose();
  226.         pausing = true;
  227.     } else {
  228.         if (pb_time <= 5000)
  229.             sc_np_timer = window.CreateTimerTimeout(5000 - pb_time);
  230.         pausing = false;
  231.         pf.Reset();
  232.     }
  233. }
  234.  
  235. function on_playback_edited() {
  236.     if (artist != fb.TitleFormat("%artist%").EvalWithMetadb(g_metadb)) load();
  237.     if (!window.GetProperty("scrobble")) return;
  238.     if (artist != fb.TitleFormat("%artist%").EvalWithMetadb(g_metadb) || alartist != fb.TitleFormat("%album artist%").EvalWithMetadb(g_metadb) || album != fb.TitleFormat("%album%").EvalWithMetadb(g_metadb) || title != fb.TitleFormat("%title%").EvalWithMetadb(g_metadb)) {
  239.         artist = fb.TitleFormat(tf_artist).EvalWithMetadb(g_metadb);
  240.         alartist = fb.TitleFormat("%album artist%").EvalWithMetadb(g_metadb);
  241.         album = fb.TitleFormat("%album%").EvalWithMetadb(g_metadb);
  242.         title = fb.TitleFormat(tf_title).EvalWithMetadb(g_metadb);
  243.         entry = sc_cache[sc_cache.length-1];
  244.         entry[1] = false;
  245.         entry[3] = album;
  246.         entry[4] = alartist;
  247.         entry[5] = artist;
  248.         entry[7] = title;
  249.         if (!lfm_np_updating && !window.GetProperty("offline")) {
  250.             lfm_np_updating = true;
  251.             set_lfm_np(sc_cache.slice());
  252.         }
  253.     }
  254. }
  255.  
  256. function on_playback_stop(reason) {
  257.     if (reason == 0) startplay = true;
  258.     if (reason != 2) {
  259.         sc_np_timer && window.KillTimer(sc_np_timer) && sc_np_timer.Dispose();
  260.         if (reason != 3) playing = false;
  261.         if (!pausing) pb_time += pf.Time;
  262.         pausing = false;
  263.         pb_time = Math.round(pb_time / 1000);
  264.         if (window.GetProperty("scrobble")) {
  265.             entry = sc_cache[sc_cache.length-1];
  266.             if (pb_time <= 5 || entry[0] == -1)
  267.             sc_cache.pop();
  268.             else {
  269.                 if (entry.length == 9) entry.push(pb_time);
  270.             }
  271.         } else sc_cache.pop();
  272.         window.Repaint();
  273.     }
  274. }
  275.  
  276. function get_playing_track_info(tartist, ttitle) {
  277.     if (username.length == 0 || api_key.length != 32) return(fb.trace("Can't contact Last.fm. Check your username / API KEY settings."));
  278.     var listeners = 0;
  279.     var playcount = 0;
  280.     var userplaycount = 0;
  281.     var userloved = 0;
  282.     var lfm_artist = '';
  283.     var lfm_track = '';
  284.     trackxmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
  285.     qs = "&method=track.getinfo&autocorrect=1&username=" + username + "&artist=" + encodeURIComponent(tartist) + "&track=" + encodeURIComponent(ttitle);
  286.     trackxmlhttp.open("GET", "http://ws.audioscrobbler.com/2.0/?api_key=" + api_key + "&user=" + username + qs + "&s=" + Math.random(), true);
  287.     trackxmlhttp.setRequestHeader('User-Agent', useragent);
  288.     trackxmlhttp.send();
  289.     trackxmlhttp.onreadystatechange = function() {
  290.         if (trackxmlhttp.readyState == 4) {
  291.             if (trackxmlhttp.status == 200) {
  292.                 trackxml = trackxmlhttp.responseText;
  293.                 var trackxmldom= new ActiveXObject("Microsoft.XMLDOM");
  294.                 trackxmldom.async="false";
  295.                 trackxmldom.loadXML(trackxml);
  296.                 try {
  297.                     lfm_artist = trackxmldom.getElementsByTagName("artist")[0].childNodes[0].childNodes[0].nodeValue;
  298.                 } catch (e) {};
  299.                 try {
  300.                     lfm_track = trackxmldom.getElementsByTagName("track")[0].childNodes[1].childNodes[0].nodeValue;
  301.                 } catch (e) {};
  302.                 try {
  303.                     listeners = trackxmldom.getElementsByTagName("listeners")[0].childNodes[0].nodeValue;
  304.                 } catch (e) {};
  305.                 try {
  306.                     playcount = trackxmldom.getElementsByTagName("playcount")[0].childNodes[0].nodeValue;
  307.                 } catch (e) {};
  308.                 try {
  309.                     userplaycount = trackxmldom.getElementsByTagName("userplaycount")[0].childNodes[0].nodeValue;
  310.                 } catch (e) {};
  311.                 try {
  312.                     userloved = trackxmldom.getElementsByTagName("userloved")[0].childNodes[0].nodeValue;
  313.                 } catch (e) {};
  314.             } else {
  315.                 fb.trace(trackxmlhttp.responseText);
  316.             }
  317.             window.NotifyOthers("playingtrack", [lfm_artist, lfm_track, listeners, playcount, userplaycount, userloved]);
  318.         }
  319.     }
  320. }
  321.  
  322. function get_lastfm_chart(method, type, period, charts_folder) {
  323.     if(username.length == 0 || api_key.length != 32) return(fb.trace("Last.fm Charts: Can't contact Last.fm. Check your username / API KEY settings."));
  324.     top_el = method.substring(3).toLowerCase();
  325.     filename = charts_folder + "\\" + username+ "_" + type + "_" + period + ".xml";
  326.     ranks = new Array();
  327.     names = new Array();
  328.     name_widths = new Array();
  329.     tt_texts = new Array();
  330.     playcounts = new Array();
  331.     urls = new Array();
  332.     artists = new Array();
  333.     if(fso.fileExists(filename)) {
  334.         file = fso.Getfile(filename);
  335.         if((refreshlastfmchart || (Date.parse(Date()) - Date.parse(file.DateLastModified) > 86400000)) && !window.GetProperty("offline")) {
  336.             refreshlastfmchart = false;
  337.             lastfm("&user=" + username + "&method=user." + method + "&period=" + period, useragent, function() {save_xml_file(filename); get_lastfm_chart(method, type, period, charts_folder);});
  338.             return;
  339.         }
  340.         chartxml = utils.ReadTextFile(filename);
  341.         if(chartxml.length > 0) {
  342.             var temp_bmp = gdi.CreateImage(1, 1);
  343.             var temp_gr = temp_bmp.GetGraphics();
  344.             var xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
  345.             xmlDoc.async="false";
  346.             xmlDoc.loadXML(chartxml);
  347.             try {
  348.                 var tops = xmlDoc.getElementsByTagName(top_el)[0];
  349.                 for(i = 0; i < tops.childNodes.length; i++) {
  350.                     var top = tops.childNodes[i];
  351.                     ranks[i] = top.getAttribute("rank");
  352.                     for(j = 0; j < top.childNodes.length; j++) {
  353.                         if(top.childNodes[j].tagName == "url") urls[i] = top.childNodes[j].childNodes[0].nodeValue;
  354.                         if(top.childNodes[j].tagName == "name") names[i] = top.childNodes[j].childNodes[0].nodeValue;
  355.                         if(top.childNodes[j].tagName == "playcount") playcounts[i] = top.childNodes[j].childNodes[0].nodeValue;
  356.                         if(i > 0 && playcounts[i] == playcounts[i -1]) ranks[i] = ranks[i -1];
  357.                         if(type != 0 && top.childNodes[j].tagName == "artist") {
  358.                             artists[i] = top.childNodes[j].childNodes[0].childNodes[0].nodeValue;
  359.                         }
  360.                     }
  361.                     tt_texts[i] = ((artists.length > 0) ? artists[i] + " - " : "") + names[i];
  362.                     name_widths[i] = temp_gr.CalcTextWidth(names[i], g_font);
  363.                 }
  364.                 window.NotifyOthers("lastfmchart", [ranks, names, name_widths, tt_texts, playcounts, urls]);
  365.             } catch (e) {
  366.                 window.NotifyOthers("lastfmchart", [[], [], [], [], [], []]);
  367.             }
  368.             temp_bmp.ReleaseGraphics(temp_gr);
  369.             temp_bmp.Dispose();
  370.             temp_gr = null;
  371.             temp_bmp = null;
  372.         }
  373.     } else if (!window.GetProperty("offline")){
  374.         lastfm("&user=" + username + "&method=user." + method + "&period=" + period, useragent, function() {save_xml_file(filename); get_lastfm_chart(method, type, period, charts_folder);});
  375.     } else window.NotifyOthers("lastfmchart", [[], [], [], [], [], []]);
  376. }
  377.  
  378. function get_recent_tracks() {
  379.     if(username.length == 0 || api_key.length != 32) return(fb.trace("Last.fm Charts: Can't contact Last.fm. Check your username / API KEY settings."));
  380.     var ret = "";
  381.     recentxmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
  382.     recentxmlhttp.open("GET", "http://ws.audioscrobbler.com/2.0/?api_key=" + api_key + "&user=" + username + "&method=user.getrecenttracks&limit=20" + "&s=" + Math.random(), true);
  383.     recentxmlhttp.setRequestHeader('User-Agent',useragent);
  384.     recentxmlhttp.send();
  385.     recentxmlhttp.onreadystatechange = function() {
  386.         if (recentxmlhttp.readyState == 4) {
  387.             if (recentxmlhttp.status == 200) {
  388.                 recentxml = recentxmlhttp.responseText;
  389.                 var recentxmldom = new ActiveXObject("Microsoft.XMLDOM");
  390.                 recentxmldom.async="false";
  391.                 recentxmldom.loadXML(recentxml);
  392.                 try {
  393.                     tracks = recentxmldom.getElementsByTagName("name");
  394.                     artists = recentxmldom.getElementsByTagName("artist");
  395.                     for (i = 0; i < tracks.length; i++) {
  396.                         ret += zeroPad((i + 1),2) + ". " + tracks[i].childNodes[0].nodeValue + "\n";
  397.                         ret += "      By " + artists[i].childNodes[0].nodeValue;
  398.                         if (i < tracks.length - 1) ret += "\n";
  399.                     }
  400.                 } catch(e) {
  401.                     ret = "User " + username + " does not have a recent track information on Last.fm.";
  402.                 }
  403.             } else ret = "User " + username + " does not have a recent track information on Last.fm.";
  404.             window.NotifyOthers("recenttracks", ret);
  405.         }
  406.     }
  407. }
  408.  
  409. function get_lastfm_token(func) {
  410.     lfmtokenxmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
  411.     lfmtokenxmlhttp.open("GET", "http://ws.audioscrobbler.com/2.0/?api_key=" + api_key + "&method=auth.getToken" + "&s=" + Math.random(), true);
  412.     lfmtokenxmlhttp.setRequestHeader('User-Agent',useragent);
  413.     lfmtokenxmlhttp.send();
  414.     lfmtokenxmlhttp.onreadystatechange = function() {
  415.         if (lfmtokenxmlhttp.readyState == 4) {
  416.             if (lfmtokenxmlhttp.status == 200) {
  417.                 lfmtokenxml = lfmtokenxmlhttp.responseText;
  418.                 var lfmtokenxmldom = new ActiveXObject("Microsoft.XMLDOM");
  419.                 lfmtokenxmldom.async="false";
  420.                 lfmtokenxmldom.loadXML(lfmtokenxml);
  421.                 try {
  422.                     lfm_token = lfmtokenxmldom.getElementsByTagName("token")[0].childNodes[0].nodeValue;
  423.                     token_timer && window.KillTimer(token_timer) && token_timer.Dispose();
  424.                     token_timer = window.CreateTimerTimeout(3600000);
  425.                     get_lastfm_sk(func);
  426.                 } catch (e) {
  427.                     fb.trace(lfmtokenxml);
  428.                 }
  429.             } else {
  430.                 fb.trace(lfmtokenxmlhttp.responseText);
  431.                 fb.ShowPopupMessage("Unable to get last.fm token. Please check foobar2000 console for furthur information.");
  432.             }
  433.         }
  434.     }
  435. }
  436.  
  437. function get_lastfm_sk(func) {
  438.     if (api_key.length != 32) return(fb.ShowPopupMessage("Can't contact Last.fm. Check your username / API KEY settings."));
  439.     if (lfm_secret == "") return(fb.ShowPopupMessage("Last.fm secret missing, please reenter your last.fm secret in bio panel then try again."));
  440.     if (lfm_token == "") {
  441.         get_lastfm_token(func);
  442.         return;
  443.     }
  444.     WshShell.Run("\"" + lfm_auth_vbs + "\" http://www.last.fm/api/auth/?api_key=" + api_key + "&token=" + lfm_token, 0, true);
  445.     var api_sig = md5("api_key" + api_key + "methodauth.getSessiontoken" + lfm_token + lfm_secret);
  446.     lfmskxmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
  447.     lfmskxmlhttp.open("GET", "http://ws.audioscrobbler.com/2.0/?api_key=" + api_key + "&method=auth.getSession&token=" + lfm_token + "&api_sig=" + api_sig, true);
  448.     lfmskxmlhttp.setRequestHeader('User-Agent',useragent);
  449.     lfmskxmlhttp.send();
  450.     lfmskxmlhttp.onreadystatechange = function() {
  451.         if (lfmskxmlhttp.readyState == 4) {
  452.             if (lfmskxmlhttp.status == 200) {
  453.                 lfmskxml = lfmskxmlhttp.responseText;
  454.                 var lfmskxmldom = new ActiveXObject("Microsoft.XMLDOM");
  455.                 lfmskxmldom.async="false";
  456.                 lfmskxmldom.loadXML(lfmskxml);
  457.                 try {
  458.                     lfm_sk = lfmskxmldom.getElementsByTagName("key")[0].childNodes[0].nodeValue;
  459.                     utils.WriteINI(inifile, "default", "session_key", lfm_sk);
  460.                     fb.trace("Last.fm authentication complete");
  461.                     func();
  462.                 } catch (e) {
  463.                     fb.trace(lfmskxml);
  464.                 }
  465.             } else {
  466.                 fb.trace(lfmskxmlhttp.responseText);
  467.                 fb.ShowPopupMessage("Unable to get last.fm session key. Please check foobar2000 console for furthur information.");
  468.             }
  469.         }
  470.     }
  471. }
  472.  
  473. function alt_lastfm_loved_state(artist, track, love) {
  474.     if (api_key.length != 32) return(fb.ShowPopupMessage("Can't contact Last.fm. Check your username / API KEY settings."));
  475.     if (lfm_secret == "") return(fb.ShowPopupMessage("Last.fm secret missing, please reenter your last.fm secret in bio panel then try again."));
  476.     if (lfm_sk == "") {
  477.         get_lastfm_sk(function() {alt_lastfm_loved_state(artist, track, love)});
  478.         return;
  479.     }
  480.     var method = love ? "track.love" : "track.unlove";
  481.     var api_sig = md5("api_key" + api_key + "artist" + artist + "method" + method + "sk" + lfm_sk + "track" + track + lfm_secret);
  482.     lfmaltlovehttp = new ActiveXObject("Microsoft.XMLHTTP");
  483.     lfmaltlovehttp.open("POST", "http://ws.audioscrobbler.com/2.0/", true);
  484.     lfmaltlovehttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  485.     lfmaltlovehttp.setRequestHeader('User-Agent',useragent);
  486.     lfmaltlovehttp.send("api_key=" + api_key + "&method=" + method + "&api_sig=" + api_sig + "&artist=" + encodeURIComponent(artist) + "&track=" + encodeURIComponent(track) + "&sk=" + lfm_sk);
  487.     lfmaltlovehttp.onreadystatechange = function() {
  488.         if (lfmaltlovehttp.readyState == 4) {
  489.             if (lfmaltlovehttp.status == 200) {
  490.                 window.NotifyOthers("lastfmlovedstate", love);
  491.             } else {
  492.                 fb.trace(lfmaltlovehttp.responseText);
  493.             }
  494.         }
  495.     }
  496. }
  497.  
  498. function sc_cache_save() {
  499.     ts = fso.OpenTextFile(sc_cache_file, 2, true, -1);
  500.     if (playing) {
  501.         if (!pausing) pb_time += pf.Time;
  502.         pb_time = Math.round(pb_time / 1000);
  503.         if (window.GetProperty("scrobble")) {
  504.             entry = sc_cache[sc_cache.length-1];
  505.             if (pb_time <= 5 || entry[0] == -1)
  506.             sc_cache.pop();
  507.             else {
  508.                 if (entry.length == 9) entry.push(pb_time);
  509.             }
  510.         } else sc_cache.pop();
  511.     }
  512.     var sc_cache_str = "";
  513.     for (i in sc_cache) {
  514.         entry = sc_cache[i];
  515.         if (entry[0] != -1 && entry.length == 10) {
  516.             sc_cache_str += entry.join(String.fromCharCode(31));
  517.             sc_cache_str += String.fromCharCode(30);
  518.         }
  519.     }
  520.     ts.Write(sc_cache_str);
  521.     ts.Close();
  522. }
  523.  
  524. function sc_cache_restore() {
  525.     var sc_cache_str = utils.ReadTextFile(sc_cache_file, 1200);
  526.     if (sc_cache_str) {
  527.         var entries = sc_cache_str.split(String.fromCharCode(30));
  528.         for (i in entries) {
  529.             if (entries[i]) {
  530.                 entry = (entries[i]).split(String.fromCharCode(31));
  531.                 sc_cache.push(entry);
  532.             }
  533.         }
  534.         /*fb.trace("SC Total " + sc_cache.length + ":")
  535.         for (i in sc_cache) {
  536.             fb.trace(i + ":")
  537.             fb.trace(sc_cache[i].join("\n"));
  538.         }*/
  539.         if (!lfm_np_updating && !window.GetProperty("offline")) {
  540.             lfm_np_updating = true;
  541.             set_lfm_np(sc_cache.slice());
  542.         }
  543.         //lastfm_scrobble(get_sc_list());
  544.     }
  545. }
  546.  
  547. function sc_cache_add(mdb, timestamp) {
  548.     var ID;
  549.     if (window.GetProperty("onlymlfile")) {
  550.         if (fb.IsMetadbInMediaLibrary(mdb))
  551.         ID = Math.random();
  552.         else
  553.         ID = -1;
  554.     } else
  555.     ID = Math.random();
  556.  
  557.     var track = fb.TitleFormat(tf_title).EvalWithMetadb(mdb);
  558.     var artist = fb.TitleFormat(tf_artist).EvalWithMetadb(mdb);
  559.     var album = fb.TitleFormat("%album%").EvalWithMetadb(mdb);
  560.     var albumArtist = fb.TitleFormat("%album artist%").EvalWithMetadb(mdb);
  561.     var trackNumber = fb.TitleFormat("$meta(tracknumber)").EvalWithMetadb(mdb);
  562.     var duration = Math.round(fb.PlaybackLength);
  563.     sc_cache.push([ID, false, timestamp, album, albumArtist, artist, duration, track, trackNumber]);
  564.     if (window.GetProperty("scrobble")) {
  565.         sc_np_timer && window.KillTimer(sc_np_timer) && sc_np_timer.Dispose();
  566.         sc_np_timer = window.CreateTimerTimeout(5000);
  567.     }
  568. }
  569.  
  570. function sc_cache_update(ID, album, albumArtist, artist, track) {
  571.     for (i = 0; i < sc_cache.length; i++) {
  572.         entry = sc_cache[i];
  573.         if (ID == entry[0]) {
  574.             entry[1] = true;
  575.             if (album) entry[3] = album;
  576.             if (albumArtist && albumArtist != entry[4]) entry[4] = albumArtist;
  577.             if (artist) entry[5] = artist;
  578.             if (track) entry[7] = track;
  579.         }
  580.         //fb.trace(entry.join("\n"))
  581.     }
  582. }
  583.  
  584. function sc_cache_remove(ID) {
  585.     for (i = 0; i < sc_cache.length; i++) {
  586.         entry = sc_cache[i];
  587.         if (ID == entry[0]) sc_cache.splice(i, 1);
  588.     }
  589. }
  590.  
  591. function set_lfm_np(entries) {
  592.     if (api_key.length != 32) return(fb.ShowPopupMessage("Can't contact Last.fm. Check your username / API KEY settings."));
  593.     if (lfm_secret == "") return(fb.ShowPopupMessage("Last.fm secret missing, please reenter your last.fm secret in bio panel then try again."));
  594.     if (lfm_sk == "") {
  595.         get_lastfm_sk(function() {set_lfm_np(entries)});
  596.         return;
  597.     }
  598.     if (entries.length == 0) {
  599.         lfm_np_updating = false;
  600.         return;
  601.     }
  602.  
  603.     var entry = entries.shift();
  604.  
  605.     if (entry[1]) {
  606.         set_lfm_np(entries);
  607.         return;
  608.     }
  609.  
  610.     //fb.trace("=======================called set_lfm_np========")
  611.  
  612.     var ID = entry[0];
  613.     var artist = entry[5];
  614.     var track = entry[7];
  615.     if (track == "" || artist == "?" || track == "?" || artist == "") {
  616.         set_lfm_np(entries);
  617.         return(fb.trace("Track tags are incomplete, unable to set last.fm now playing."));
  618.     }
  619.     var album = entry[3];
  620.     var albumArtist = entry[4];
  621.     var duration = entry[6];
  622.     var trackNumber = entry[8];
  623.     var api_sig_raw = "";
  624.     var qs = "";
  625.     if (album != "?" && window.GetProperty("walbum")) {
  626.         api_sig_raw += "album" + album;
  627.         qs += "album=" + encodeURIComponent(album);
  628.     }
  629.     if (albumArtist != "?" && albumArtist != artist && window.GetProperty("walbumartist")) {
  630.         api_sig_raw += "albumArtist" + albumArtist;
  631.         qs += "&albumArtist=" + encodeURIComponent(albumArtist);
  632.     }
  633.     api_sig_raw += "api_key" + api_key;
  634.     qs += "&api_key=" + api_key;
  635.     api_sig_raw += "artist" + artist;
  636.     qs += "&artist=" + encodeURIComponent(artist);
  637.     if (duration != 0 && window.GetProperty("wduration")) {
  638.         api_sig_raw += "duration" + duration;
  639.         qs += "&duration=" + duration;
  640.     }
  641.     api_sig_raw += "methodtrack.updateNowPlaying" + "sk" + lfm_sk;
  642.     qs += "&method=track.updateNowPlaying" + "&sk=" + lfm_sk;
  643.     api_sig_raw += "track" + track;
  644.     qs += "&track=" + encodeURIComponent(track);
  645.     if (trackNumber != "" && window.GetProperty("wtracknumber")) {
  646.         api_sig_raw += "trackNumber" + trackNumber;
  647.         qs += "&trackNumber=" + trackNumber;
  648.     }
  649.     api_sig_raw += lfm_secret
  650.     var api_sig = md5(api_sig_raw);
  651.     qs += "&api_sig=" + api_sig;
  652.  
  653.     //fb.trace(qs)
  654.  
  655.     lfmsetnphttp = new ActiveXObject("Microsoft.XMLHTTP");
  656.     lfmsetnphttp.open("POST", "http://ws.audioscrobbler.com/2.0/", true);
  657.     lfmsetnphttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  658.     lfmsetnphttp.setRequestHeader('User-Agent',useragent);
  659.     lfmsetnphttp.send(qs);
  660.     lfmsetnphttp.onreadystatechange = function() {
  661.         if (lfmsetnphttp.readyState == 4) {
  662.             if (lfmsetnphttp.status == 200) {
  663.                 lfmsetnpxml = lfmsetnphttp.responseText;
  664.                 var lfmsetnpdom = new ActiveXObject("Microsoft.XMLDOM");
  665.                 lfmsetnpdom.async="false";
  666.                 lfmsetnpdom.loadXML(lfmsetnpxml);
  667.                 var t_artist = t_track = t_album = t_albumArtist = "";
  668.                 try {
  669.                     t_artist = lfmsetnpdom.getElementsByTagName("artist")[0].childNodes[0].nodeValue;
  670.                 } catch (e) {}
  671.                 try {
  672.                     t_track = lfmsetnpdom.getElementsByTagName("track")[0].childNodes[0].nodeValue;
  673.                 } catch (e) {}
  674.                 try {
  675.                     t_album = lfmsetnpdom.getElementsByTagName("album")[0].childNodes[0].nodeValue;
  676.                 } catch (e) {}
  677.                 try {
  678.                     t_albumArtist = lfmsetnpdom.getElementsByTagName("albumArtist")[0].childNodes[0].nodeValue;
  679.                 } catch (e) {}
  680.                 sc_cache_update(ID, t_album, t_albumArtist, t_artist, t_track)
  681.                 if (entries.length == 0 && fb.IsPlaying) fb.trace("Last.fm submission: Now playing... OK");
  682.                 set_lfm_np(entries);
  683.             } else {
  684.                 fb.trace(lfmsetnphttp.responseText);
  685.                 set_lfm_np(entries);
  686.             }
  687.         }
  688.     }
  689. }
  690.  
  691. function get_sc_list() {
  692.     var sc_list = [];
  693.     var sc_batch = [];
  694.     var discards = [];
  695.     var c = 0;
  696.     for (i = 0; i < sc_cache.length; i++) {
  697.         entry = sc_cache[i];
  698.         if (entry[1] && entry.length == 10) {
  699.             switch (true) {
  700.             case (entry[0] == -1):
  701.             case (entry[6] < 30):
  702.             case (entry[9] < 240 && entry[9] < Math.floor(entry[6] / 2)):
  703.             case (entry[5] == "" || entry[7] == "" || entry[5] == "?" || entry[7] == "?"):
  704.                 discards.push(entry[0]);
  705.                 break;
  706.             default:
  707.                 sc_batch.push(entry);
  708.                 c++;
  709.                 if (c == 50) {
  710.                     sc_list.push(sc_batch.slice());
  711.                     sc_batch = [];
  712.                     c = 0;
  713.                 }
  714.             }
  715.         }
  716.     }
  717.     sc_list.push(sc_batch);
  718.     while (discards.length > 0) {
  719.         sc_cache_remove(discards.shift());
  720.     }
  721.     return sc_list;
  722. }
  723.  
  724. function lastfm_scrobble(sl) {
  725.     if (api_key.length != 32) return(fb.ShowPopupMessage("Can't contact Last.fm. Check your username / API KEY settings."));
  726.     if (lfm_secret == "") return(fb.ShowPopupMessage("Last.fm secret missing, please reenter your last.fm secret in bio panel to scrobble."));
  727.     if (lfm_sk == "") {
  728.         get_lastfm_sk(function() {lastfm_scrobble(sl)});
  729.         return;
  730.     }
  731.  
  732.     if (sl.length == 0) {
  733.         scrobbling = false;
  734.         return;
  735.     }
  736.  
  737.     var entries = sl.shift();
  738.    
  739.     if (entries.length == 0) {
  740.         lastfm_scrobble(sl);
  741.         return;
  742.     }
  743.    
  744.     var qs_arr = [];
  745.     var scrobbled = [];
  746.     var qs = "";
  747.     var api_sig = "";
  748.     var duration, played_t = 0;
  749.     var album, albumArtist, artist, track, trackNumber = '';
  750.     for (i = 0; i < entries.length; i++) {
  751.         entry = entries[i];
  752.         ID = entry[0];
  753.         timestamp = entry[2];
  754.         album = entry[3];
  755.         albumArtist = entry[4];
  756.         artist = entry[5];
  757.         duration = entry[6];
  758.         track = entry[7];
  759.         trackNumber = entry[8];
  760.         played_t = entry[9];
  761.  
  762.         scrobbled.push(ID);
  763.  
  764.         qs_arr.push("timestamp[" + i + "]" + timestamp);
  765.         qs += "&timestamp[" + i + "]=" + timestamp;
  766.         if (album != "?" && window.GetProperty("walbum")) {
  767.             qs_arr.push("album[" + i + "]" + album);
  768.             qs += "&album[" + i + "]=" + encodeURIComponent(album);
  769.         }
  770.         if (albumArtist != "?" && albumArtist != artist && window.GetProperty("walbumartist")) {
  771.             qs_arr.push("albumArtist[" + i + "]" + albumArtist);
  772.             qs += "&albumArtist[" + i + "]=" + encodeURIComponent(albumArtist);
  773.         }
  774.         qs_arr.push("artist[" + i + "]" + artist);
  775.         qs += "&artist[" + i + "]=" + encodeURIComponent(artist);
  776.         if (duration != 0 && window.GetProperty("wduration")) {
  777.             qs_arr.push("duration[" + i + "]" + duration);
  778.             qs += "&duration[" + i + "]=" + duration;
  779.         }
  780.         qs_arr.push("track[" + i + "]" + track);
  781.         qs += "&track[" + i + "]=" + encodeURIComponent(track);
  782.         if (trackNumber != "" && window.GetProperty("wtracknumber")) {
  783.             qs_arr.push("trackNumber[" + i + "]" + trackNumber);
  784.             qs += "&trackNumber[" + i + "]=" + trackNumber;
  785.         }
  786.     }
  787.     qs_arr.push("api_key" + api_key);
  788.     qs = "api_key=" + api_key + qs;
  789.     qs_arr.push("methodtrack.scrobble");
  790.     qs += "&method=track.scrobble";
  791.     qs_arr.push("sk" + lfm_sk);
  792.     qs += "&sk=" + lfm_sk;
  793.     qs_arr.sort();
  794.     var api_sig = md5(qs_arr.join("") + lfm_secret);
  795.     qs += "&api_sig=" + api_sig;
  796.  
  797.     //fb.trace(qs)
  798.  
  799.     lfmscrobblehttp = new ActiveXObject("Microsoft.XMLHTTP");
  800.     lfmscrobblehttp.open("POST", "http://ws.audioscrobbler.com/2.0/", true);
  801.     lfmscrobblehttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  802.     lfmscrobblehttp.setRequestHeader('User-Agent',useragent);
  803.     lfmscrobblehttp.send(qs);
  804.     lfmscrobblehttp.onreadystatechange = function() {
  805.         if (lfmscrobblehttp.readyState == 4) {
  806.             if (lfmscrobblehttp.status == 200) {
  807.                 fb.trace("Last.fm submission: Scrobbled " + entries.length + " track(s)... OK");
  808.                 while (scrobbled.length > 0)
  809.                     sc_cache_remove(scrobbled.shift());
  810.                 lastfm_scrobble(sl);
  811.             } else {
  812.                 fb.trace(lfmscrobblehttp.responseText);
  813.                 lastfm_scrobble(sl);
  814.             }
  815.         }
  816.     }
  817. }
  818.  
  819. function get_playing_artistart(path, artist) {
  820.     arr = [];
  821.     arr = read_images(path);
  822.     if (arr.length > 0) {
  823.         arr.push(path);
  824.         notify_artistart(arr);
  825.         return;
  826.     }
  827.     if (!window.GetProperty("auto") || window.GetProperty("offline")) {
  828.         notify_artistart([path]);
  829.         return;
  830.     }
  831.     if (username.length == 0 || api_key.length != 32) return(fb.trace("Can't contact Last.fm. Check your username / API KEY settings."));
  832.     wget = "\"" + script_path + "wget.exe\"";
  833.     if (artist != "") {
  834.         str = utils.ReadTextFile(path + "\\blacklist.txt");
  835.         if (!str) blacklist = "";
  836.         blacklist = str.split("|");
  837.         for (i in blacklist)
  838.         blacklist[i] = blacklist[i].split("\\").pop();
  839.         artistxmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
  840.         qs = "&method=artist.getimages&autocorrect=1&limit=" + limit + "&artist=" + encodeURIComponent(artist);
  841.         artistxmlhttp.open("GET", "http://ws.audioscrobbler.com/2.0/?api_key=" + api_key + qs + "&s=" + Math.random(), true);
  842.         artistxmlhttp.setRequestHeader('User-Agent',useragent);
  843.         artistxmlhttp.send();
  844.         artistxmlhttp.onreadystatechange = function() {
  845.             if (artistxmlhttp.readyState == 4) {
  846.                 working++;
  847.                 window.NotifyOthers("gettingartistart", true);
  848.                 if (artistxmlhttp.status == 200) {
  849.                     artistxml = artistxmlhttp.responseText;
  850.                     artistxmldom = new ActiveXObject("Microsoft.XMLDOM");
  851.                     artistxmldom.async="false";
  852.                     artistxmldom.loadXML(artistxml);
  853.                     try {
  854.                         nodeList = artistxmldom.getElementsByTagName("size");
  855.                         ts = fso.OpenTextFile(path + "\\dllist.txt", 2, true, 0);
  856.                         getfiles = [];
  857.                         geturls = [];
  858.                         tails = [];
  859.                         for (i = 0; i < nodeList.length; i++) {
  860.                             if (nodeList[i].attributes != null && nodeList[i].attributes.getNamedItem("name") != null && nodeList[i].attributes.getNamedItem("name").nodeValue == artistartsize) {
  861.                                 geturl = nodeList[i].childNodes[0].nodeValue;
  862.                                 orifilename = geturl.split("/").pop();
  863.                                 getfiles.push(orifilename);
  864.                                 geturls.push(geturl.replace(orifilename, encodeURIComponent(orifilename)));
  865.                             }
  866.                         }
  867.                         for (i in blacklist) {
  868.                             tails = blacklist[i].match(/\.(\d+)\.(jpg|png|gif)$/);
  869.                             count = 0;
  870.                             for (j in getfiles) {
  871.                                 if (tails) {
  872.                                     delfile = blacklist[i].replace(tails[0], "." + tails[2]);
  873.                                     if (delfile == getfiles[j]) {
  874.                                         if (count == tails[1]) {
  875.                                             geturls[j] = "";
  876.                                             break;
  877.                                         }
  878.                                         count++;
  879.                                     }
  880.                                 } else {
  881.                                     if (blacklist[i] == getfiles[j]) {
  882.                                         geturls[j] = "";
  883.                                         break;
  884.                                     }
  885.                                 }
  886.                             }
  887.                         }
  888.                         ts.Write(geturls.join("\n"));
  889.                         ts.close();
  890.                         var pathobj = fso.GetFolder(path);
  891.                         WshShell.Run(wget + " -q " + "-P \"" + pathobj.ShortPath + "\" -i \"" + pathobj.ShortPath + "\\dllist.txt\"", 0, true);
  892.                         fix_wget_clobber(path);
  893.                         fso.DeleteFile(path + "\\dllist.txt");
  894.                         arr = read_images(path);
  895.                         arr.push(path);
  896.                     } catch (e) { arr = [path]; }
  897.                 } else {
  898.                     arr = [path];
  899.                 }
  900.                 working--;
  901.                 if (working == 0) {
  902.                     window.NotifyOthers("gettingartistart", false);
  903.                     notify_artistart(arr);
  904.                 }
  905.             }
  906.         }
  907.     } else notify_artistart([path]);
  908. }
  909.  
  910. function fix_wget_clobber(path) {
  911.     if (fso.FolderExists(path)) {
  912.         var files = new Enumerator((fso.GetFolder(path)).Files);
  913.         for (; !files.atEnd(); files.moveNext()) {
  914.             fnchunks = ((files.item()).Name).match(/^(.*)\.(jpg|png|gif)\.(\d+)$/);
  915.             if (fnchunks) {
  916.                 newname = fnchunks[1] + "." + fnchunks[3] + "." + fnchunks[2];
  917.                 fso.MoveFile((files.item()).Path, path + "\\" + newname);
  918.             }
  919.         }
  920.     }
  921. }
  922.  
  923. function notify_artistart(arr) {
  924.     if (!fb.IsPlaying) return;
  925.     artist_folder = data_folder + "\\" + fb.TitleFormat("$crc32(%artist%)").EvalWithMetadb(g_metadb);
  926.     if (arr[arr.length - 1] != artist_folder) {
  927.         arr = [];
  928.         arr = read_images(artist_folder);
  929.         arr.push(artist_folder);
  930.     }
  931.     window.NotifyOthers("artistart", arr);
  932. }
  933.  
  934. function load() {
  935.     if(!g_metadb) return(window.Repaint());
  936.     startplay = false;
  937.     if (data_folder == "/") data_folder = fb.ProfilePath + "wsh_lastfm";
  938.     df_chunks = data_folder.match(/^\?(.*)$/);
  939.     if (df_chunks) {
  940.         data_folder = fb.TitleFormat(df_chunks[1]).EvalWithMetadb(g_metadb) + "\\wsh_lastfm";
  941.     }
  942.     if(!fso.FolderExists(data_folder)) fso.CreateFolder(data_folder);
  943.     lastfm_artist = ret = "";
  944.     simartist_height = 0;
  945.     simartists_height = 0;
  946.     simartists = [];
  947.     simartist_urls_ori = [];
  948.     artist_folder = data_folder + "\\" + fb.TitleFormat("$crc32(%artist%)").EvalWithMetadb(g_metadb);
  949.     if(!fso.FolderExists(artist_folder)) fso.CreateFolder(artist_folder);
  950.     filename = artist_folder + "\\artistinfo.xml";
  951.     if(fso.fileExists(filename)) {
  952.         file = fso.Getfile(filename);
  953.         if (cache_life > 0 && (Date.parse(Date()) - Date.parse(file.DateLastModified) > cache_life)) {
  954.             get(filename, artist);
  955.             if (window.GetProperty("artistartcacherefresh")) {
  956.                 var arr = [];
  957.                 arr = read_images(artist_folder);
  958.                 arr.push(artist_folder);
  959.                 window.NotifyOthers("artistart", arr);
  960.                 window.NotifyOthers("refreshartistart", 1);
  961.             }
  962.             return;
  963.         }
  964.         ret = utils.ReadTextFile(filename);
  965.         if (ret.match(/^offline/)) {
  966.             if (!window.GetProperty("offline")) {
  967.                 get(filename, artist);
  968.                 return;
  969.             }
  970.             ret = "offline";
  971.         } else {
  972.             var xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
  973.             xmlDoc.async="false";
  974.             xmlDoc.loadXML(ret);
  975.             ret = ""
  976.             getartistart = false;
  977.             try {
  978.                 lastfm_artist = xmlDoc.getElementsByTagName("name")[0].childNodes[0].nodeValue;
  979.                 if (lastfm_artist != artist)
  980.                 ret = "(redirected from " + artist + ")\n\n";
  981.             } catch (e) { lastfm_artist = ""; }
  982.             try {
  983.                 if (xmlDoc.getElementsByTagName("image")[0].childNodes[0].nodeValue != "")
  984.                 getartistart = true;
  985.             } catch (e) { getartistart = false; }
  986.             if (getartistart)
  987.             get_playing_artistart(artist_folder, lastfm_artist);
  988.             else
  989.             notify_artistart([artist_folder]);
  990.             if (dlartistart) return;
  991.             try {
  992.                 bioraw = xmlDoc.getElementsByTagName("content")[0].childNodes[0].nodeValue;
  993.                 ret += decodeXML(bioraw);
  994.             } catch(e) {
  995.                 ret += "This artist does not have a biography page on Last.fm.";
  996.             }
  997.             try {
  998.                 ret += "\n\nListeners: " + xmlDoc.getElementsByTagName("listeners")[0].childNodes[0].nodeValue;
  999.             } catch (e) {}
  1000.             try {
  1001.                 playcount = xmlDoc.getElementsByTagName("playcount")[0].childNodes[0].nodeValue;
  1002.                 ret += "\nPlaycount: " + playcount + (playcount > 1 ? " times" : " time");
  1003.             } catch (e) {}
  1004.             try {
  1005.                 similars = xmlDoc.getElementsByTagName("similar")[0];
  1006.                 if (similars.childNodes.length > 1) {
  1007.                     ret += "\n\nSimilar artists:\n";
  1008.                     for (i = 0; i < similars.childNodes.length; i++) {
  1009.                         simartist = (i+1) + ". " + similars.childNodes[i].childNodes[0].childNodes[0].nodeValue;
  1010.                         ret += simartist;
  1011.                         if (i < similars.childNodes.length - 1) ret += "\n";
  1012.                         simartists.push(simartist);
  1013.                         simartist_urls_ori[i] = similars.childNodes[i].childNodes[1].childNodes[0].nodeValue;
  1014.                     }
  1015.                 }
  1016.             } catch (e) {}
  1017.             try {
  1018.                 lastfm_artist_url = xmlDoc.getElementsByTagName("url")[0].childNodes[0].nodeValue;
  1019.             } catch (e) { lastfm_artist_url = "http://www.last.fm/music/" + ((lastfm_artist != "") ? encodeURIComponent(lastfm_artist.replace(/\s+/g,"+")) : encodeURIComponent(artist)); }
  1020.         }
  1021.         reset();
  1022.         g_tooltip.Text = p_title = (lastfm_artist != "") ? lastfm_artist : artist;
  1023.         g_text = ret;
  1024.         window.Repaint();
  1025.     } else {
  1026.         get(filename, artist);
  1027.     }
  1028. }
  1029.  
  1030. function get(path, artist) {
  1031.     if (username.length == 0 || api_key.length != 32) return(fb.trace("Can't contact Last.fm. Check your username / API KEY settings."));
  1032.     if (!window.GetProperty("offline"))
  1033.     lastfm("&lang=" + lang + "&method=artist.getinfo&artist=" + encodeURIComponent(artist) + "&autocorrect=1", useragent, function() {save_xml_file(path); load()});
  1034.     else {
  1035.         xmlDoc = "offline";
  1036.         save_xml_file(path);
  1037.         load();
  1038.     }
  1039. }
  1040.  
  1041. function lastfm(qs, user_agent, func) {
  1042.     xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
  1043.     xmlhttp.open("GET", "http://ws.audioscrobbler.com/2.0/?api_key=" + api_key + "&user=" + username + qs + "&s=" + Math.random(), true);
  1044.     xmlhttp.setRequestHeader('User-Agent',user_agent);
  1045.     xmlhttp.send();
  1046.     xmlhttp.onreadystatechange = function() {
  1047.         if (xmlhttp.readyState == 4) {
  1048.             if (xmlhttp.status == 200) {
  1049.                 xmlDoc = xmlhttp.responseText;
  1050.                 func();
  1051.             } else {
  1052.                 fb.trace(xmlhttp.responseText);
  1053.                 func();
  1054.             }
  1055.         }
  1056.     }
  1057. }
  1058.  
  1059. function save_xml_file(path) {
  1060.     try {
  1061.         ts = fso.OpenTextFile(path, 2, true, -1);
  1062.         ts.WriteLine(xmlDoc);
  1063.         ts.close();
  1064.     } catch(e) {
  1065.     }
  1066. }
  1067.  
  1068. function calc_simartists_dim() {
  1069.     var temp_bmp = gdi.CreateImage(1, 1);
  1070.     var temp_gr = temp_bmp.GetGraphics();
  1071.     t_arr = [];
  1072.     simartist_widths = [];
  1073.     simartist_urls = [];
  1074.     for (i in simartists)
  1075.     t_arr[i] = temp_gr.CalcTextWidth(simartists[i], g_font);
  1076.     for (i = 0; i < t_arr.length; i++) {
  1077.         if (t_arr[i] >= ww-16) {
  1078.             wrapped_lines = temp_gr.EstimateLineWrap(simartists[i], g_font, ww-16).toArray();
  1079.             for (j = 1; j < wrapped_lines.length; j = j + 2) {
  1080.                 simartist_widths.push(wrapped_lines[j]);
  1081.                 simartist_urls.push(simartist_urls_ori[i]);
  1082.             }
  1083.         } else {
  1084.             simartist_widths.push(t_arr[i]);
  1085.             simartist_urls.push(simartist_urls_ori[i]);
  1086.         }
  1087.     }
  1088.     if (simartist_widths.length != 0) {
  1089.         simartist_height = temp_gr.CalcTextHeight(simartist_widths[0], g_font);
  1090.         simartists_height = simartist_height * simartist_widths.length;
  1091.     }
  1092.     need_calc_simartists_dim = false;
  1093.     temp_bmp.ReleaseGraphics(temp_gr);
  1094.     temp_bmp.Dispose();
  1095.     temp_gr = null;
  1096.     temp_bmp = null;
  1097. }
  1098.  
  1099. function text_input_box(title, message, section, key, value) {
  1100.     WshShell.Run("\"" + inputbox + "\" \"" + title + "\" \"" + message + "\" \"" + value + "\"", 0, true);
  1101.     var wshEnv = WshShell.Environment("Volatile");
  1102.     var input = wshEnv("WshEnv");
  1103.     if (input != "") {
  1104.         utils.WriteINI(inifile, section, key, input);
  1105.         return input;
  1106.     }
  1107.     return value;
  1108. }
  1109.  
  1110. function read_images(path) {
  1111.     var ret = [];
  1112.     if (fso.FolderExists(path)) {
  1113.         var files = new Enumerator((fso.GetFolder(path)).Files);
  1114.         for (; !files.atEnd(); files.moveNext()) {
  1115.             if (((files.item()).Name).match(/^.*\.(jpg|png|gif)$/)) {
  1116.                 ret.push(path + "\\" + (files.item()).Name);
  1117.             }
  1118.         }
  1119.     }
  1120.     return ret;
  1121. }
  1122.  
  1123. function decodeXML(value) {
  1124.     value = value.replace(/<\/?[^>]+(>|$)/g, "");
  1125.     doc = new ActiveXObject("htmlfile");
  1126.     doc.open();
  1127.     div = doc.createElement("div");
  1128.     div.innerHTML = value.replace(/\n/g, "<br>");
  1129.     value = div.innerHTML;
  1130.     value = value.replace(/<BR>/g,"\n");
  1131.     value = value.replace(/&gt;/g,">");
  1132.     value = value.replace(/&lt;/g,"<");
  1133.     value = value.replace(/&nbsp;/g," ");
  1134.     return value.replace(/&amp;/g,"&");
  1135. }
  1136.  
  1137. function zeroPad(num,count) {
  1138.     var numZeropad = num + '';
  1139.     while(numZeropad.length < count) {
  1140.         numZeropad = "0" + numZeropad;
  1141.     }
  1142.     return numZeropad;
  1143. }
  1144.  
  1145. function on_mouse_wheel(delta) {
  1146.     if (!fb.IsPlaying) return;
  1147.     applyDelta(delta * 20, defoffset);
  1148. }
  1149.  
  1150. function on_mouse_lbtn_down(x, y) {
  1151.     g_drag = true;
  1152.     g_drag_y = y;
  1153. }
  1154.  
  1155. function on_mouse_move(x,y) {
  1156.     if (!fb.IsPlaying) {
  1157.         g_tooltip.Deactivate();
  1158.         window.SetCursor(IDC_ARROW);
  1159.         return;
  1160.     }
  1161.     index = Math.floor((y - start_y - 1)/simartist_height);
  1162.     switch (true) {
  1163.     case (simartists_height > 0 && x > 6 && x < Math.min(ww-16, 6 + simartist_widths[index]) && y > start_y && y < start_y + simartists_height && y < wh-11):
  1164.         window.SetCursor(IDC_HAND);
  1165.         if (g_tooltip.Text != simartist_urls[index]) g_tooltip.Text = simartist_urls[index];
  1166.         g_tooltip.Activate();
  1167.         break;
  1168.     case (lastfm_artist_url != "" && x > 6 && x < 6 + p_title_width && y > 6 && y < 30):
  1169.         if (p_title_width >= ww - 12) {
  1170.             if (g_tooltip.Text != p_title) g_tooltip.Text = p_title;
  1171.             g_tooltip.Activate();
  1172.         } else g_tooltip.Deactivate();
  1173.         window.SetCursor(IDC_HAND);
  1174.         break;
  1175.     default:
  1176.         g_tooltip.Deactivate();
  1177.         window.SetCursor(IDC_ARROW);
  1178.     }
  1179.     if (fb.IsPlaying && g_drag) {
  1180.         applyDelta(y - g_drag_y, defoffset);
  1181.         g_drag_y = y;
  1182.     }
  1183. }
  1184.  
  1185. function on_mouse_lbtn_up(x, y) {
  1186.     g_drag = false;
  1187.     if (!fb.IsPlaying) return;
  1188.     if (lastfm_artist_url != "" && x > 6 && x < 6 + p_title_width && y > 6 && y < 30)
  1189.     WshShell.run(lastfm_artist_url);
  1190.     index = Math.floor((y - start_y - 1)/simartist_height);
  1191.     if (simartists_height > 0 && x > 6 && x < Math.min(ww-16, 6 + simartist_widths[index]) && y > start_y && y < start_y + simartists_height && y < wh-11)
  1192.     WshShell.run(simartist_urls[index]);
  1193. }
  1194.  
  1195. function on_mouse_rbtn_up(x, y) {
  1196.     var _menu = window.CreatePopupMenu();
  1197.     var _languages = window.CreatePopupMenu();
  1198.     var _lastfm = window.CreatePopupMenu();
  1199.     var _artistart = window.CreatePopupMenu();
  1200.     var _artistartsize = window.CreatePopupMenu();
  1201.     var _limit = window.CreatePopupMenu();
  1202.     var _scrobbler = window.CreatePopupMenu();
  1203.     var idx;
  1204.     _menu.AppendMenuItem(username.length > 0 && api_key.length == 32 && g_metadb && !window.GetProperty("offline") && fb.IsPlaying ? MF_STRING : MF_GRAYED, 1, "Update");
  1205.     _menu.AppendMenuItem(MF_STRING, 2, "Work offline");
  1206.     _menu.CheckMenuItem(2, window.GetProperty("offline"));
  1207.     _menu.AppendMenuItem(MF_SEPARATOR, 0, 0);
  1208.     _lastfm.AppendMenuItem(MF_STRING, 3, "Set your username");
  1209.     _lastfm.AppendMenuItem(MF_STRING, 4, "Set your API KEY");
  1210.     _lastfm.AppendMenuItem(MF_STRING, 5, "Set your secret");
  1211.     _lastfm.AppendMenuItem(MF_SEPARATOR, 0, 0);
  1212.     _lastfm.AppendMenuItem(MF_STRING, 6, "Set biography text cache life");
  1213.     _lastfm.AppendMenuItem(MF_STRING, 7, "Set data folder");
  1214.     _lastfm.AppendMenuItem(MF_SEPARATOR, 0, 0);
  1215.     _lastfm.AppendMenuItem(MF_STRING, 8, "Enable scrobbler");
  1216.     _lastfm.CheckMenuItem(8, window.GetProperty("scrobble"));
  1217.     _scrobbler.AppendMenuItem(MF_STRING, 81, "Only file in media library");
  1218.     _scrobbler.CheckMenuItem(81, window.GetProperty("onlymlfile"));
  1219.     _scrobbler.AppendMenuItem(MF_SEPARATOR, 0, 0);
  1220.     _scrobbler.AppendMenuItem(MF_GRAYED, 0, "Modification");
  1221.     _scrobbler.AppendMenuItem(MF_STRING, 82, "Artist");
  1222.     _scrobbler.AppendMenuItem(MF_STRING, 83, "Title");
  1223.     _scrobbler.AppendMenuItem(MF_SEPARATOR, 0, 0);
  1224.     _scrobbler.AppendMenuItem(MF_GRAYED, 0, "Query inclusion");
  1225.     _scrobbler.AppendMenuItem(MF_STRING, 84, "Album");
  1226.     _scrobbler.CheckMenuItem(84, window.GetProperty("walbum"));
  1227.     _scrobbler.AppendMenuItem(MF_STRING, 85, "Album Artist");
  1228.     _scrobbler.CheckMenuItem(85, window.GetProperty("walbumartist"));
  1229.     _scrobbler.AppendMenuItem(MF_STRING, 86, "Track duration");
  1230.     _scrobbler.CheckMenuItem(86, window.GetProperty("wduration"));
  1231.     _scrobbler.AppendMenuItem(MF_STRING, 87, "Track number");
  1232.     _scrobbler.CheckMenuItem(87, window.GetProperty("wtracknumber"));
  1233.     _lastfm.AppendMenuItem(window.GetProperty("scrobble") ? MF_STRING | MF_POPUP : MF_GRAYED, _scrobbler.ID, "Scrobble options");
  1234.     _menu.AppendMenuItem(MF_STRING | MF_POPUP, _lastfm.ID, "Last.fm options");
  1235.     _artistart.AppendMenuItem(MF_STRING, 1000, "Automatically download");
  1236.     _artistart.CheckMenuItem(1000, window.GetProperty("auto"));
  1237.     _artistart.AppendMenuItem(MF_STRING, 1001, "Refresh artist art with biography text cache");
  1238.     _artistart.CheckMenuItem(1001, window.GetProperty("artistartcacherefresh"));
  1239.     for (i in artistartsizes) {
  1240.         _artistartsize.AppendMenuItem(MF_STRING, 400 + parseInt(i), artistartsizes[i]);
  1241.     }
  1242.     _artistartsize.CheckMenuRadioItem(400, 405, window.GetProperty("artistartsize", 100));
  1243.     _artistart.AppendMenuItem(MF_STRING | MF_POPUP, _artistartsize.ID, "Size");
  1244.     _limit.AppendMenuItem(MF_STRING, 301, "1");
  1245.     _limit.AppendMenuItem(MF_STRING, 303, "3");
  1246.     _limit.AppendMenuItem(MF_STRING, 305, "5");
  1247.     _limit.AppendMenuItem(MF_STRING, 310, "10");
  1248.     _limit.AppendMenuItem(MF_STRING, 320, "20");
  1249.     _limit.CheckMenuRadioItem(301, 320, window.GetProperty("limit"));
  1250.     _artistart.AppendMenuItem(MF_STRING | MF_POPUP, _limit.ID, "Limit");
  1251.     _artistart.AppendMenuItem(MF_SEPARATOR, 0, 0)
  1252.     _artistart.AppendMenuItem(MF_STRING, 1002, "Wget settings")
  1253.     _menu.AppendMenuItem(MF_STRING | MF_POPUP, _artistart.ID, "Artist art options");
  1254.     for(i in languages) {
  1255.         _languages.AppendMenuItem(MF_STRING, 100 + parseInt(i), languages[i]);
  1256.     }
  1257.     _languages.CheckMenuRadioItem(100, 111, window.GetProperty("language",100));
  1258.     _menu.AppendMenuItem(MF_STRING | MF_POPUP, _languages.ID, "Language");
  1259.     if(utils.IsKeyPressed(0x10)) {
  1260.         _menu.AppendMenuItem(MF_SEPARATOR, 0, 0);
  1261.         _menu.AppendMenuItem(MF_STRING, 10, "Configure...");
  1262.     }
  1263.     idx = _menu.TrackPopupMenu(x, y);
  1264.     switch(idx) {
  1265.     case 100:
  1266.     case 101:
  1267.     case 102:
  1268.     case 103:
  1269.     case 104:
  1270.     case 105:
  1271.     case 106:
  1272.     case 107:
  1273.     case 108:
  1274.     case 109:
  1275.     case 110:
  1276.     case 111:
  1277.         window.SetProperty("language", idx);
  1278.         lang = langs[window.GetProperty("language",100) - 100];
  1279.         if (!fb.IsPlaying) return;
  1280.         get(filename, artist);
  1281.         break;
  1282.     case 1:
  1283.         get(filename, artist);
  1284.         break;
  1285.     case 2:
  1286.         window.SetProperty("offline", !window.GetProperty("offline"));
  1287.         if (!window.GetProperty("offline")) {
  1288.             fb.IsPlaying && load();
  1289.             if (!lfm_np_updating && window.GetProperty("scrobble")) {
  1290.                 lfm_np_updating = true;
  1291.                 set_lfm_np(sc_cache.slice());
  1292.             }
  1293.         }
  1294.         break;
  1295.     case 3:
  1296.         username = text_input_box("Simple Biography", "Please enter your Last.fm username", "default", "username", username);
  1297.         if (username != "" && api_key != "") {
  1298.             fb.IsPlaying && load();
  1299.             window.NotifyOthers("lastfm_account", 1);
  1300.         }
  1301.         break;
  1302.     case 4:
  1303.         api_key = text_input_box("Simple Biography", "Please enter your Last.fm API KEY\n\nhttp://www.last.fm/api/account", "default", "api_key", api_key);
  1304.         if (username != "" && api_key != "") {
  1305.             fb.IsPlaying && load();
  1306.             window.NotifyOthers("lastfm_account", 1);
  1307.         }
  1308.         break;
  1309.     case 5:
  1310.         lfm_secret = text_input_box("Simple Biography", "Please enter your Last.fm secret\n\nhttp://www.last.fm/api/account", "default", "secret", lfm_secret);
  1311.         break;
  1312.     case 6:
  1313.         cache_life = text_input_box("Simple Biography", "Please enter your Last.fm artist biography text cache life (in days).\n\nUse 0 to disable", "default", "cache_life", cache_life / 86400000) * 86400000;
  1314.         break;
  1315.     case 7:
  1316.         data_folder = text_input_box("Simple Biography", "Please enter your Last.fm cache data folder.\nTo use titleformatting please prefix your string with '?'.\n\nBy default Last.fm cache data is stored in wsh_lastfm folder inside foobar profile directory (enter / to use default).", "default", "data_folder", utils.ReadINI(inifile, "default", "data_folder", "/"));
  1317.         if (data_folder == "/") data_folder = fb.ProfilePath + "wsh_lastfm";
  1318.         break;
  1319.     case 8:
  1320.         window.SetProperty("scrobble", !window.GetProperty("scrobble"));
  1321.         if (!lfm_np_updating && window.GetProperty("scrobble") && !window.GetProperty("offline")) {
  1322.             lfm_np_updating = true;
  1323.             set_lfm_np(sc_cache.slice());
  1324.         }
  1325.         break;
  1326.     case 81:
  1327.         window.SetProperty("onlymlfile", !window.GetProperty("onlymlfile"))
  1328.         break;
  1329.     case 82:
  1330.         tf_artist = text_input_box("Simple Biography", "Enter titleformatting string to get track title.\n\nDefault is %artist% (enter blank string to use default)", "scrobbler", "tf_artist", tf_artist);
  1331.         break;
  1332.     case 83:
  1333.         tf_title = text_input_box("Simple Biography", "Enter titleformatting string to get artist title.\n\nDefault is $meta(title) (enter blank string to use default)", "scrobbler", "tf_title", tf_title);
  1334.         break;
  1335.     case 84:
  1336.         window.SetProperty("walbum", !window.GetProperty("walbum"));
  1337.         break;
  1338.     case 85:
  1339.         window.SetProperty("walbumartist", !window.GetProperty("walbumartist"));
  1340.         break;
  1341.     case 86:
  1342.         window.SetProperty("wduration", !window.GetProperty("wduration"));
  1343.         break;
  1344.     case 87:
  1345.         window.SetProperty("wtracknumber", !window.GetProperty("wtracknumber"));
  1346.         break;
  1347.     case 10:
  1348.         window.ShowConfigure();
  1349.         break;
  1350.     case 301:
  1351.     case 303:
  1352.     case 305:
  1353.     case 310:
  1354.     case 320:
  1355.         window.SetProperty("limit", idx);
  1356.         limit = idx - 300;
  1357.         fb.IsPlaying && window.NotifyOthers("refreshartistart", 1);
  1358.         break;
  1359.     case 400:
  1360.     case 401:
  1361.     case 402:
  1362.     case 403:
  1363.     case 404:
  1364.     case 405:
  1365.         window.SetProperty("artistartsize", idx);
  1366.         artistartsize = artistartsizetext[window.GetProperty("artistartsize", 400) - 400];
  1367.         fb.IsPlaying && window.NotifyOthers("refreshartistart", 1);
  1368.         break;
  1369.     case 1000:
  1370.         window.SetProperty("auto", !window.GetProperty("auto"));
  1371.         fb.IsPlaying && window.NotifyOthers("refreshartistart", 1);
  1372.         break;
  1373.     case 1001:
  1374.         window.SetProperty("artistartcacherefresh", !window.GetProperty("artistartcacherefresh"));
  1375.         break;
  1376.     case 1002:
  1377.         WshShell.run("notepad.exe " + proxy_file, 1, true);
  1378.         fb.IsPlaying && window.NotifyOthers("refreshartistart", 1);
  1379.         break;
  1380.     }
  1381.     _scrobbler.Dispose();
  1382.     _languages.Dispose();
  1383.     _limit.Dispose();
  1384.     _lastfm.Dispose();
  1385.     _artistartsize.Dispose();
  1386.     _artistart.Dispose();
  1387.     _menu.Dispose();
  1388.     return true;
  1389. }