В очередной раз хочу допилить то, что раздражает в любимой сборке fb2k. Недавно получил доступ к китайским сайтам с закачкой через baidu, теперь у меня жесткий диск кишит сотнями гигов файлов с иероглифами. Мой встроенный sox не умеет создавать файл спектра, если присутствуют иероглифы в названии файла и/или тегах.
В моем случае запуск спектра реализован следующим образом:
- Спойлер
- var empty_rating = gdi.Image(fb.FoobarPath + "images/similar_wmp_12/STAR1.png");
var empty_rating2 = gdi.Image(fb.FoobarPath + "images/similar_wmp_12/STAR2.png");
var checked_rating = gdi.Image(fb.FoobarPath + "images/similar_wmp_12/STAR3.png");
var g_font = gdi.Font("Segoe UI", 11, 0);
var focus_playing = false;
var in_library = false;
var g_move = null;
var xpos;
var ypos;
var g_timer = window.CreateTimerInterval(500);
var property_spectrum = window.GetProperty("Spectrum.Enabled", true);
var property_tmp_auto = window.GetProperty("Spectrum.TmpDir.Auto", true);
var property_tmp_dir = window.GetProperty("Spectrum.TmpDir.String", "G:\\TEMP\\spectrum\\");
// Flags, used with GdiDrawText()
DT_LEFT = 0x00000000;
DT_RIGHT = 0x00000002;
DT_END_ELLIPSIS = 0x00008000;
function RGB(r,g,b){
return (0xff000000|(r<<16)|(g<<8)|(b));
}
function on_paint(gr){
var title_back_color = RGB(200,225,250);
var title_fore_color = RGB(0,41,99);
var back_color = window.GetColorCUI(3);
var text1_color = window.GetColorCUI(0);
var text2_color = RGB(0,100,200);
var ww = window.Width;
var wh = window.Height;
gr.FillSolidRect(0, 0, ww, wh, back_color);
gr.SetTextRenderingHint(5);
gr.FillGradRect(4, 1, ww-4, 14, 0, title_back_color, back_color);
gr.FillRoundRect(1, 0, 4, 15, 2, 2, title_back_color);
gr.GdiDrawText("›› General Information", g_font, title_fore_color, 4, 1, ww, 14, DT_LEFT);
gr.FillGradRect(122, 8, ww-124, 1, 0, text1_color, back_color);
gr.FillSolidRect(122, 8, 1, 1, text1_color);
gr.GdiDrawText("Codec:", g_font, text1_color, 5, 14, 70, 14, DT_RIGHT);
gr.GdiDrawText("Codec Profile:", g_font, text1_color, 5, 28, 70, 14, DT_RIGHT);
gr.GdiDrawText("Bitrate:", g_font, text1_color, 5, 42, 70, 14, DT_RIGHT);
gr.GdiDrawText("Channels:", g_font, text1_color, 5, 56, 70, 14, DT_RIGHT);
gr.GdiDrawText("Sample Rate:", g_font, text1_color, 5, 70, 70, 14, DT_RIGHT);
gr.GdiDrawText("Tool:", g_font, text1_color, 5, 84, 70, 14, DT_RIGHT);
gr.GdiDrawText("Tag Type:", g_font, text1_color, 5, 98, 70, 14, DT_RIGHT);
gr.GdiDrawText("File Size:", g_font, text1_color, 5, 112, 70, 14, DT_RIGHT);
gr.FillGradRect(4, 134, ww-4, 14, 0, title_back_color, back_color);
gr.FillRoundRect(1, 133, 4, 15, 2, 2, title_back_color);
gr.GdiDrawText("›› Playback Statistics", g_font, title_fore_color, 4, 134, ww, 14, DT_LEFT);
gr.FillGradRect(110, 141, ww-112, 1, 0, text1_color, back_color);
gr.FillSolidRect(110, 141, 1, 1, text1_color);
gr.GdiDrawText("First Played:", g_font, text1_color, 5, 147, 70, 14, DT_RIGHT);
gr.GdiDrawText("Last Played:", g_font, text1_color, 5, 161, 70, 14, DT_RIGHT);
gr.GdiDrawText("Played:", g_font, text1_color, 5, 175, 70, 14, DT_RIGHT);
gr.FillGradRect(4, 197, ww-4, 14, 0, title_back_color, back_color);
gr.FillRoundRect(1, 196, 4, 15, 2, 2, title_back_color);
gr.GdiDrawText("›› Rating", g_font, title_fore_color, 4, 197, ww, 14, DT_LEFT);
gr.FillGradRect(52, 204, ww-54, 1, 0, text1_color, back_color);
gr.FillSolidRect(52, 204, 1, 1, text1_color);
var key_playing = fb.TitleFormat("%path%\\%subsong%").Eval();
focus_playing = false;
in_library = false;
var g_focus_metadb = fb.GetFocusItem();
if(g_focus_metadb!=null){
var key_focus = fb.TitleFormat("%path%\\%subsong%").EvalWithMetadb(g_focus_metadb);
if(key_focus==key_playing) focus_playing = true;
var string1 = fb.TitleFormat("[%codec%][ '('$info(encoding)')']").EvalWithMetadb(g_focus_metadb);
var string2 = fb.TitleFormat("[%codec_profile%]").EvalWithMetadb(g_focus_metadb);
if(focus_playing) string3 = fb.TitleFormat("$if($strcmp(%codec_profile%,CBR),,~)%bitrate% kbit").Eval();
else var string3 = fb.TitleFormat("$if($strcmp(%codec_profile%,CBR),,~)$info(bitrate) kbit").EvalWithMetadb(g_focus_metadb);
var string4 = fb.TitleFormat("$caps($if3(%__mp3_stereo_mode%,[%channels%]))").EvalWithMetadb(g_focus_metadb);
var string5 = fb.TitleFormat("[%samplerate%' Hz']").EvalWithMetadb(g_focus_metadb);
var string6 = fb.TitleFormat("$if(%__tool%,$caps($if($strcmp($left(%__tool%,4),LAME),$insert(%__tool%,' ',4),%__tool%)),n/a)").EvalWithMetadb(g_focus_metadb);
var string7 = fb.TitleFormat("$if3($replace($info(tagtype),|,+),n/a)").EvalWithMetadb(g_focus_metadb);
var string8 = fb.TitleFormat("$insert(%filesize_natural%,' ',$sub($len(%filesize_natural%),2))").EvalWithMetadb(g_focus_metadb);
gr.GdiDrawText(string1, g_font, text2_color, 78, 14, ww-80, 14, DT_END_ELLIPSIS);
gr.GdiDrawText(string2, g_font, text2_color, 78, 28, ww-80, 14, DT_END_ELLIPSIS);
gr.GdiDrawText(string3, g_font, text2_color, 78, 42, ww-80, 14, DT_END_ELLIPSIS);
gr.GdiDrawText(string4, g_font, text2_color, 78, 56, ww-80, 14, DT_END_ELLIPSIS);
gr.GdiDrawText(string5, g_font, text2_color, 78, 70, ww-80, 14, DT_END_ELLIPSIS);
gr.GdiDrawText(string6, g_font, text2_color, 78, 84, ww-80, 14, DT_END_ELLIPSIS);
gr.GdiDrawText(string7, g_font, text2_color, 78, 98, ww-80, 14, DT_END_ELLIPSIS);
gr.GdiDrawText(string8, g_font, text2_color, 78, 112, ww-80, 14, DT_END_ELLIPSIS);
if(fb.IsMetadbInMediaLibrary(g_focus_metadb)){
in_library = true;
var string9 = fb.TitleFormat("$if(%first_played%,$day_of_month(%first_played%)'.'$month(%first_played%)'.'$year(%first_played%)' '$substr(%first_played%,12,16),Never Played)").EvalWithMetadb(g_focus_metadb);
var string10 = fb.TitleFormat("$if(%last_played%,$day_of_month(%last_played%)'.'$month(%last_played%)'.'$year(%last_played%)' '$substr(%last_played%,12,16),Never Played)").EvalWithMetadb(g_focus_metadb);
var string11 = fb.TitleFormat("'x '$if3(%play_count%,0)").EvalWithMetadb(g_focus_metadb);
}
else{
var string9 = "[NOT IN MEDIA LIBRARY]";
var string10 = "";
var string11 = "";
}
gr.GdiDrawText(string9, g_font, text2_color, 78, 147, ww-80, 14, DT_END_ELLIPSIS);
gr.GdiDrawText(string10, g_font, text2_color, 78, 161, ww-80, 14, DT_END_ELLIPSIS);
gr.GdiDrawText(string11, g_font, text2_color, 78, 175, ww-80, 14, DT_END_ELLIPSIS);
xpos = Math.floor((ww-65)/2);
ypos = 212;
if(g_move) var now_check = g_move;
else var now_check = fb.TitleFormat("$if2(%rating%,0)").EvalWithMetadb(g_focus_metadb);
for (i = 0; i < now_check; i++){
gr.DrawImage(checked_rating, xpos+i*13, ypos, 13, 13, 0, 0, 13, 13);
}
for (j = now_check; j < 5; j++){
if(g_move) gr.DrawImage(empty_rating2, xpos+j*13, ypos, 13, 13, 0, 0, 13, 13);
else gr.DrawImage(empty_rating, xpos+j*13, ypos, 13, 13, 0, 0, 13, 13);
}
}
}
function on_item_focus_change(){
window.Repaint();
}
function on_mouse_move(x,y){
if(focus_playing && in_library){
if(xpos<=x && x<xpos+65 && ypos<=y && y<ypos+13){
g_move = Math.floor((x-xpos)/13)+1;
window.Repaint();
}
else{
if(g_move){
g_move = null;
window.Repaint();
}
}
}
}
function on_mouse_leave(){
g_move = null;
window.Repaint();
}
function on_mouse_lbtn_down(x,y){
if(focus_playing && in_library){
if(xpos<=x && x<xpos+65 && ypos<=y && y<ypos+13){
g_move = Math.floor((x-xpos)/13)+1;
fb.RunContextCommand("Playback Statistics/Rating/" + g_move);
}
}
}
function on_mouse_rbtn_down(x,y){
var _menu = window.CreatePopupMenu();
if(focus_playing && in_library){
var current_rating = fb.TitleFormat("$if2(%rating%,0)").Eval();
if(current_rating>0){
_menu.AppendMenuItem(0x00000000, 1, "Delete rating");
_menu.AppendMenuItem(0x00000800, 0, 0);
}
}
if(property_spectrum && fb.GetFocusItem()!=null){
_menu.AppendMenuItem(0x00000000, 2, "Spectrum");
_menu.AppendMenuItem(0x00000800, 0, 0);
}
_menu.AppendMenuItem(0x00000000, 3, "Properties");
_menu.AppendMenuItem(0x00000000, 4, "Configure...");
ret = _menu.TrackPopupMenu(x, y);
switch (ret){
case 1:
fb.RunContextCommand("Playback Statistics/Rating/<not set>");
break;
case 2:
spectrum();
break
case 3:
window.ShowProperties();
break;
case 4:
window.ShowConfigure();
}
_menu.Dispose();
}
function on_timer(id){
window.Repaint();
}
function spectrum(){
var g_focus_metadb = fb.GetFocusItem();
if(g_focus_metadb!=null){
var subsong=fb.TitleFormat("%subsong%").EvalWithMetadb(g_focus_metadb);
if(subsong==0){
var workdir = fb.FoobarPath+"\spectrum\\";
if(property_tmp_auto) var tmpdir = workdir;
else var tmpdir = property_tmp_dir;
var batname = tmpdir+"spectrum.bat";
var filename = fb.TitleFormat("%path%").EvalWithMetadb(g_focus_metadb);
var lenght = " ("+fb.TitleFormat("%length%=%length_seconds%").EvalWithMetadb(g_focus_metadb)+")";
var fso = new ActiveXObject("Scripting.FileSystemObject");
if (fso.fileexists(batname)==true) var ts = fso.OpenTextFile(batname, 2);
else var ts = fso.CreateTextFile(batname, 1);
ts.WriteLine('@echo off');
ts.WriteLine('"'+workdir+'ffmpeg.exe" -y -i '+shortname(filename)+' "'+tmpdir+'spectrum.wav"');
ts.WriteLine('"'+workdir+'sox\\sox.exe" "'+tmpdir+'spectrum.wav" -n spectrogram -x 739 -Y 568 -w Hann -S 0 -t "'+filename+lenght+'" -c "Generated with SOX in foobar2000 by Alex Realist" -o "'+tmpdir+'spectrum_tmp.png"');
ts.WriteLine('copy "'+tmpdir+'spectrum_tmp.png" "'+tmpdir+'spectrum.png"');
ts.WriteLine('"'+tmpdir+'spectrum.png"');
ts.WriteLine('exit');
ts.Close();
var WshShell = new ActiveXObject("WScript.Shell");
WshShell.run('cmd /c start "spectrum.bat" /min cmd /c "'+batname+'"');
}
else fb.ShowPopupMessage("Spectrum for multiple tracks within single physical file is unreleased in this version.","Information");
}
}
function shortname(filespec){
var fso2 = new ActiveXObject("Scripting.FileSystemObject");
return(fso2.GetFile(filespec).ShortPath);
}
//EOF
Коль sox не может работать с файлами, содержащими иероглифами, я согласен переключиться на Spek. Но вот вопрос — как реализовать его запуск привычным мне способом — не через добавление службы, а вызовом программы по клику (у меня это в поле над обложкой альбома ПКМ->Spectrum)?