В очередной раз хочу допилить то, что раздражает в любимой сборке 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)?







