In case anyone's interested, I modified marc2003's bio script to create a Windows 7 style bio panel and lyrics panel. Screenshots:
The code for the bio panel:
var username = "";
var api_key = "";
var image_path = fb.FoobarPath + "images\\";
DT_CENTER = 0x00000001;
DT_VCENTER = 0x00000004;
DT_WORDBREAK = 0x00000010;
DT_CALCRECT = 0x00000400;
DT_NOPREFIX = 0x00000800;
DT_END_ELLIPSIS = 0x00008000;
ColorTypeCUI = {
text: 0,
selection_text: 1,
inactive_selection_text: 2,
background: 3,
selection_background: 4,
inactive_selection_background: 5,
active_item_frame: 6
};
FontTypeCUI = {
items: 0,
labels: 1
};
ColorTypeDUI = {
text: 0,
background: 1,
highlight: 2,
selection: 3
};
FontTypeDUI = {
defaults: 0,
tabs: 1,
lists: 2,
playlists: 3,
statusbar: 4,
console: 5
};
function RGB(r,g,b) {
return (0xff000000|(r<<16)|(g<<8)|(b));
}
function get_font() {
if (g_instancetype == 0) {
g_font = window.GetFontCUI(FontTypeCUI.items);
}
else if (g_instancetype == 1) {
g_font = window.GetFontDUI(FontTypeDUI.defaults);
}
}
function get_colors() {
if (g_instancetype == 0) {
g_textcolor = window.GetColorCUI(ColorTypeCUI.text);
g_textcolor_hl = window.GetColorCUI(ColorTypeCUI.text);
g_backcolor = window.GetColorCUI(ColorTypeCUI.background);
}
else if (g_instancetype == 1) {
g_textcolor = window.GetColorDUI(ColorTypeDUI.text);
g_textcolor_hl = window.GetColorDUI(ColorTypeDUI.highlight);
g_backcolor = window.GetColorDUI(ColorTypeDUI.background);
}
}
function on_playlist_switch() {
on_item_focus_change();
}
function on_colors_changed() {
get_colors();
window.Repaint();
}
function on_font_changed() {
get_font();
window.Repaint();
}
function on_item_focus_change() {
if (g_metadb) window.UnwatchMetadb();
g_metadb = fb.IsPlaying ? fb.GetNowPlaying() : fb.GetFocusItem();
if (g_metadb) {
try { on_metadb_changed(); } catch(e) {}
window.WatchMetadb(g_metadb);
}
}
g_instancetype = window.InstanceType;
get_font();
get_colors();
function lastfm(url, user_agent, func, debug) {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
xmlhttp.open("GET", url + "&s=" + Math.random(), true);
xmlhttp.setRequestHeader('User-Agent',user_agent);
xmlhttp.send();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4) {
if (xmlhttp.status == 200) {
if(debug) fb.trace(xmlhttp.responsetext);
func();
}
else {
fb.trace(xmlhttp.responsetext);
}
}
}
}
g_metadb = fb.GetFocusItem();
var artist = g_text = playcount = '';
var g_img = gdi.Image(image_path + "header.png");
folder = fb.ProfilePath + "wsh_lastfm";
fso = new ActiveXObject("Scripting.FileSystemObject");
WshShell = new ActiveXObject("WScript.Shell");
if(!fso.FolderExists(folder)) fso.CreateFolder(folder);
on_item_focus_change();
get_playcount();
String.prototype.count=function(s1) {
return (this.length - this.replace(new RegExp(s1,"g"), '').length) / s1.length;
}
function get_bio() {
url = "http://ws.audioscrobbler.com/2.0/?method=artist.getinfo&api_key=" + api_key + "&username=" + username + "&artist=" + encodeURIComponent(artist);
lastfm(url, "foo_wsh_lastfm_bio", function() {save_file();},0);
}
function get_playcount() {
url = "http://ws.audioscrobbler.com/2.0/?method=artist.getinfo&api_key=" + api_key + "&username=" + username + "&artist=" + encodeURIComponent(artist);
lastfm(url, "foo_wsh_lastfm_bio", function() {extract_playcount();},0);
}
function save_file() {
xmlDoc = xmlhttp.responseXML;
try {
g_text = xmlDoc.getElementsByTagName("content")[0].childNodes[0].nodeValue;
playcount = xmlDoc.getElementsByTagName("userplaycount")[0].childNodes[0].nodeValue;
g_text = g_text.replace(/<\/?[^>]+(>|$)/g, "");
doc = new ActiveXObject("htmlfile");
doc.open();
div = doc.createElement("div");
div.innerHTML = g_text.replace(/\n/g, "<br>");
g_text = div.innerHTML;
g_text = g_text.replace(/<BR>/g,"\n");
g_text = g_text.replace(/&/g,"&");
}
catch(e) {
playcount = "0";
g_text = "This artist does not have a biography page on Last.fm.";
}
try {
ts = fso.OpenTextFile(filename, 2, true, -1);
ts.WriteLine(g_text);
ts.close();
}
catch(e) {
g_text = "Error saving biography for this artist.";
}
calc();
}
function extract_playcount() {
xmlDoc = xmlhttp.responseXML;
try {
playcount = xmlDoc.getElementsByTagName("userplaycount")[0].childNodes[0].nodeValue;
}
catch(e) {
playcount = "0";
}
window.Repaint();
}
function on_size() {
ww = window.Width;
wh = window.Height;
calc();
}
function on_paint(gr) {
gr.FillSolidRect(0, 0, ww, wh, g_backcolor);
if(g_metadb) {
gr.GdiDrawText(g_text, g_font, g_textcolor, 21, offset + 60, ww-42, wh-offset,DT_WORDBREAK | DT_CALCRECT | DT_NOPREFIX);
gr.FillSolidRect(0, 0, ww, 55, g_backcolor);
gr.DrawImage(g_img, 0, 0, 830, 55, 0, 0, 830, 55);
gr.FillGradRect(830, 0, ww - 820, 55, 0, RGB(252,252,252), RGB(255,255,255));
gr.GdiDrawText(artist, gdi.Font("Segoe UI", 18, 0), RGB(0, 120, 50), 21, 4, ww-77, 24,DT_END_ELLIPSIS | DT_CALCRECT | DT_NOPREFIX);
gr.GdiDrawText("Artist Playcount:", gdi.Font("Segoe UI", 13, 0), RGB(90, 103, 121), 21, 29, ww-16, 24,DT_END_ELLIPSIS | DT_CALCRECT | DT_NOPREFIX);
gr.GdiDrawText(playcount, gdi.Font("Segoe UI", 13, 0), RGB(42, 102, 212), 120, 29, ww-16, 24,DT_END_ELLIPSIS | DT_CALCRECT | DT_NOPREFIX);
gr.DrawLine(21, 54, ww-21, 54, 1, RGB(214,229,245));
gr.FillGradRect(6, 54,15, 1, 0, RGB(255,255,255), RGB(214,229,255));
gr.FillGradRect(ww-21, 54,10, 1, 0, RGB(214,229,255),RGB(255,255,255));
}
}
function on_playback_new_track() {
on_item_focus_change();
get_playcount();
}
function on_metadb_changed() {
if(!g_metadb || artist == fb.TitleFormat("%artist%").EvalWithMetadb(g_metadb)) return;
artist = fb.TitleFormat("%artist%").EvalWithMetadb(g_metadb);
filename = folder + "\\" + fb.TitleFormat("$crc32(%artist%).txt").EvalWithMetadb(g_metadb);
if(fso.fileExists(filename)) {
try {
ts = fso.OpenTextFile(filename,1, false, -1);
g_text = ts.ReadAll();
ts.close();
}
catch(e) {
g_text = "Error opening file!";
}
calc();
}
else {
get_bio();
get_playcount();
}
}
function calc() {
temp_bmp = gdi.CreateImage(1, 1);
temp_gr = temp_bmp.GetGraphics();
arr = temp_gr.GdiDrawText(g_text, g_font, g_textcolor, 0, 0, ww, wh,DT_CENTER| DT_WORDBREAK | DT_VCENTER | DT_CALCRECT | DT_NOPREFIX).toArray();
textheight = arr[3] - arr[1] + (wh/2) + (g_text.count("\n") * 3);
temp_bmp.ReleaseGraphics(temp_gr);
temp_bmp.Dispose();
temp_gr = null;
temp_bmp = null;
offset = 0;
window.Repaint();
}
function on_mouse_rbtn_up(x, y) {
var MF_SEPARATOR = 0x00000800;
var MF_STRING = 0x00000000;
var _menu = window.CreatePopupMenu();
var idx;
_menu.AppendMenuItem(MF_STRING, 1, "Force update");
_menu.AppendMenuItem(MF_STRING, 2, "View on Last.fm");
_menu.AppendMenuItem(MF_SEPARATOR, 0, 0);
_menu.AppendMenuItem(MF_STRING, 3, "Configure...");
idx = _menu.TrackPopupMenu(x, y);
if(idx == 1) get_bio();
if(idx == 2) WshShell.run("http://www.last.fm/music/" + encodeURIComponent(artist));
if(idx == 3) window.ShowConfigure();
_menu.Dispose();
return true;
}
function on_mouse_wheel(delta) {
step = g_font.height * 5;
offset += (delta * step);
if(offset > 0 || textheight < wh) {
offset = 0;
}
else {
temp = -textheight + wh;
if(offset < temp) offset = Math.round(temp / step) * step;
}
window.Repaint();
}
The code for the lyrics panel:
var image_path = fb.FoobarPath + "images\\";
var lyrics_tag = "%lyrics%";
DT_CENTER = 0x00000001;
DT_VCENTER = 0x00000004;
DT_WORDBREAK = 0x00000010;
DT_CALCRECT = 0x00000400;
DT_NOPREFIX = 0x00000800;
DT_END_ELLIPSIS = 0x00008000;
function RGB(r,g,b) {
return (0xff000000|(r<<16)|(g<<8)|(b));
}
function on_playlist_switch() {
on_item_focus_change();
}
function on_item_focus_change() {
if (g_metadb) window.UnwatchMetadb();
g_metadb = fb.IsPlaying ? fb.GetNowPlaying() : fb.GetFocusItem();
if (g_metadb) {
try { on_metadb_changed(); } catch(e) {}
window.WatchMetadb(g_metadb);
}
}
var artist = '';
var title = '';
var lyrics = '';
var g_img = gdi.Image(image_path + "header.png");
g_instancetype = window.InstanceType;
g_metadb = fb.GetFocusItem();
fso = new ActiveXObject("Scripting.FileSystemObject");
WshShell = new ActiveXObject("WScript.Shell");
on_item_focus_change();
String.prototype.count=function(s1) {
return (this.length - this.replace(new RegExp(s1,"g"), '').length) / s1.length;
}
function on_size() {
ww = window.Width;
wh = window.Height;
calc();
}
function on_paint(gr) {
gr.FillSolidRect(0, 0, ww, wh, RGB(255,255,255));
if(g_metadb) {
gr.GdiDrawText(lyrics, gdi.Font("Segoe UI", 13, 2), RGB(0, 0, 0), 0, offset + 65, ww-16, wh-offset,DT_CENTER|DT_WORDBREAK | DT_CALCRECT | DT_NOPREFIX);
gr.FillSolidRect(0, 0, ww, 55, RGB(255,255,255));
gr.DrawImage(g_img, 0, 0, 830, 55, 0, 0, 830, 55);
gr.FillGradRect(830, 0, ww - 820, 55, 0, RGB(252,252,252), RGB(255,255,255));
gr.GdiDrawText(title, gdi.Font("Segoe UI", 18, 0), RGB(0, 120, 50), 0, 4, ww-16, 24,DT_CENTER|DT_END_ELLIPSIS | DT_CALCRECT | DT_NOPREFIX);
gr.GdiDrawText(artist, gdi.Font("Segoe UI", 13, 0), RGB(90, 103, 121), 0, 29, ww-16, 24,DT_CENTER|DT_END_ELLIPSIS | DT_CALCRECT | DT_NOPREFIX);
gr.DrawLine(21, 54, ww-21, 54, 1, RGB(214,229,245));
gr.FillGradRect(6, 54,15, 1, 0, RGB(255,255,255), RGB(214,229,255));
gr.FillGradRect(ww-21, 54,10, 1, 0, RGB(214,229,255),RGB(255,255,255));
}
}
function on_playback_new_track() {
on_item_focus_change();
}
function on_metadb_changed() {
artist = fb.TitleFormat("%artist%").EvalWithMetadb(g_metadb);
title = fb.TitleFormat("%title%").EvalWithMetadb(g_metadb);
lyrics = fb.TitleFormat(lyrics_tag).EvalWithMetadb(g_metadb);
if (lyrics == "?") lyrics = "No Lyrics Available";
window.Repaint();
}
function calc() {
temp_bmp = gdi.CreateImage(1, 1);
temp_gr = temp_bmp.GetGraphics();
arr = temp_gr.GdiDrawText(lyrics, gdi.Font("Segoe UI", 13, 2), RGB(0, 0, 0), 0, 0, ww, wh,DT_CENTER| DT_WORDBREAK | DT_VCENTER | DT_CALCRECT | DT_NOPREFIX).toArray();
textheight = arr[3] - arr[1] + (wh/2) + (lyrics.count("\n") * 3);
temp_bmp.ReleaseGraphics(temp_gr);
temp_bmp.Dispose();
temp_gr = null;
temp_bmp = null;
offset = 0;
window.Repaint();
}
function on_mouse_rbtn_up(x, y) {
var MF_SEPARATOR = 0x00000800;
var MF_STRING = 0x00000000;
var _menu = window.CreatePopupMenu();
var idx;
_menu.AppendMenuItem(MF_STRING, 1, "Refresh");
_menu.AppendMenuItem(MF_STRING, 2, "Edit Lyrics");
_menu.AppendMenuItem(MF_SEPARATOR, 0, 0);
_menu.AppendMenuItem(MF_STRING, 3, "Configure...");
idx = _menu.TrackPopupMenu(x, y);
if(idx == 1) window.Repaint();
if(idx == 2) fb.RunContextCommandWithMetadb("edit",g_metadb);
if(idx == 3) window.ShowConfigure();
_menu.Dispose();
return true;
}
function on_mouse_wheel(delta) {
step = gdi.Font("Segoe UI", 13, 2).height * 5;
offset += (delta * step);
if(offset > 0 || textheight < wh) {
offset = 0;
}
else {
temp = -textheight + wh;
if(offset < temp) offset = Math.round(temp / step) * step;
}
window.Repaint();
}
The required header image (needs to be named "header.png"):
Finally, in order to get the "edit lyrics" command working, you need this component:
http://www.hydrogenaudio.org/forums/index....showtopic=36598
In order to preserve the Windows 7 styling, these scripts don't really play nice with the CUI/DUI default colors. Hopefully someone finds these useful.