To keep the main JScript Panel thread (https://www.hydrogenaud.io/forums/index.php?showtopic=110499) for component updates/issues only, I've started this.
Although many scripts should work in WSH Panel Mod and JScript Panel, there are incompatibilities which are only going to increase as time goes forward.
First of all, here is how to update WSH Panel Mod scripts for JScript Panel:
https://github.com/19379/foo-jscript-panel/...r-JScript-Panel (https://github.com/19379/foo-jscript-panel/wiki/Updating-WSH-Panel-Mod-scripts-for-JScript-Panel)
New JScript sample lastfm bio.txt used in chooser panel crashes. The other text samples I used (properties & thumbs) work fine. Error message below.
JScript Panel (Panel Receiver by marc2003): Microsoft JScript runtime error:
'this.content.length' is null or not an object
Line: 1, Col: 1
<source text only available at compile time>
Well it works for me so try putting the bio script in a fresh panel and see if you get the same error. If you do, try browsing
wsh_data\artists\WHOEVER IT WAS and deleting the
bio.www.last.fm.json file.
@Falstaff, I just installed your SmoothBrowser script and noticed a couple of things...
This can be removed from the preprocessor section...
// @feature "v1.4"
// @feature "watch-metadb"
Also...
if (!("FormatDuration" in utils))
That's in WSH Panel Mod v1.6.3 so you need to use something only available in JScript Panel...
if (!("ShowAutoPlaylistUI" in plman))
question concerning art viewer
is there a way to show a jpg in a top level folder that does not have media in it?
Kinda like a placeholder say for a band name folder when there are album directories below
currently if I have more than 1 folder in a band directory it defaults to the first found art in the first found folder
even if I have art in the "band" folder(but no media)
File>Preferences>Display>Album art
..\image.jpg
File>Preferences>Display>Album art
..\image.jpg
hmm?
doesnt seem to work or Im not understanding
the ..\ tells it to look in the parent folder. also, what image gets displayed depends on the order it appears in the list. if you put it before the pattern that gets the art from the same folder as the music then it will always override when it exists. if it goes after then it won't be displayed when there is art present in the same folder.
the ..\ tells it to look in the parent folder. also, what image gets displayed depends on the order it appears in the list. if you put it before the pattern that gets the art from the same folder as the music then it will always override when it exists. if it goes after then it won't be displayed when there is art present in the same folder.
ok I was thinking thats what you meant
poking a bit more
see if I can find a combo that works
the ..\ tells it to look in the parent folder. also, what image gets displayed depends on the order it appears in the list. if you put it before the pattern that gets the art from the same folder as the music then it will always override when it exists. if it goes after then it won't be displayed when there is art present in the same folder.
ok I was thinking thats what you meant
poking a bit more
see if I can find a combo that works
ok so maybe its my lazyness thats catching up with me
my default art search pattern is *.jpg(*bmp,*.png) as I don't have my cover art all name formatted(Front,cover,back etc)
(put a jpg in the folder,whatever its name and wildcard it)
does this make a difference?
No. foobar works its way from top to the bottom of the list and stops whenever an image is found.
Well it works for me so try putting the bio script in a fresh panel and see if you get the same error. If you do, try browsing wsh_data\artists\WHOEVER IT WAS and deleting the bio.www.last.fm.json file.
Removing the json file doesn't help entirely. It will repeatedly crash on one artist in particular every time. (hed)PE, if selected from any library browser or filter, causes it to fold instantly. Naming issue perhaps? WSH version works flawlessly yet.
That artist works fine for me with JScript panel so it's not that. I think your best bet is to stick with WSH panel mod.
Already switched back. Error spam below.
JScript Panel (Panel Receiver by marc2003): JavaScript runtime error:
Unable to get property 'length' of undefined or null reference
Line: 1262, Col: 25
<source text only available at compile time>
If you're going to report errors, don't use the panel receiver script because it's impossible to tell what file/line it's referring to.
Sorry about that. In this case it triggers on LastFM Bio.
Yeah, you mentioned that in your original post. How else do you think I tested it?
Seeing as my previous post was too cryptic, let's just forget it. You use WSH panel mod and don't ever bother me again.
File: Desktop\foobar2000-5555\js_marc2003\js\text.js
Line: 261, Col: 25
Dragging & dropping folders with mp3 over JScript Paned doesn't work in Windows 10. Is it a limitation of the component?
Drag/dropping files on to the panel works fine. You cannot drag files out though - that is a limitation of the component.
JSplaylist is a fully working example: https://github.com/19379/jsplaylist-mod (https://github.com/19379/jsplaylist-mod)
That script has been broken the last few days as I forgot to update paths in it when I renamed a folder. It is working now though.
I am using HiDPI settings on Windows 10 (200%), and with the new JScript Panel the tooltips are appearing very small.
With WSH Panel Mod the tooltips used to be properly scaled.
(http://i.imgur.com/RpCQ1pO.jpg)
Hopefully this can be fixed.
Thanks & regards,
bas
Search your script for window.CreateTooltip and then add your font name/size/style.
https://github.com/19379/foo-jscript-panel/...es.txt#L546L549 (https://github.com/19379/foo-jscript-panel/blob/5413fde00760437b4fa85e4d008f21723fc35757/foobar2000/foo_jscript_panel/docs/Interfaces.txt#L546L549)
BTW, WSH panel mod didn't make tooltips bigger automatically. They must have been coded in script somewhere using on_tooltip_custom_paint which JScript Panel doesn't support. I've updated my wiki page with this info...
https://github.com/19379/foo-jscript-panel/...r-JScript-Panel (https://github.com/19379/foo-jscript-panel/wiki/Updating-WSH-Panel-Mod-scripts-for-JScript-Panel)
The LastFM bio panel crashes if the download fails for any reason. When the json file is zero bytes in size this.content is null at https://github.com/19379/js-marc2003/blob/m...js/text.js#L250 (https://github.com/19379/js-marc2003/blob/master/js/text.js#L250) and you can't access length element of null object. You can fix crashing by adding "|| !this.content" before you check the length. It might also make sense to report to console potential issues with the bio download.
^That would also cause the script to crash in WSH panel mod but Machinehead insists that works ok...
edit: It has now been fixed...
https://github.com/19379/js-marc2003/releases (https://github.com/19379/js-marc2003/releases)
Search your script for window.CreateTooltip and then add your font name/size/style.
https://github.com/19379/foo-jscript-panel/...es.txt#L546L549 (https://github.com/19379/foo-jscript-panel/blob/5413fde00760437b4fa85e4d008f21723fc35757/foobar2000/foo_jscript_panel/docs/Interfaces.txt#L546L549)
BTW, WSH panel mod didn't make tooltips bigger automatically. They must have been coded in script somewhere using on_tooltip_custom_paint which JScript Panel doesn't support. I've updated my wiki page with this info...
https://github.com/19379/foo-jscript-panel/...r-JScript-Panel (https://github.com/19379/foo-jscript-panel/wiki/Updating-WSH-Panel-Mod-scripts-for-JScript-Panel)
Thank you for your reply. I use
window.CreateTooltip("Segoe UI", 24, 0) now in order to double the font size, which is working fine.
BTW, I didn't use
on_tooltip_custom_paint anywhere in my scripts. But passing the font parameters explicitly resolves my issue anyway.
Regards, bas
I've ported
YouTube Track Manager to work with JScript Panel.
YouTube Track Manager was originally a database search companion for the foo_youtube (https://www.hydrogenaud.io/forums/index.php?showtopic=104379) plug-in, but now offers much more, including comprehensive discography, track choosers, operation with the media library and a nowplaying display. Here is an updated summary of the main features:
- Interactive discography with similar & related artists, for choosing tracks & albums.
- Support for last.fm top albums, top tracks, top similar songs & MusicBrainz releases, including singles & remixes as well as albums & compilations.
- Builds albums & optionally automatically creates m-TAGS files using track lists from MusicBrainz & last.fm.
- Offers auto-generation of top 50 artist tracks & top 50 similar songs.
- Offers auto-pick radio modes for artist, genre / top tags, similar artists & similar songs playback, based on track popularity data from last.fm, echonest or your library. Radio modes are great for listening to music of a chosen style. Last.fm & echonest also work well for music discovery. Library radio offers a new way of playing your own music.
- Tracks can be YouTube links, exclusively media library tracks or a mixture of both where media library tracks are preferred, according to settings. YouTube links are advert-free & can be audio only up to 256 kbps AAC or video.
- Improved nowplaying panel that can act as a cover & artist artwork viewer if no longer wish to look at album & track lists.
- Options > right click menu + properties (*USER...). Double click > album manager: loads albums/tracks. Double click > nowplaying: toggles image/text types. Middle click > nowplaying: toggles image only mode vs image + text. yT button > toggles nowplaying vs album manager panels.
For further details, see earlier posts here (https://www.hydrogenaud.io/forums/index.php?s=&showtopic=105522&view=findpost&p=890289) or here (https://www.hydrogenaud.io/forums/index.php?s=&showtopic=105522&view=findpost&p=909160). Download the latest release (YouTube Track Manager v2.2) here (https://www.hydrogenaud.io/forums/index.php?s=&showtopic=105522&view=findpost&p=911008).
The updated screenshot shows YouTube Track Manager in the left panel with a top 50 loaded into a playlist on the right
(http://i.imgur.com/JAhxZFZ.png)
I had my
Musicbrainz script crash on me yesterday so I've uploaded a fix for it.
https://github.com/19379/js-marc2003/releases (https://github.com/19379/js-marc2003/releases)
I've ported YouTube Track Manager to work with JScript Panel.
Nice.
Help needed - Is this a bug?
The method "GetPlaylistSelectedItems" with callback "on_item_focus_change" does not seem well in my scripts.
I used scripts like this:
var font = gdi.Font(fb.TitleFormat("%theme_font%").Eval(), 12, 2);
var margin_x = 30;
var handles, displayed;
function reload() {
handles = plman.GetPlaylistSelectedItems(plman.ActivePlaylist);
if (handles.Count < 2) {
displayed = plman.PlaylistItemCount(plman.ActivePlaylist) + " items / " + utils.FormatDuration(plman.GetPlaylistItems(plman.ActivePlaylist).CalcTotalDuration()) + " / " + utils.FormatFileSize(plman.GetPlaylistItems(plman.ActivePlaylist).CalcTotalSize());
} else {
displayed = "Selected " + handles.Count + " of " + plman.PlaylistItemCount(plman.ActivePlaylist) + " items / " + utils.FormatDuration(handles.CalcTotalDuration()) + " / " + utils.FormatFileSize(handles.CalcTotalSize());
}
}
function on_size() {
if (!window.Width || !window.Height) return;
handles = plman.GetPlaylistSelectedItems(plman.ActivePlaylist);
reload();
}
function on_paint(gr) {
gr.SetSmoothingMode(4)
gr.FillSolidRect(0, 0, window.Width, window.Height, 0xaa111111);
gr.FillGradRect(0, window.Height - 12, window.Width, 12, 90, 0x00000000, 0x88000000);
gr.GdiDrawText(displayed, font, 0xffffffff, margin_x, 4, window.Width - 2 * margin_x, 16, 0x00000001 | 0x00000004 | 0x00008000);
}
function on_item_focus_change(playlist, from, to) {
reload();
window.Repaint();
}
And the displayed number of selected tracks went wrong. Everytime I use main menu command "Edit/Select all", the displayed number never changed.
When using ELPlaylist, selecting any single track worked correctly, but if selected a whole group, things went wrong like above.
In addition, I tried to avoid the GPSI method, and used the scripts below instead:
function reload() {
var nppl = plman.ActivePlaylist;
var total = plman.PlaylistItemCount(nppl);
var evtg = plman.GetPlaylistItems(nppl)
var selected = 0;
var dur = 0;
var siz = 0;
for (var i=0; i<total; i++) {
if (plman.IsPlaylistItemSelected(nppl, i)) {
selected++;
dur += evtg.Item(i).Length;
siz += evtg.Item(i).FileSize;
};
}
if (selected < 0) {
displayed = total + " items / " + utils.FormatDuration(evtg.CalcTotalDuration()) + " / " + utils.FormatFileSize(evtg.CalcTotalSize());
} else {
displayed = "Selected " + selected + " of " + total + " items / " + utils.FormatDuration(dur) + " / " + utils.FormatFileSize(siz);
}
}
But things just remained the same.
Alright, here's some further discovery.
The callback "on_item_focus_change()" is not called when using "Edit/Select all".
As in ELPlaylist, the callback is called, but its output is still not ideal.
Still wondering why.
replace on_item_focus_change() with on_selection_changed().
OK, it seemed to be solved with the method "on_playlist_items_selection_change()".
I found it in Br3tt's JS Smooth Playlist (thanks). Why isn't it referred in the docs?
on_playlist_items_selection_change()
on_selection_changed()
on_item_selection_change()
on_item_focus_change()
They look so similar. Could anyone explain their difference to me?
replace on_item_focus_change() with on_selection_changed().
Thanks. I am still wondering what differs them two.
on_playlist_items_selection_change()
That was missing from the docs so I need to update them. According to the original docs, it was added as a workaround for 3rd party playlist viewers not working with on_selection_changed(). So they're basically the same thing.
on_item_focus_change only triggers when the focused item has changed. Using Edit>Select all doesn't change the focused item.
And there is no such thing as on_item_selection_change().
on_playlist_items_selection_change()
That was missing from the docs so I need to update them. According to the original docs, it was added as a workaround for 3rd party playlist viewers not working with on_selection_changed(). So they're basically the same thing.
on_item_focus_change only triggers when the focused item has changed. Using Edit>Select all doesn't change the focused item.
And there is no such thing as on_item_selection_change().
Yes, that's the exact answer to the problem.
Thanks for the help.
I just realised on_playlist_items_selection_change() wasn't in the original docs either. My previous post about the workaround was taken from the changelog.
If you want the updated file to go in your docs folder, you can download it here:
https://raw.githubusercontent.com/19379/foo...s/Callbacks.txt (https://raw.githubusercontent.com/19379/foo-jscript-panel/master/foobar2000/foo_jscript_panel/docs/Callbacks.txt)
I'll update the component download later on.
Another question.
When drawing a gradrect over a semitransparent solidrect, an unexpected black border appears.
Just like this: http://imgur.com/qjrTKl6 (http://imgur.com/qjrTKl6)
(It's very dark; a black horizontal line in the middle; you may miss it)
I tried to change the smoothing mode, but it only got lightened, not disappeared.
Is this a bug in GDI or something like that? or I just used the wrong interface function?
This issue has been raised before and the original developer of WSH panel mod tried to fix it but it didn't go to plan....
https://www.hydrogenaud.io/forums/index.php...st&p=705543 (https://www.hydrogenaud.io/forums/index.php?s=&showtopic=70363&view=findpost&p=705543)
It seems from the preceding post that you can workaround it by increasing/decreasing the rectangle height by 1px.
This issue has been raised before and the original developer of WSH panel mod tried to fix it but it didn't go to plan....
https://www.hydrogenaud.io/forums/index.php...st&p=705543 (https://www.hydrogenaud.io/forums/index.php?s=&showtopic=70363&view=findpost&p=705543)
It seems from the preceding post that you can workaround it by increasing/decreasing the rectangle height by 1px.
Thanks for the answer. May it be fixed in the component, anyway? It may be problematic in adjustable DPIs...
From what I've read, the only "fixes" are hacks like adjusting the width/height/angle. From some quick testing, adjusting the angle by a degree or 2 can work rather well, assuming the dimensions aren't too small.
While I could implement this in the component, there's a possibility it could break some existing scripts that have worked fine up until this point. I'm not prepared to take that kind of risk so I'd rather keep the component behaviour consistent and let script writers fix these issues as they encounter them.
From what I've read, the only "fixes" are hacks like adjusting the width/height/angle. From some quick testing, adjusting the angle by a degree or 2 can work rather well, assuming the dimensions aren't too small.
While I could implement this in the component, there's a possibility it could break some existing scripts that have worked fine up until this point. I'm not prepared to take that kind of risk so I'd rather keep the component behaviour consistent and let script writers fix these issues as they encounter them.
Adjusting the angle by 1 degree worked. This idea is brilliant.
Another question:
In a single callback, is window.Repaint() only available to be called once?
i.e. If I use more than one window.Repaint() in one callback, is it that only the first one worked, and the others are ignored?
The situation is:
I have multiple rectangles on screen. The width of each rectangle is determined by the width of texts in it.
The method gr.CalcTextWidth(str, IGdiFont) can only be called within on_paint(gr), so the widths are not certain until a window.Repaint() is called.
In a callback, all the texts could be changed, so everything (including the text widths) needs to be refreshed. After the refreshment, some calculation should be done, and it need to be repainted again.
First of all, you can call window.Repaint as often as you like. The consequence of that may be increased CPU usage especially with large panels layering text/rectangles over images. For plain backgrounds, it usually isn't an issue. It's crude but I use Windows Task Manager to check...
However, in this instance you don't need to call window.Repaint. You can use temporary graphics like this...
function CalcTextWidth(value, font) {
var temp_bmp = gdi.CreateImage(1, 1);
var temp_gr = temp_bmp.GetGraphics();
var width = temp_gr.CalcTextWidth(value, font);
temp_bmp.ReleaseGraphics(temp_gr);
temp_bmp.Dispose();
temp_gr = null;
temp_bmp = null;
return width;
}
then
var font = gdi.Font("Segoe UI", 16);
var text = "fooby dooby doo";
var text_width = CalcTextWidth(text, font);
I don't think this has been documented - I just picked it up from other people's scripts. I'll stick something on my wiki pages in the next day or two with some more examples.
That's really a good idea - I should take a note.
Thanks.
Sorry it's me again......
Now I'm learning about timers, and wondering that, within
window.SetInterval(function() {
HERE
},interval)
, what is the behaviour of keyword "this"?
this.refresh = function () {
if (this.refresh_frame_count != 0) {
window.ClearInterval(this.refresh_timer);
this.refresh_frame_count = 0;
this.refresh_timer = false;
}
window.RepaintRect(this.x, this.y, this.w, this.h);
this.refresh_timer = window.SetInterval(this.refresh_nested, this.refresh_interval);
}
this.refresh_nested = function () {
if (this.refresh_frame_count >= 1000 / this.refresh_interval) {
window.ClearInterval(this.refresh_timer);
this.refresh_frame_count = 0;
this.refresh_timer = false;
} else {
this.refresh_frame_count ++;
window.RepaintRect(this.x, this.y, this.w, this.h);
}
}
This part of code belong to example_object.
In this example, if I call "example_object.refresh", it only refreshes once, and the timer doesn't seem to work.
But once I changed all "this" in the code of "this.refresh_nested" to "example_object", the code worked properly, to refresh 25 times in a second.
I am confused by now. the keyword "this" is too convenient for me to be adapted. And given that the exact name of the used reference is uncertain:
var panel = new Array();
panel.push(new example_object);
panel.push(new example_object2);
(I used this kind of code because it's easy to form something like below)
function on_mouse_lbtn_down(x, y) {
for (i = 0; i < panel.length; i++) {
if (x >= panel[i].x && x < panel[i].x + panel[i].w && y >= panel[i].y && y < panel[i].y + panel[i].h) {
panel[i].lbtn_down(x, y);
}
}
}
I even don't know how to reference the correct variable name in "this.refresh_nested", if "this" is not an option.
Wait. This is hilarious. there actually is a "this" in the workable version of code.
this.refresh_timer = window.SetInterval(this.refresh_nested, this.refresh_interval);
"this.refresh_nested". How can that "this" work while the "this"'s within itself cannot?
Desperate.
Appendix: the full code
// ==PREPROCESSOR==
// @name "Seekbar"
// ==/PREPROCESSOR==
//--------
// General Functions
function RGB(r,g,b){ return (0xff000000|(r<<16)|(g<<8)|(b)); }
function RGBA(r,g,b,a){ return ((a<<24)|(r<<16)|(g<<8)|(b)); }
function TimeFmt(t){
var zpad = function(n){
var str = n.toString();
return (str.length<2) ? "0"+str : str;
}
var m = Math.floor(t/60); t-=m*60;
var s = Math.floor(t);
return m.toString()+":"+zpad(s);
}
// Global Variables
var theme_font = fb.TitleFormat("%theme_font%").Eval(true);
var panelh, panelw;
// for time display
/*
var
*/
// Seekbar
seekbar = function () {
this.init = function (x, y, w, h) {
this.name = seekbar;
this.font = gdi.Font(theme_font, 14, 2);
this.timewidth = window.GetProperty("seekbar_time_width",70);
this.iscd = window.GetProperty("seekbar_is_countdown",true);
this.handle_size = window.GetProperty("seekbar_handle_size__even_only",12);
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.drag = false;
this.seek = 0;
this.refresh_interval = window.GetProperty("seekbar_refresh_interval",40)
this.refresh_frame_count = 0;
this.refresh_timer = false;
this.bar = {
x: this.timewidth,
y: this.x + Math.floor(this.h / 2) - this.handle_size / 2,
w: this.w - 2 * this.timewidth
};
}
this.draw = function (gr) {
var newt = 0;
var pos = 0;
var t1, t2;
var length = fb.PlaybackLength;
if (length > 0) {
if (this.drag) {
newt = length * this.seek;
pos = this.bar.w * this.seek;
} else {
var pbkt = fb.PlaybackTime;
newt = pbkt;
pos = this.bar.w * (pbkt / length);
}
newt = (length < newt) ? length: (newt < 0) ? 0: newt;
t1 = TimeFmt (newt);
t2 = (this.iscd) ? " -" + TimeFmt(length - newt): TimeFmt(length);
} else {
t1 = t2 = "-:--";
}
gr.SetSmoothingMode(2);
gr.FillSolidRect(this.bar.x, this.bar.y + this.handle_size / 2 + 1, this.bar.w, 1, RGB(67,67,67));
gr.FillSolidRect(this.bar.x, this.bar.y + this.handle_size / 2 - 1, this.bar.w, 2, RGB(80,80,80));
gr.FillSolidRect(this.bar.x, this.bar.y + this.handle_size / 2 - 1, pos + 5, 2, RGB(223,232,4));
gr.FillEllipse(this.bar.x + pos - this.handle_size / 2 - 1, this.bar.y, this.handle_size, this.handle_size, RGB(180,180,180));
gr.FillEllipse(this.bar.x + pos - this.handle_size / 2, this.bar.y + 1, this.handle_size, this.handle_size, RGB(255,255,255));
var tformat = 0x00000001 | 0x00000004 | 0x00000400 | 0x00000800 | 0x00008000;
gr.GdiDrawText(t2, this.font, RGB(255,255,255), this.w - this.timewidth, this.y, this.timewidth, this.h, tformat);
gr.GdiDrawText(t1, this.font, RGB(255,255,255), this.x, this.y, this.timewidth, this.h, tformat);
}
this.key_down = function (key) {
switch (key) {
}
}
this.lbtn_down = function (x, y) {
if (x >= this.bar.x && x < this.bar.x + this.bar.w && y >= this.bar.y && y < this.bar.y + this.handle_size) this.drag = 1;
}
this.lbtn_up = function (x, y) {
if (this.drag) {
this.drag = 0;
this.seek = (x - this.bar.x) / this.bar.w;
this.seek = (this.seek < 0) ? 0 : (this.seek < 1) ? this.seek : 1;
fb.PlaybackTime = fb.PlaybackLength * this.seek;
} else if (x > this.bar.x + this.bar.w) {
var val;
val = this.iscd? false: true;
window.SetProperty("use_countdown", val)
this.iscd = val;
}
}
this.move = function (x, y) {
if (this.drag) {
this.seek = (x - this.bar.x) / this.bar.w;
this.seek = (this.seek < 0) ? 0 : (this.seek < 1) ? this.seek : 1;
window.RepaintRect(this.x, this.y, this.w, this.h);
}
}
this.refresh = function () {
if (this.refresh_frame_count != 0) {
window.ClearInterval(this.refresh_timer);
this.refresh_frame_count = 0;
this.refresh_timer = false;
}
window.RepaintRect(this.x, this.y, this.w, this.h);
this.refresh_timer = window.SetInterval(this.refresh_nested, this.refresh_interval);
}
this.refresh_nested = function () {
if (this.refresh_frame_count >= 1000 / this.refresh_interval) {
window.ClearInterval(this.refresh_timer);
this.refresh_frame_count = 0;
this.refresh_timer = false;
} else {
this.refresh_frame_count ++;
window.RepaintRect(this.x, this.y, this.w, this.h);
}
}
}
// Panel global variables
var panel = new Array();
panel.push(new seekbar);
function on_paint(gr) {
for (i = 0; i < panel.length; i++) {
panel[i].draw(gr);
}
}
function on_size() {
panelw = window.Width;
panelh = window.Height;
panel[0].init(0, 0, panelw, panelh);
}
function on_key_down(key) {
}
function on_mouse_lbtn_down(x, y) {
for (i = 0; i < panel.length; i++) {
if (x >= panel[i].x && x < panel[i].x + panel[i].w && y >= panel[i].y && y < panel[i].y + panel[i].h) {
panel[i].lbtn_down(x, y);
}
}
}
function on_mouse_lbtn_up(x, y) {
for (i = 0; i < panel.length; i++) {
if (x >= panel[i].x && x < panel[i].x + panel[i].w && y >= panel[i].y && y < panel[i].y + panel[i].h) {
panel[i].lbtn_up(x, y);
}
}
}
function on_mouse_move(x, y) {
for (i = 0; i < panel.length; i++) {
panel[i].move(x, y);
}
}
function on_mouse_wheel(delta) {
}
function on_playback_starting(cmd, paused){
}
function on_playback_new_track(info){
panel[0].refresh();
}
function on_playback_stop(){
window.Repaint();
}
function on_playback_seek(time){
panel[0].refresh();
}
function on_playback_pause(state){
panel[0].refresh();
}
function on_playback_edited(){
}
function on_playback_dynamic_info(){
}
function on_playback_dynamic_info_track(){
}
function on_playback_time(time){
panel[0].refresh();
}
function on_volume_change(val){
}
You're having a problem with
variable scope. That's something you might want to research when you have the time.
Workarounds:
1) When inside your
on_playback_seek callback, you're calling your
Refresh function using the external name. There's no reason why you can't do the same from inside your
SetInterval function.
2) If you google the term I mentioned, you'll find assigning
this to another variable works.
function timer() {
this.x = 0;
var that = this;
window.SetInterval(function () {
that.x++;
fb.trace(that.x);
}, 200);
}
var t = new timer();
3) If you were developing in an environment that supports ECMAscript 5, you could use the
bind function. Unfortunately, windows script host only support ECMAscript 3. However, you can work around that by adding a polyfill (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind#Polyfill)
If you added that snippet in to your code, you can use it like this...
function timer() {
this.func = function () {
this.x++;
fb.trace(this.x);
}
this.x = 0;
window.SetInterval(this.func.bind(this), 200);
}
var t = new timer();
4) Rather than using a polyfill for each new fangled javascript function you might want to try, you could use a library like lodash (https://lodash.com/) which is what I currently do. I have the same issue not being able to use
this inside the xmlhttp onreadystatechange function. You can see an example of how I use that here...
https://github.com/19379/js-marc2003/blob/0...ist.js#L693L702 (https://github.com/19379/js-marc2003/blob/0242357106591c627f62c71ec5ed9c6faa673ae4/js/list.js#L693L702)
If you do decide to try lodash, get the compat (https://raw.githubusercontent.com/lodash/lodash-compat/3.10.1/lodash.min.js) version and import it in your preprocessor section.
I know you didn't ask for other advice but I'm giving it anyway...
1) I wouldn't bother creating/clearing/recreating timers. I just create one on startup and let it run indefinitely. In a seekbar example, I'd do this...
window.SetInterval(function () {
if (fb.IsPlaying && !fb.IsPaused && fb.PlaybackLength > 0) {
refresh();
}
}, 100);
2) This is rather unnecessary.
var val;
val = this.iscd? false: true;
window.SetProperty("use_countdown", val)
this.iscd = val;
You can toggle true/false like this and without creating extra variables...
this.iscd = !this.iscd
window.SetProperty("use_countdown", this.iscd)
Also, you could tidy up other areas of the code using the same principal as above.
Thanks for the reply! It's far more useful than I expected.
I'm feeling silly now for the additional advise 2.
It's official... hell has finally frozen over. Last.fm are now allowing new API key signups.
http://www.last.fm/api/account/create (http://www.last.fm/api/account/create)
Before anyone gets too excited, large portions of it are utterly broken with no acknowledgement to the numerous repeated reports on their forums.
Hi marc2003, thanks for creating JScript Panel!
I wonder is it possible to modify last.fm bio script so that there will be artist photo behind the text? And I cant find where to edit script in order to change text color/placement etc.
Hi marc2003, thanks for creating JScript Panel!
I wonder is it possible to modify last.fm bio script so that there will be artist photo behind the text? And I cant find where to edit script in order to change text color/placement etc.
OK, I've found other sample script - Now Playing - it is what I was looking for. Only one problem - artist art doesn't download automatically.
Help needed for 2 questions:
1. Does fb.VolumeMute() have a different behaviour to the main menu command?
When first called, it mutes the volume, but when called for the second time, the volume won't resume.
2. Is there any function to draw a "glowing" shape?
I've seen the "glow text example", but did not find any reference to a shape to do so.
Appreciate any replies.
Only one problem - artist art doesn't download automatically.
That's by design and I'm not changing it.
1. Does fb.VolumeMute() have a different behaviour to the main menu command?
No. If you put that command in a blank panel, keep the configuration window open and repeatedly click
Apply, it toggles the volume between mute and the current value like you would expect.
I've seen the "glow text example", but did not find any reference to a shape to do so.
If you try the Guifx v2 Transports (http://blog.guifx.com/2009/04/02/guifx-v2-transport-font/) font, it has a few basic shapes. If that's not good enough, I'd probably use
gdi.Image on some image created in another program.
Hi, i would like if somebody would post the most minimal scripts (wsh/jspanel) for the seekbar and volume. (maybe even other things if you have the will.)
so... solid colors, black on white, just the pure script, no @import .js stuff. so i can learn from that.
There are already minimal scripts here i know, but i find them slightly modified and its hard to modify/remove things i dont want. i want to start from the begining, thus the request.
also..
2.
i know how to make a square and circle with gr.Fill ... and all
but how do i make a triangle pointing this > direction. maybe you are already figured for what
3.
this is more advanced i guess and probably off topic.
is there a plugin/script/anything that gives foobar an ASCII visualisation, like the ones you can occasionaly spot in ncmpcpp on linux.
1. #43 reply in this topic is my example of seekbar, though there still are some issues to solve...
2. You can use the polygon functions to draw triangles.
3. You mean the DOS-like interface? I guess you could make that with simply text drawing and on_key callbacks...
Btw I think I've got it how to draw infusing shadows: by box blur...
That may be slow, but as I hate external images, that's affordable.
Those who remain at Pentium 4 and win xp don't deserve to enjoy my creations. Yup.
Marc2003, I'm trying to combine AlbumArt sample with BoxBlur with no luck. Is it possible to do that albumart would be shown as blurry image?
Insert this directly after
var albumart = new _.albumart(0, 0, 0, 0);albumart.metadb_changed = function () {
if (panel.metadb) {
this.img && this.img.Dispose();
this.tooltip = "";
this.path = "";
var img = utils.GetAlbumArtV2(panel.metadb, this.id);
if (img) {
this.img = gdi.CreateImage(img.Width, img.Height);
var g = this.img.GetGraphics();
_.drawImage(g, img, 0, 0, img.Width, img.Height);
this.img.ReleaseGraphics(g);
this.img.BoxBlur(20, 2); //mess around with these values
utils.GetAlbumArtAsync(window.ID, panel.metadb, this.id, true, false, true);
}
window.Repaint();
}
}
I just realised the above snippet will crash when there is no album art. This fixes it...
albumart.metadb_changed = function () {
if (panel.metadb) {
this.img && this.img.Dispose();
this.tooltip = "";
this.path = "";
var img = utils.GetAlbumArtV2(panel.metadb, this.id);
if (img) {
this.img = gdi.CreateImage(img.Width, img.Height);
var g = this.img.GetGraphics();
_.drawImage(g, img, 0, 0, img.Width, img.Height);
this.img.ReleaseGraphics(g);
this.img.BoxBlur(20, 2); //mess around with these values
utils.GetAlbumArtAsync(window.ID, panel.metadb, this.id, true, false, true);
} else {
this.img = null;
}
window.Repaint();
}
}
Marc2000, beautiful!!! Thanks a lot!!! This is the result:
(http://i.imgur.com/yEkBfCA.png)
I'm using this code to love tracks with marc's button script
fb.RunContextCommand("Last.fm/Last.fm Love Track '" + fb.TitleFormat("%title%").Eval() + "' By '" + fb.TitleFormat("%artist%").Eval() + "'");
When i click on it it freezes the whole foobar for like two seconds for it to love track (not the playback ,but still very annoying- I can see this in the channel spectrum panel )
Is this a issue with Last.fm or what??
@marc
any chance including last.fm love/unlove part in your scripts(not playcount sync only love /unlove part)
It looks like you're using foo_softplaylists so I guess that is the culprit? Surely you get the same delay when using the right click menu from the playlist??
As for me providing a script, not much chance of that. I simply can't be bothered with last.fm any more. FWIW, my old WSH panel mod scripts can still love/unlove tracks. It's just the server response is broken meaning the script doesn't update foo_customdb or display any message. If you check the WSH script thread, I've posted a hack to fix that. Of course you'll need a copy of the old script because I don't keep any of my old stuff.
Ya same delay when using context menu nothing to do then
I thought old script broked with new update to last.fm
Guess i can use it then
Marc2003, can you show me a hint how to assign different font symbol to every element of PBOArray in PBOButton(Menu).txt sample? I'm trying to get rid of image icons at all.
I want to have button to love/unlove based on rating
if loved -> rating =5
Unlove -> rating = 0
buttons.buttons.love = new _.button(100, 0, 40, 40, {
normal: _.tf("%rating%", panel.metadb) == 5 ? "buttons\\love_h.png" :"buttons\\love.png",
hover :"buttons\\love_h.png"
}, function() {
_.tf("%rating%", panel.metadb) == 5 ?fb.GetNowPlaying().UpdateFileInfoSimple("RATING",5,"RATING"): fb.GetNowPlaying().UpdateFileInfoSimple("RATING", 0, "RATING");
}, "Love");
but it's not working
any idea why??
@awx, use an array like this.
var symbols = ["a", "b", "c", "d", "e", "f", "g"];
Replace each letter with the character(s) from your font. Then inside your
on_paint function, remove the code that draws the buttons and use gdi.DrawText with your custom font and this as the text
symbols[plman.PlaybackOrder]
@samithaj
panel.metadb.UpdateFileInfoSimple("RATING", panel.tf("%rating%") == 5 ? "" : 5);
Using double quotes deletes the tag. If you really want to write 0 then you can change it.
@samithaj
panel.metadb.UpdateFileInfoSimple("RATING", panel.tf("%rating%") == 5 ? "" : 5);
Using double quotes deletes the tag. If you really want to write 0 then you can change it.
Thanks that worked
After updating to change the icon to love_h.png i used
window.RepaintRect(buttons.buttons.love.x, buttons.buttons.love.y, buttons.buttons.love.w, buttons.buttons.love.h);
in the button's function
but it doesn't work, only after reloading the script it shows the updated icon image
sorry for all the stupid questions
Presumably your code that creates the button is inside the on_metadb_changed callback? If not, it should be. The window.RepaintRect should be last line of code inside the callback, not inside the button function.
Presumably your code that creates the button is inside the on_metadb_changed callback? If not, it should be. The window.RepaintRect should be last line of code inside the callback, not inside the button function.
worked after putting button inside the
on_metadb_changed callback
Thanks again
General question:
Is it possible to make a button in JScript with (switch to playlist) as menu?
Thx
Yes. If you browse samples that came with the component, take the
MainMenuManager All-In-One.txt script and replace the menu function with this:
function menu() {
var m = window.CreatePopupMenu();
m.AppendMenuItem(MF_GRAYED, 0, "Switch to..."); //you wouldn't use an ID of 0 with a normal menu item but it's ok because this is greyed out.
m.AppendMenuSeparator();
for (var i = 0; i < plman.PlaylistCount; i++) {
m.AppendMenuItem(MF_STRING, 1 + i, plman.GetPlaylistName(i).replace(/&/g, "&&"));
}
if (plman.ActivePlaylist > -1)
m.CheckMenuRadioItem(1, plman.PlaylistCount + 1, plman.ActivePlaylist + 1);
var idx = m.TrackPopupMenu(b.buttons.menu.x, b.buttons.menu.y);
if (idx > 0)
plman.ActivePlaylist = idx - 1;
m.Dispose();
}
General question:
Is it possible to make a button in JScript with (switch to playlist) as menu?
Thx
Yes. If you browse samples that came with the component, take the MainMenuManager All-In-One.txt script and replace the menu function with this:
function menu() {
var m = window.CreatePopupMenu();
m.AppendMenuItem(MF_GRAYED, 0, "Switch to..."); //you wouldn't use an ID of 0 with a normal menu item but it's ok because this is greyed out.
m.AppendMenuSeparator();
for (var i = 0; i < plman.PlaylistCount; i++) {
m.AppendMenuItem(MF_STRING, 1 + i, plman.GetPlaylistName(i).replace(/&/g, "&&"));
}
if (plman.ActivePlaylist > -1)
m.CheckMenuRadioItem(1, plman.PlaylistCount + 1, plman.ActivePlaylist + 1);
var idx = m.TrackPopupMenu(b.buttons.menu.x, b.buttons.menu.y);
if (idx > 0)
plman.ActivePlaylist = idx - 1;
m.Dispose();
}
Thank you working!!!! Great
I'm not really sure why you removed the file. The error tells you exactly what to do:
"It appears the cached file has been corrupted. Use the right click menu>Force Update to try again."
If it's happening randomly (fixed by a forced update) then there isn't much I can do. If you can't get the bio of specific artist with multiple retries then I can take a look if you tell me what the artist is.
edit: If you reply, please do it in the script thread: https://www.hydrogenaud.io/forums/index.php?showtopic=110516 (https://www.hydrogenaud.io/forums/index.php?showtopic=110516)
I had tried numerous times to update it, but that did not work so I tried removing the file to see if that would. As I mentioned in the other thread, other info (similar artist, other releases) does fetch fine.
This has happened with a few artists but the last 2 are
http://www.last.fm/music/This+Will+Destroy+You (http://www.last.fm/music/This+Will+Destroy+You)
http://www.last.fm/music/Maybeshewill (http://www.last.fm/music/Maybeshewill)
Thanks
They both work fine for me so I blame your computer or internet connection.
Open
js_marc2003\js\text.js in a text editor, go to line 338 and replace this...
case "lastfm_bio":
var content = _(_.getElementsByTagName(this.xmlhttp.responsetext, "div"))
.filter({"className" : "wiki-content"})
.map("innerHTML")
.stripTags()
.value();
_.save(JSON.stringify([content]), f);
this.artist = "";
panel.item_focus_change();
break;
with
case "lastfm_bio":
fb.ShowPopupMessage(this.xmlhttp.responsetext, 1);
var content = _(_.getElementsByTagName(this.xmlhttp.responsetext, "div"))
.filter({"className" : "wiki-content"})
.map("innerHTML")
.value();
fb.ShowPopupMessage(content, 2);
content = _.stripTags(content);
fb.ShowPopupMessage(content, 3);
fb.ShowPopupMessage(JSON.stringify([content]), 4);
break;
Delete the cached file and then let the script run. 4 popup windows should open at once and I'd like to see the contents of each one. Each window will be labelled with a number 1-4. Use something like pastebin for the first window because it should be a large chunk of html.
They both work fine for me so I blame your computer or internet connection.
Delete the cached file and then let the script run. 4 popup windows should open at once and I'd like to see the contents of each one. Each window will be labelled with a number 1-4. Use something like pastebin for the first window because it should be a large chunk of html.
Damn computer
Those other 3 windows did indeed show the bio.
HTML
https://copy.com/9Ui6X0t3qXJz9MKt (https://copy.com/9Ui6X0t3qXJz9MKt)
Window 2
https://copy.com/lQLIBInfZ1UKmijH (https://copy.com/lQLIBInfZ1UKmijH)
Window 3
https://copy.com/9N1lCTnCfoImIXA1 (https://copy.com/9N1lCTnCfoImIXA1)
Window 4
https://copy.com/iGxONECt8hWOdFnf (https://copy.com/iGxONECt8hWOdFnf)
Thanks
Well if the bio is fine there, the only thing that can break it from that point onwards is the process of saving it to disk. All my scripts use the same _.save function though so I can't explain why it only seems to happen randomly in the bio script???
Well if the bio is fine there, the only thing that can break it from that point onwards is the process of saving it to disk. All my scripts use the same _.save function though so I can't explain why it only seems to happen randomly in the bio script???
It does create a "bio.www.last.fm.json" file but it's empty. When I try to copy and paste from the actual bio, the file gets wiped once I play a song. I made the file "read only" but even that never gets loaded. However, if I choose another Last.fm site, it works . Now I just need to brush up on my French or German or Italian or etc.
Oh well, thanks for your time.
Cheers
However, if I choose another Last.fm site, it works
That really makes no sense at all. But given your location says Canada, French should be no problem for you.
I have a panel for "playback button + status bar" within single panel.
The little buggy point is that the panel doesn't refresh when I resize foobar.
The buttons and status information stick to the initial postion even after I resized my foobar.
So, I want to know if there is any method to refresh this panel whenever I change the foobar size.
Thank you for your help.
// ==PREPROCESSOR==
// @name "Playback Buttons"
// @author "marc2003"
// @import "%fb2k_profile_path%js_marc2003\js\lodash.min.js"
// @import "%fb2k_profile_path%js_marc2003\js\helpers.js"
// @import "%fb2k_profile_path%js_marc2003\js\panel.js"
// ==/PREPROCESSOR==
var panel = new _.panel("Playback Buttons", ["custom_background"]);
var buttons = new _.buttons();
var bs = 32;
var guifx_font = _.gdiFont(guifx.font, 8, 1);
var ww = window.Width;
var wh = window.Height;
var left_text_tf = "%playback_time%[ / %length%] :: %__bitrate% kbps %codec% [%codec_profile% ]";
var text_colour = _.RGB(40, 40, 40);
var show_volume = window.GetProperty("2K3.STATUS.SHOW.VOLUME", true);
var font = _.gdiFont("Segoe UI", 11);
var count = 0;
var right_text = "";
var right_text_width = 0;
refresh();
buttons.buttons.menu = new _.button(5, 5, bs, bs, {normal : "buttons\\menu.png"}, function () { _.menu(0, 16); }, "Menu");
buttons.buttons.stop = new _.button(ww/2-2*bs-15, 5, bs, bs, {normal : "buttons\\stop.png"}, function () { fb.Stop(); }, "Stop");
buttons.buttons.play = new _.button(ww/2-bs-5, 5, bs, bs, {normal : !fb.IsPlaying || fb.IsPaused ? "buttons\\play.png" : "buttons\\pause.png"}, function () { fb.PlayOrPause(); }, !fb.IsPlaying || fb.IsPaused ? "Play" : "Pause");
buttons.buttons.previous = new _.button(ww/2+5, 5, bs, bs, {normal : "buttons\\previous.png"}, function () { fb.Prev(); }, "Previous");
buttons.buttons.next = new _.button(ww/2+bs+15, 5, bs, bs, {normal : "buttons\\next.png"}, function () { fb.Next(); }, "Next");
buttons.update = function () {
this.buttons.play = new _.button(ww/2-bs-5, 5, bs, bs, {normal : !fb.IsPlaying || fb.IsPaused ? "buttons\\play.png" : "buttons\\pause.png"}, function () { fb.PlayOrPause(); }, !fb.IsPlaying || fb.IsPaused ? "Play" : "Pause");
window.RepaintRect(this.buttons.play.x, this.buttons.play.y, this.buttons.play.w, this.buttons.play.h);
}
function on_playlist_stop_after_current_changed() {
window.RepaintRect(buttons.buttons.stop.x, buttons.buttons.stop.y, buttons.buttons.stop.w, buttons.buttons.stop.h);
}
function on_size() {
panel.size();
window.MinHeight = 45;
window.MaxHeight = 45;
}
function on_paint(gr) {
panel.paint(gr);
buttons.paint(gr);
gr.SetTextRenderingHint(4);
if (fb.StopAfterCurrent)
gr.DrawString("", guifx_font, _.RGB(196, 30, 35), buttons.buttons.stop.x, buttons.buttons.stop.y + 1, buttons.buttons.stop.w, buttons.buttons.stop.h, SF_CENTRE);
if (fb.IsPlaying)
gr.GdiDrawText(_.tfe(left_text_tf), font, text_colour, 0, 2, ww - 55, font.Height, RIGHT);
if (count > 0)
gr.GdiDrawText(right_text, font, text_colour, 0, 22, ww - 5, font.Height, RIGHT);
if (show_volume)
gr.GdiDrawText(fb.Volume.toFixed(2) + " dB", font, text_colour, 0, 2, ww - 5, font.Height, RIGHT);
}
function on_playback_stop() {
buttons.update();
window.Repaint();
}
function on_playback_pause() {
buttons.update();
}
function on_playback_starting() {
buttons.update();
}
function on_mouse_move(x, y) {
buttons.move(x, y);
}
function on_mouse_leave() {
buttons.leave();
}
function on_mouse_lbtn_up(x, y) {
buttons.lbtn_up(x, y);
}
function on_mouse_rbtn_up(x, y) {
if (buttons.buttons.stop.trace(x, y)) {
var m = window.CreatePopupMenu();
m.AppendMenuItem(MF_STRING, 1, "Stop After Current");
m.CheckMenuItem(1, fb.StopAfterCurrent);
m.AppendMenuSeparator();
m.AppendMenuItem(MF_STRING, 2, "Configure...");
var idx = m.TrackPopupMenu(x, y);
if (idx == 1)
fb.StopAfterCurrent = !fb.StopAfterCurrent;
else if (idx == 2)
window.ShowConfigure();
m.Dispose();
return true;
} else {
return panel.rbtn_up(x, y);
}
}
function on_playback_time() {
window.Repaint();
}
function on_volume_change() {
window.Repaint();
}
function on_mouse_wheel(s) {
if (!show_volume)
return;
if (s == 1)
fb.VolumeUp();
else
fb.VolumeDown();
}
function on_mouse_lbtn_dblclk() {
fb.RunMainMenuCommand("View/Show now playing in playlist");
}
function on_mouse_rbtn_up(x, y) {
if (utils.IsKeyPressed(VK_SHIFT))
return false;
var m = window.CreatePopupMenu();
var c = fb.CreateContextMenuManager();
if (fb.IsPlaying) {
c.InitNowPlaying();
c.BuildMenu(m, 1, -1);
m.AppendMenuSeparator();
}
m.AppendMenuItem(MF_STRING, 10000, "Show volume");
m.CheckMenuItem(10000, show_volume);
m.AppendMenuSeparator();
m.AppendMenuItem(MF_STRING, 10001, "Configure...");
var idx = m.TrackPopupMenu(x, y);
switch (true) {
case idx == 0:
break;
case idx == 10000:
show_volume = !show_volume;
window.SetProperty("2K3.STATUS.SHOW.VOLUME", show_volume);
window.Repaint();
break;
case idx == 10001:
window.ShowConfigure();
break;
default:
c.ExecuteByID(idx - 1);
break;
}
m.Dispose();
c.Dispose();
return true;
}
function on_playlist_items_added(p) {
if (p == plman.ActivePlaylist)
refresh();
}
function on_playlist_items_removed(p) {
if (p == plman.ActivePlaylist)
refresh();
}
function on_playlist_switch() {
refresh();
}
function refresh() {
var items = plman.GetPlaylistItems(plman.ActivePlaylist);
count = items.Count;
right_text = count + (count == 1 ? " track :: " : " tracks :: ") + utils.FormatDuration(items.CalcTotalDuration()) + " :: " + utils.FormatFileSize(items.CalcTotalSize());
right_text_width = _.textWidth(right_text, font);
window.Repaint();
items.Dispose();
}
Get rid of the ww/wh variables and use panel.w and panel.h instead. Also, your buttons should go inside the on_size function, after panel.size().
Get rid of the ww/wh variables and use panel.w and panel.h instead. Also, your buttons should go inside the on_size function, after panel.size().
It works well. Thank you, marc2003!
However, if I choose another Last.fm site, it works
That really makes no sense at all. But given your location says Canada, French should be no problem for you.
huzzah, saw on Devart that someone else is having the same problem as me so it isn't my puter.
Hello, I got some songs fetching last.fm artist biography get some error on foobar
Unable to get property 'length' of undefined or null reference
File: D:\Program Files\foobar2000\skins\Zetro\scripts\text.js
Line: 249, Col: 25
how to fix this?
any ideas?
Thanks
huzzah, saw on Devart that someone else is having the same problem as me so it isn't my puter.
It just means both of your computers are broken and should be disposed of at once.
I don't have a serious reply because you said yourself it works with languages other than English. There is nothing I can think of to troubleshoot an issue like that.
huzzah, saw on Devart that someone else is having the same problem as me so it isn't my puter.
It just means both of your computers are broken and should be disposed of at once.
I don't have a serious reply because you said yourself it works with languages other than English. There is nothing I can think of to troubleshoot an issue like that.
Oh well, thanks again for your time
Does anyone have some recommended resources/references I can take a look at? I've taken a look at some of Marc's sample scripts and just want to see examples of what I could do to modify the look to my ideal set-up.
I'm especially interested in the drawing functions; shadows, border, gradient, etc.
Get rid of the ww/wh variables and use panel.w and panel.h instead. Also, your buttons should go inside the on_size function, after panel.size().
I'm having a similar problem. The values of panel.w and panel.h are equal to 0 so they are not useful for my purpose.
I need the values of window.height and window.width to automatically update.
// ==PREPROCESSOR==
// @name "np_basic"
// @author "marc2003"
// @import "%fb2k_profile_path%js_marc2003\js\lodash.min.js"
// @import "%fb2k_profile_path%js_marc2003\js\helpers.js"
// @import "%fb2k_profile_path%js_marc2003\js\panel.js"
// @import "%fb2k_profile_path%js_marc2003\js\thumbs.js"java script:bbc_pop()
// @import "%fb2k_profile_path%js_marc2003\js\text.js"
// @import "%fb2k_profile_path%js_marc2003\js\rating.js"
// ==/PREPROCESSOR==
//the track info section displays 3 lines of title formatted text. you can customise that here/////////////////////////////////////////////
var line1 = {
text: "", //leave this blank
tf: "%title%", //enter any title formatting
font: _.gdiFont("Calibri", 24, 0), //font name, size, style. 1 means bold and 0 is normal.
colour: _.RGB(240, 240, 240), //colour
y: 0 //change this value to move text up or down.
}
var line2 = {
text: "",
tf: "%album artist% - %album%",
font: _.gdiFont("Segoe UI", 16, 0),
colour: _.RGB(240, 240, 240),
y: 40
}
var line3 = {
text: "",
tf: "[%album% ]['('%date%')']",
font: _.gdiFont("Segoe UI", 14, 1),
colour: _.RGB(180, 180, 180),
y: 65
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
var panel = new _.panel("np_basic", ["metadb", "remap", "custom_background"]);
var text = new _.text("lastfm_bio", 20, 0, 0, 0);
var thumbs = new _.thumbs();
var panw = window.Width; // panel width
var pan_h = window.Height; // panel height
thumbs.mode = 5;
var bar_h = 80; // height of the title stuff
var buttons = new _.buttons();
var mbuts = 48; // menu button size
buttons.buttons.menu = new _.button( panw - 5 - mbuts, (bar_h - mbuts) / 2, mbuts, mbuts, {normal : "misc\\foobar2000.png"}, function () { _.menu(0, 36); }, "Menu");
var guifx_font = _.gdiFont(guifx.font, 8, 1);
//rating
var r_x = (panw - 28 * 5) / 2; // rating buttons starting x position
var r_y = bar_h + 5; //rating buttons starting y position
var rating = new _.rating(r_x, r_y, 28, _.RGB(128, 128, 128), _.RGB(255, 128, 0));
//playback buttons
var bs = 80; // playback buttons size
var strpnt_x = (panw - bs) / 2; // playback buttons starting x position
var strpnt_y = pan_h - 100; // playback buttons starting y position
buttons.buttons.stop = new _.button(strpnt_x - bs * 3, strpnt_y, bs, bs , {normal : "buttons\\stop.png"}, function () { fb.Stop(); }, "Stop");
buttons.buttons.play = new _.button(strpnt_x, strpnt_y, bs, bs, {normal : !fb.IsPlaying || fb.IsPaused ? "buttons\\play.png" : "buttons\\pause.png"}, function () { fb.PlayOrPause(); }, !fb.IsPlaying || fb.IsPaused ? "Play" : "Pause");
buttons.buttons.previous = new _.button(strpnt_x - bs * 1.5, strpnt_y, bs, bs, {normal : "buttons\\previous.png"}, function () { fb.Prev(); }, "Previous");
buttons.buttons.next = new _.button(strpnt_x + bs * 1.5 , strpnt_y, bs, bs, {normal : "buttons\\next.png"}, function () { fb.Next(); }, "Next");
buttons.buttons.next1 = new _.button(strpnt_x + bs * 3, strpnt_y, bs, bs, {normal : "buttons\\next.png"}, function () { fb.Next(); }, "Next");
buttons.update = function () {
this.buttons.play = new _.button(bs, 0, bs, bs, {normal : !fb.IsPlaying || fb.IsPaused ? "buttons\\play.png" : "buttons\\pause.png"}, function () { fb.PlayOrPause(); }, !fb.IsPlaying || fb.IsPaused ? "Play" : "Pause");
window.RepaintRect(this.buttons.play.x, this.buttons.play.y, this.buttons.play.w, this.buttons.play.h);
}
panel.item_focus_change();
function on_size() {
panel.size();
thumbs.size();
text.y = _.floor(panel.h * 0.75);
text.w = panel.w - 40
text.h = panel.h - text.y - 5;
text.size();
}
function on_paint(gr) {
panel.colours.text = _.RGB(220, 220, 220);
panel.paint(gr);
thumbs.paint(gr);
gr.FillSolidRect(0, 0, panel.w, bar_h, _.RGBA(0, 0, 0, 196));
gr.GdiDrawText(line1.text, line1.font, line1.colour, 10, line1.y, panel.w - 20, line1.font.Height, LEFT);
gr.GdiDrawText(line2.text, line2.font, line2.colour, 10, line2.y, panel.w - 20, line2.font.Height, LEFT);
//gr.GdiDrawText(line3.text, line3.font, line3.colour, 10, line3.y, panel.w - 20, line3.font.Height, LEFT);
//gr.FillSolidRect(text.x - 15, text.y, text.w + 30, text.h, _.RGBA(0, 0, 0, 156));
text.paint(gr);
buttons.paint(gr);
gr.SetTextRenderingHint(4);
if (fb.StopAfterCurrent)
gr.DrawString("4", guifx_font, _.RGB(196, 30, 35), buttons.buttons.stop.x, buttons.buttons.stop.y + 1, buttons.buttons.stop.w, buttons.buttons.stop.h, SF_CENTRE);
rating.paint(gr);
}
function on_metadb_changed() {
thumbs.metadb_changed();
//text.metadb_changed();
if (panel.metadb) {
line1.text = panel.tf(line1.tf);
line2.text = panel.tf(line2.tf);
line3.text = panel.tf(line3.tf);
}
window.Repaint();
rating.metadb_changed();
}
function on_playlist_stop_after_current_changed() {
window.RepaintRect(buttons.buttons.stop.x, buttons.buttons.stop.y, buttons.buttons.stop.w, buttons.buttons.stop.h);
}
function on_playback_stop() {
buttons.update();
}
function on_playback_pause() {
buttons.update();
}
function on_playback_starting() {
buttons.update();
}
function on_mouse_move(x, y) {
buttons.move(x, y);
rating.move(x, y);
}
function on_mouse_leave() {
buttons.leave();
rating.leave();
}
function on_mouse_lbtn_up(x, y) {
buttons.lbtn_up(x, y);
rating.lbtn_up(x, y);
}
function on_mouse_rbtn_up(x, y) {
return panel.rbtn_up(x, y);
if (buttons.buttons.stop.trace(x, y)) {
var m = window.CreatePopupMenu();
m.AppendMenuItem(MF_STRING, 1, "Stop After Current");
m.CheckMenuItem(1, fb.StopAfterCurrent);
m.AppendMenuSeparator();
m.AppendMenuItem(MF_STRING, 2, "Configure...");
var idx = m.TrackPopupMenu(x, y);
if (idx == 1)
fb.StopAfterCurrent = !fb.StopAfterCurrent;
else if (idx == 2)
window.ShowConfigure();
m.Dispose();
return true;
} else {
return panel.rbtn_up(x, y);
}
}
Sorry if its a bit messy.
Hey all, thanks marc2003, Br3tt and everyone else for your work. I've just installed the "foo_jscript_panel-v1.0.7.fb2k-component" and Br3tt's JS Smooth script.
When I import it, I get the following in the console:
One JScript panel said:
The following preprocessor @import file(s) were not found:
C:\Users\Ben\AppData\Roaming\foobar2000\js_br3tt\jssb\js\JScommon.js
C:\Users\Ben\AppData\Roaming\foobar2000\js_br3tt\jssb\js\JSinputbox.js
And the console said:
JScript Panel ({A1765CC9-04BD-4F05-A555-F42F57233ACE}): initialized in 0 ms
Error: JScript Panel (JS Smooth Browser v20151114-1630-340 by Br3tt aka Falstaff >> http://br3tt.deviantart.com): (http://br3tt.deviantart.com):) Parsing file "C:\Users\Ben\AppData\Roaming\foobar2000\js_br3tt\jssb\js\JScommon.js": Failed to load.
Error: JScript Panel (JS Smooth Browser v20151114-1630-340 by Br3tt aka Falstaff >> http://br3tt.deviantart.com): (http://br3tt.deviantart.com):) Parsing file "C:\Users\Ben\AppData\Roaming\foobar2000\js_br3tt\jssb\js\JSinputbox.js": Failed to load.
Error: JScript Panel (JS Smooth Browser v20151114-1630-340 by Br3tt aka Falstaff >> http://br3tt.deviantart.com): (http://br3tt.deviantart.com):) Microsoft JScript runtime error:
Object expected
File: <main>
Line: 126, Col: 1
<source text only available at compile time>
I had a look at the script and the only reference to those two variables are in a (commented out) preprocessor block as follows:
// ==PREPROCESSOR==
// @name "JS Smooth Browser"
// @version "20151114-1630-340"
// @author "Br3tt aka Falstaff >> http://br3tt.deviantart.com" (http://br3tt.deviantart.com")
// @feature "v1.4"
// @feature "watch-metadb"
// @import "%fb2k_profile_path%js_br3tt\jssb\js\JScommon.js"
// @import "%fb2k_profile_path%js_br3tt\jssb\js\JSinputbox.js"
// ==/PREPROCESSOR==
I tried changing the path to the actual location (my foobar install isn't where it went looking), but that only gave a different error.
Any ideas? Please let me know if you need more information to debug/identify. Thanks in advance.
I'm in the process of migrating from foo_uie_biography and I have some questions.
I would like to recreate my original panel (top picture) as closest as possible using your last.fm biography script (bottom). This means no headers, very small margins and the text filling as much space as it can. I removed the corresponding lines which draw the header and the square behind it and tried to adjust the position of the text. However at the top and the bottom there are white spaces that I can't get rid of (and text can't flow there). Any idea how to do that? I'd imagine that's governed by one of the prerequisites in \js\, but it would take me a long time to figure anything out there.
Furthermore, foo_uie_biography had an option for short descriptions. This most of the time meant the pulled text fit the given area perfectly, unlike your script which downloads the entire page. This often results in even just the main paragraph running out of bounds and any further information is also only accessible after scrolling down. Which I rarely do, so I won't need that. Is the short description part of the API still usable? Can this be added to the script?
It also appears that this version of your thumbs script doesn't have an automatic download function. Is this the result of some API changes at last.fm or simply a precaution so people don't spam your API key? Can this be readded with the criterion that everyone must acquire and use their own key? If not, do you know if the old script is still technically operational (as long as I switch to my key)?
(http://i.imgur.com/LEcx9HH.png)
The slightly modified last.fm biography script:
// ==PREPROCESSOR==
// @name "Last.fm Bio"
// @author "marc2003"
// @import "%fb2k_profile_path%js_marc2003\js\lodash.min.js"
// @import "%fb2k_profile_path%js_marc2003\js\helpers.js"
// @import "%fb2k_profile_path%js_marc2003\js\panel.js"
// @import "%fb2k_profile_path%js_marc2003\js\text.js"
// ==/PREPROCESSOR==
var panel = new _.panel("Last.fm Bio", ["metadb", "remap"]);
var text = new _.text("lastfm_bio", 0, 0, 0, 0);
panel.item_focus_change();
function on_size() {
panel.size();
text.w = panel.w;
text.h = panel.h;
text.size();
}
function on_paint(gr) {
panel.paint(gr);
text.paint(gr);
}
function on_metadb_changed() {
text.metadb_changed();
}
function on_mouse_wheel(s) {
text.wheel(s);
}
function on_mouse_move(x, y) {
text.move(x, y);
}
function on_mouse_lbtn_up(x, y) {
text.lbtn_up(x, y);
}
function on_key_down(k) {
text.key_down(k);
}
function on_mouse_rbtn_up(x, y) {
return panel.rbtn_up(x, y, text);
}
Hi!
Sorry for this very stupid question, but what is the color code to use with FillSolidRect function ?
If I use hex color code such as 0x0080C0 it doesn't work (although this code is ok when I use GdiDrawText function).
Thanks in advance
Something like this should work.
gr.FillSolidRect(0, 0, panel.w, panel.h, _.RGB(150,150,250));
I'm examining some of the samples that came along with the plugin. The one I'm interested in is the "Themed Seek Bar" and I am having a hard time understanding how to color it so say white rather than the default green and keep the default style.
// ==PREPROCESSOR==
// @name "Themed Seek Bar"
// @author "marc2003"
// @import "%fb2k_component_path%docs\helpers.txt"
// ==/PREPROCESSOR==
var tooltip = window.CreateTooltip();
var g_theme = window.CreateThemeManager("PROGRESS");
// seekbar is defined inside docs\helpers.txt
// 4 arguments are x, y, w, h
// y and w are dynamic based on panel size so we set those inside on_size function
var s = new seekbar(10, 0, 0, 20);
function on_size() {
s.y = Math.floor((window.Height - 20) / 2);
//because we've set x 10 pixels from the left, the seekbar width can be the panel
//width minus 20 pixels to leave the same gap on the right side.
s.w = window.Width - 20;
}
function on_paint(gr) {
g_theme.SetPartAndStateID(1, 0);
g_theme.DrawThemeBackground(gr, s.x, s.y, s.w, s.h);
if (fb.IsPlaying && fb.PlaybackLength > 0) {
g_theme.SetPartAndStateID(5, fb.IsPaused ? 3 : 1);
g_theme.DrawThemeBackground(gr, s.x, s.y, s.pos(), s.h);
}
}
function on_playback_seek() {
s.playback_seek();
}
function on_playback_stop() {
s.playback_stop();
}
function on_mouse_wheel(s) {
s.wheel(s);
}
function on_mouse_move(x, y) {
s.move(x, y);
}
function on_mouse_lbtn_down(x, y) {
s.lbtn_down(x, y);
}
function on_mouse_lbtn_up(x, y) {
s.lbtn_up(x, y);
}
Something like this should work.
Thanks !
I'm in the process of migrating from foo_uie_biography and I have some questions.
I would like to recreate my original panel (top picture) as closest as possible using your last.fm biography script (bottom). This means no headers, very small margins and the text filling as much space as it can. I removed the corresponding lines which draw the header and the square behind it and tried to adjust the position of the text. However at the top and the bottom there are white spaces that I can't get rid of (and text can't flow there). Any idea how to do that? I'd imagine that's governed by one of the prerequisites in \js\, but it would take me a long time to figure anything out there.
You can try something like
var text = new _.text("lastfm_bio", 0, -10, 0, 0);
text.h = panel.h+20;
Works, thanks. Seems like I forgot you can add to the add to the height of the text panel not just remove the subtraction.
Hey all, thanks marc2003, Br3tt and everyone else for your work. I've just installed the "foo_jscript_panel-v1.0.7.fb2k-component" and Br3tt's JS Smooth script.
When I import it, I get the following in the console:
One JScript panel said:
The following preprocessor @import file(s) were not found:
C:\Users\Ben\AppData\Roaming\foobar2000\js_br3tt\jssb\js\JScommon.js
C:\Users\Ben\AppData\Roaming\foobar2000\js_br3tt\jssb\js\JSinputbox.js
And the console said:
JScript Panel ({A1765CC9-04BD-4F05-A555-F42F57233ACE}): initialized in 0 ms
Error: JScript Panel (JS Smooth Browser v20151114-1630-340 by Br3tt aka Falstaff >> http://br3tt.deviantart.com): (http://br3tt.deviantart.com):) Parsing file "C:\Users\Ben\AppData\Roaming\foobar2000\js_br3tt\jssb\js\JScommon.js": Failed to load.
Error: JScript Panel (JS Smooth Browser v20151114-1630-340 by Br3tt aka Falstaff >> http://br3tt.deviantart.com): (http://br3tt.deviantart.com):) Parsing file "C:\Users\Ben\AppData\Roaming\foobar2000\js_br3tt\jssb\js\JSinputbox.js": Failed to load.
Error: JScript Panel (JS Smooth Browser v20151114-1630-340 by Br3tt aka Falstaff >> http://br3tt.deviantart.com): (http://br3tt.deviantart.com):) Microsoft JScript runtime error:
Object expected
File: <main>
Line: 126, Col: 1
<source text only available at compile time>
I had a look at the script and the only reference to those two variables are in a (commented out) preprocessor block as follows:
// ==PREPROCESSOR==
// @name "JS Smooth Browser"
// @version "20151114-1630-340"
// @author "Br3tt aka Falstaff >> http://br3tt.deviantart.com" (http://br3tt.deviantart.com")
// @feature "v1.4"
// @feature "watch-metadb"
// @import "%fb2k_profile_path%js_br3tt\jssb\js\JScommon.js"
// @import "%fb2k_profile_path%js_br3tt\jssb\js\JSinputbox.js"
// ==/PREPROCESSOR==
I tried changing the path to the actual location (my foobar install isn't where it went looking), but that only gave a different error.
Any ideas? Please let me know if you need more information to debug/identify. Thanks in advance.
all is explained as well, the folder js_br3tt (that contain all ressources for the main script) MUST be in your foobar2000 profile folder, and it isn't !
the foobar2000 profile folder is the foobar2000 program folder if you have installed foobar2000 as a portable installation
else, if standard installation done, the profile folder is C:\Users\username\AppData\Roaming\foobar2000
you should figure it out, but if not, do not try to use scripts anymore and stay with basics interfaces and panels.
OH. Profile folder, not Foobar install folder. Misread the instructions. Thanks It's noticeably quicker than facets. Is there a way to make it even faster in loading up the album images? eg. using smaller image sizes or similar?
I don't have a serious reply because you said yourself it works with languages other than English. There is nothing I can think of to troubleshoot an issue like that.
Finally!! I got it sorted. It was the scripting engine.
I've tracked down the source of the problem but I have no idea why it fails in the JScript9 engine but not JScript. I have added a workaround though. This works in both engines.
https://raw.githubusercontent.com/19379/js-...ster/js/text.js (https://raw.githubusercontent.com/19379/js-marc2003/master/js/text.js)
Save it in js_marc2003\js
@Daeron, I don't use the API for bio text or images. That means fetching all text is mandatory but everything else is by design and I have no intention of changing it. I suppose cutting the text off at the first double line break to get the first paragraph could be possible if you feel like tinkering with it.
I've tracked down the source of the problem but I have no idea why it fails in the JScript9 engine but not JScript. I have added a workaround though. This works in both engines.
https://raw.githubusercontent.com/19379/js-...ster/js/text.js (https://raw.githubusercontent.com/19379/js-marc2003/master/js/text.js)
Thank you.
New for 2016 - JScript Library Tree
Download and info here (https://www.hydrogenaud.io/forums/index.php?showtopic=110938)
This is mostly regarding performance of foobar
I want change all of my JScript panel's (i have about 10 ) background colour on every playback of new song
I have two options
1)
put the the panel on transparent mode and
put
function on_playback_new_track() {
window.Reload();
}
on every panel because the transparent background doesn't change when new new playback occurs
Is there any way to do this without using window.Reload() ??
2)
Use function window.NotifyOthers() to pass the new background colors to all other panels and use that via on_notify_data(name, info)
I use window.Repaint() on that callback and i pass two values( background, foreground ) so i think window.Repaint will get called twice??
Is there a way to pass two values (array) by window.NotifyOthers ??
Either way i'm experiencing like 3 second lag in between when i change a track(not entirely sure this happen because of this but i guess it had to do something with window.Reload() window.Repaint() functions getting called lot of times)
so what is the best (faster) way to do this ?
and is there any other way to do this faster?
And one other question
So not all of my JScript panels are visible in one layout, they are hidden via panel stack splitter till assessed
so this hidden panels get affected too ? (will they be executed ?)
Pardon my English
If using panel stack splitter with a background image, position your panels using
Forced layout and
$movepanel /
$movepanel_cAnd yes, you can pass arrays with window.NotifyOthers. The docs even say so...
window.NotifyOthers(name, info); (void)
/*
name: string
info: all variable/array/object types should be supported
listen for notifications in other panels using on_notify_data(name, info) {}
*/
If using panel stack splitter with a background image, position your panels using Forced layout and $movepanel / $movepanel_c
Thing is i'm already using it like this , but background color stays the same colour when track changes (panel stack splitter's background color changes according to album artwork's Color Scheme)
only a
reload() in jscript panel or
REFRESH in panel stack splitter will ensure the colour will changed
any idea about that??
So I guess the using
window.NotifyOthers() is better because it uses only
repaint() rather than
reload() in transparent method
I realised later the 3 second delay was because of a silly mistake made by me while editing one of scripts
but there still some laggy behavior while changing the tracks
Could
on_notify_data(name, info) function being used in lot of panels can cause this??
I tested using panel stack splitter to display album art and had a pseudo-transparent JScript panel on top. It updates fine on a new track with different cover. Do you have your Panel stack splitter>script tab>titleformat mode on startup: set to now playing?
Yes
Evaluate scripts when track info is modified on behavior tab doesn't changes anything either :/
maybe it's because of i'm changing a color via $drawrect per track
Artwork change could be trigger a REFRESH maybe ??
I doubt it. The artwork is displayed using PSS $functions
$puts(bg.p,$directory_path(%path%)\cover.jpg)
$imageabs(,,,,$get(bg.p),nodisplay,,)
$puts(scale1,$div($mul(%_width%,10000),$getimagewidth($get(bg.p))))
$puts(scale2,$div($mul(%_height%,10000),$getimageheight($get(bg.p))))
$puts(scale,$max($get(scale1),$get(scale2)))
$puts(w,$ifgreater($get(scale1),$get(scale2),%_width%,$muldiv($getimagewidth($get(bg.p)),$get(scale),10000)))
$puts(h,$ifgreater($get(scale2),$get(scale1),%_height%,$muldiv($getimageheight($get(bg.p)),$get(scale),10000)))
$puts(x,$div($sub(%_width%,$get(w)),2))
$puts(d,$ifgreater(12,$div($mul($getimagewidth($get(bg.p)),10),$getimageheight($get(bg.p))),3,2))
$puts(y,$div($sub(%_height%,$get(h)),$get(d)))
$drawimage($get(x),$get(y),$get(w),$get(h),$get(bg.p),,,255)
That's wired i have to reload the script panel to get the updated image
I have my behavior tab with all options disabled what settings do you use??
now it works!!!
sorry for all the trouble
edit: nvm, you sorted it.
I had my jscript panels on top of another panel stack splitter and in them no forced layout only on the outer panel
using only a jscript panel it works!!
Thank you very much for pointing me in the right direction
sorry for all the trouble
Hello,
Does someone know a way to play a different track from an already playing playlist without activating the playlist ?
With plman.ExecutePlaylistDefaultAction(), if the target playlist is already playing but not active, the default action seems to be to stop playback, you can try with the code sample below, instead of playing the first track of the playing playlist on double click, it will stop playback
function on_mouse_lbtn_dblclk(){
plman.ExecutePlaylistDefaultAction(plman.playingPlaylist, 0);
}
For me it plays the selected track from the active playlist which is completely wrong. I guess that's because I've altered my playback follows currsor/cursor follows playback settings. It seems the function plain doesn't work unless you feed it the active playlist as the playlist argument. Given its pretty much direct access to the SDK method, there isn't anything I can do. I do wonder if it's broken given this post from 2008 accurately describes the same issue...
https://www.hydrogenaud.io/forums/index.php..._default_action (https://www.hydrogenaud.io/forums/index.php?showtopic=62390&hl=playlist_execute_default_action)
marc2003, is there an example script calling context menu command(s) on a selection?
Is it possible to execute a script from context menu itself?
var selected_items = plman.GetPlaylistSelectedItems(plman.ActivePlaylist);
fb.RunContextCommandWithMetadb("Properties", selected_items);
Just modify the text in quotes to whichever command you want.
That's a godsend, thanks!
Is is possible to use your rating script without the playback statistics component? It shows the rating but doesn't let me change it.
I keep the ratings in the file metadata and would like to edit them with your script.
Or instead make the panel able to display and edit the file ratings instead
Open up the editor dialog and replace
function on_mouse_lbtn_up(x, y) {
rating.lbtn_up(x, y);
}
with
function on_mouse_lbtn_up(x, y) {
if (rating.trace(x, y) && panel.metadb)
panel.metadb.UpdateFileInfoSimple("RATING", rating.hrating == rating.rating ? "" : rating.hrating);
}
I forgot you'll need to edit
js_marc2003\js\rating.js to stop the warning dialog popping up on each start. Just remove this from the end...
if (!utils.CheckComponent("foo_playcount", true))
window.SetTimeout(function () {
WshShell.popup("This script requires foo_playcount.", 0, panel.name, popup.stop);
}, 500);
Anyone here with Foobar2000 through Wine? JSPanel seems to crash is there any Windows dependent component required?
https://www.hydrogenaud.io/forums/index.php...st&p=876501 (https://www.hydrogenaud.io/forums/index.php?s=&showtopic=77883&view=findpost&p=876501)
thx marc, I have tried that, doesn't crash anymore, but common7.js is acting up lol
JScript Panel (Now Playing by marc2003): Microsoft JScript runtime error:
Automation server can't create object
File: Z:\home\zarkbit\.wine32\drive_c\Program Files\foobar2000\marc2003\common7.js
Line: 1426, Col: 2
<source text only available at compile time>
Checked line 1426, seems to be empty, or am I missing something?
There's also this, which affects most samples I'm using
JScript Panel (Playback Buttons by marc2003): Microsoft JScript runtime error:
Automation server can't create object
File: Z:\home\zarkbit\.wine32\drive_c\Program Files\foobar2000\js_marc2003\js\helpers.js
Line: 42, Col: 1
<source text only available at compile time>
Line 42: var vb = new ActiveXObject("ScriptControl");
Edit: ie8 32bit is acting up, trying to get ie8 32bit on 64bit OS.
Can the items in the red box (Properties - STYLE) shown in image be reverted to a single comma separated line? I disabled all autoplaylist functions since I have no need for them being created via Properties. Which I think is why they were changed to that. I'm not sure which JS script controls that behavior now. Guessing it is list.js, though.
@Zarkbit, I have no idea about the first one and you can comment the second one out. It was used for an input dialog but you can set variables by other means.
@MachineHead insert this in your editor window directly after
var list = new...list.add_meta = function (f) {
for (var i = 0; i < f.MetaCount; i++) {
this.add([f.MetaName(i).toUpperCase()]);
}
}
I've been looking at Br3tt's JS Smooth Browser. I'd like to force the script to load up ALL images into the cache when the panel starts (to avoid the 'loading' symbol and the wait for covers to display in Album mode). I've added a few debugs and noticed that the function 'image_cache' is no longer called once I've scrolled through all the albums (and no more loading symbols are shown. I don't fully understand all the code yet, but think it's because the resource has been loaded from the resource array into the cache. So I'm thinking this could be forced to occur up front. Any suggestions would be welcome. I dev in java/C++ for work, but haven't done much in JS so functions being called vs 'invoked' and some of the syntax throws me
http://i.imgur.com/u2f7Rr6.png (http://i.imgur.com/u2f7Rr6.png)
Does your list is ELP? Are you able to share the playlist‘s configuration?
I have a poor network speed, replied twice, can not find revoked, sorry!
@MachineHead insert this in your editor window directly after var list = new...
Thanks.
I was thinking maybe we could have a separate thread only for scripts
So we can share and find useful scripts 8)
And if you can somehow update the first post in case of a script update (I don't know whether it's possible)
Then we'll have one updated place for look for useful scripts :)
And these russian forums (http://foobar2000.ru) have some interesting scripts too
I was thinking maybe we could have a separate thread only for scripts
So we can share and find useful scripts 8)
And if you can somehow update the first post in case of a script update (I don't know whether it's possible)
Then we'll have one updated place for look for useful scripts :)
And these russian forums (http://foobar2000.ru) have some interesting scripts too
There is a good place for new/updated things, not only scripts though.
http://foobar2000.xrea.jp/
marc2003, just a few questions.
About last.fm user charts script, would've it be possible for script to display specific artist charts, like for instance, top songs from The Beatles, but using only songs that we have listened, from our library. Now top tracks and top albums of particular artist come from last.fm, and doesn't matter if we listened to them or not.
What I hope will be available in the future are last.fm-like charts' scripts but without last.fm. Using our tags from files (or customdb).
EDIT: Seems, these would be urls for data...
http://www.last.fm/user/*username*/library/music/*artist*/+tracks
http://www.last.fm/user/*username*/library/music/*artist*/+albums
So, with the lyrics3 panel no longer working I was wondering if it at all possible to have a script whipped up that could fetch lyrics? The ability to add our own sites for the query would be a nice option the extension was missing.
@OoNebsoO, use foo_facets with foo_playcount. Use a statistics column to reverse sort.
Is there a way to alter tag colors in properties.txt like this that doesn't involve editing the list.js color option? I dislike poking around in the scripts but in this case it was the only way I seem to be able to do it.
(http://i.imgur.com/AwtupI3.png)
inside on_paint before calling list.paint(gr)...
panel.colours.text = _.RGB(1, 2, 3);
panel.colours.highlight = _.RGB(4, 5, 6);
@OoNebsoO, use foo_facets with foo_playcount. Use a statistics column to reverse sort.
Thanks, marc2003. Though, shame facets do not work within Column UI.
I am fooling around a bit with autoplaylists + esplaylist (elp in future most likely). Used a bit graphical browser, but for some reason, that won't display all the results. Works well with the whole library, of course, Can't figure out a query for a particular artist that is selected, or is playing though. If that's possible anyway...
(http://i.imgur.com/FnlZ9TP.gif)
I am getting this error with one of your sample scripts:
JScript Panel (Album Art + Allmusic Review by marc2003): JavaScript runtime error:
Unable to get property 'getElementsByTagName' of undefined or null reference
File: C:\Users\xxx\AppData\Roaming\foobar2000\js_marc2003\js\text.js
Line: 316, Col: 8
<source text only available at compile time>
Is it happening with all artists/albums or just a specific one? If it's just one then let me know what it is and I'll take a look.
Is it happening with all artists/albums or just a specific one? If it's just one then let me know what it is and I'll take a look.
Well it's very rare and random it seems. I posted when it crashed during playing
Artist Name : Straylight Run
Track Title : Tool Sheds And Hot Tubs
Album Title : Straylight Run
Date : 2004
Genre : Alternative
but playing it a few more times just now didn't give any errors.
Also thanks a lot for your samples, I can't do anything in javascript so these are very helpful ;)
Well it worked first time for me. There's not a lot I can when I can't reproduce the problem but I guess I should handle errors more gracefully.
The script now displays a message in the Console when reading the server response fails. Just save this inside js_marc2003\js
https://raw.githubusercontent.com/19379/js-marc2003/master/js/text.js
So, with the lyrics3 panel no longer working I was wondering if it at all possible to have a script whipped up that could fetch lyrics? The ability to add our own sites for the query would be a nice option the extension was missing.
you may mean this: (http://snag.gy/5BPIr.jpg)
but......... could read Chinese? or ESLyric would be a good choice.
marc2003, could Autoplaylists use only the currently playing playlist, and not the whole library? Or think that query could be made that uses currently playing (or selected artist) automatically? Something like %artist% (is playing/is selected) SORT DESCENDING BY %title%?
Thanks.
Using a custom source for autoplaylists would require component changes way beyond my extremely limited capabilities.
You can run a query against an existing playlist and send the results to a new (standard) playlist. This method doesn't support SORT BY but you can use regular title formatting to sort instead.
Using a custom source for autoplaylists would require component changes way beyond my extremely limited capabilities.
Dread to think how limited some of ours' capabilites are then. ;)
Thank you. Found also one older thread (https://hydrogenaud.io/index.php/topic,99876.0.html) where you again helped a member who had quite similar questions like I had.
So, with the lyrics3 panel no longer working I was wondering if it at all possible to have a script whipped up that could fetch lyrics? The ability to add our own sites for the query would be a nice option the extension was missing.
you may mean this: (http://snag.gy/5BPIr.jpg)
but......... could read Chinese? or ESLyric would be a good choice.
Thank you but I did not have any luck with this
I hope this is the best place to ask this...
THe "now playing (basic)" Script... is it possible to change the location where the images are downloaded to? When selecting to download the images from last.fm it saves to the user configuration folder.. can I for example change this to my album artist folder? (drive\album artist\artowrk\?) This is something I already use for one source for my images.. ($replace(%path%,$directory(%path%)\%filename_ext%,)extrathumbs\*)
So, with the lyrics3 panel no longer working I was wondering if it at all possible to have a script whipped up that could fetch lyrics? The ability to add our own sites for the query would be a nice option the extension was missing.
you may mean this: (http://snag.gy/5BPIr.jpg)
but......... could read Chinese? or ESLyric would be a good choice.
Thank you but I did not have any luck with this
Once @dreamawake made an English version of ESLyric and shared it with her configuration "Foobox" on deviantart, but got "SHIT" feedback... maybe that is why @ttsping(aka oyeah) has no motion to compile an english version.
I hope this is the best place to ask this...
THe "now playing (basic)" Script... is it possible to change the location where the images are downloaded to? When selecting to download the images from last.fm it saves to the user configuration folder.. can I for example change this to my album artist folder? (drive\album artist\artowrk\?) This is something I already use for one source for my images.. ($replace(%path%,$directory(%path%)\%filename_ext%,)extrathumbs\*)
Theoretically possible but tricky to explain so I'm just going to say no. :))
Theoretically possible but tricky to explain so I'm just going to say no. :))
Thank you. That's all I needed. Being new to foobar my head is spinning a little and wanted to make sure I wasn't overlooking anything.
Last.fm updated their website today and it broke image downloading in my thumbs/now playing (simple) scripts. This fixes it...
https://raw.githubusercontent.com/19379/js-marc2003/master/js/thumbs.js
Just save it inside js_marc2003\js.
Getting API error after I enter my last.fm password into last.fm sync sample panel, do I have to manually enter it into one of the .js files?
I want to add a few extra buttons to marc2003's sample "track info + seekbar + buttons", where do I find the functions syntax I need?
For example stop after queue/current.
docs\interfaces.txt contains most of what you need. You can get/set the state of stop after current with fb.StopAfterCurrent. You can also detect when the state changes using the on_playlist_stop_after_current_changed callback. See callbacks.txt
Assuming stop after queue is provided by some third party component, all you can do is trigger the menu command using fb.RunMainMenuCommand. You cannot query its state.
docs\interfaces.txt contains most of what you need.
I opened interfaces.txt in Notepad and quickly found that was a mistake. So I opened it in the JScript Panel editor, which obviously should have been my first choice. Can you recommend a text editor that works the same way?
docs\interfaces.txt contains most of what you need. You can get/set the state of stop after current with fb.StopAfterCurrent. You can also detect when the state changes using the on_playlist_stop_after_current_changed callback. See callbacks.txt
Assuming stop after queue is provided by some third party component, all you can do is trigger the menu command using fb.RunMainMenuCommand. You cannot query its state.
Thank you.
All samples I find for playback order button work fine in wsh panel but in js panel they give error -
JavaScript runtime error:
Overflow
File: <main>
Line: 132, Col: 2
<source text only available at compile time>
line is k.CheckMenuRadioItem(1, 7, fb.PlayBackOrder
+ 1);
removing +1/-1 stops crashing but then the menu doesn't actually do anything. Is there a way to make it JS panel friendly?
Use plman.PlaybackOrder
It is documented in the changelog...
https://github.com/19379/foo-jscript-panel/blob/master/CHANGELOG.md#v100-compared-to-wsh-panel-mod-156
Perfect, thanks again.
Last.fm updated their website today and it broke image downloading in my thumbs/now playing (simple) scripts. This fixes it...
https://raw.githubusercontent.com/19379/js-marc2003/master/js/thumbs.js
Just save it inside js_marc2003\js.
Thank you.
Each folder is now duplicates example:
Medeski, Martin & Wood 100596f6218c45c69164896428acb00a.jpg
Medeski, Martin & Wood_100596f6218c45c69164896428acb00a.jpg.jpg
This can be fixed?
Thanks for spotting that. The updated file can be downloaded using the same link:
https://raw.githubusercontent.com/19379/js-marc2003/master/js/thumbs.js
I'm having a problem with the on_mouse_wheel callback. (jscript panel & wsh panel)
Any help is appreciated.
Using an external mouse with my laptop , scrolling is possible and the callback returns step of 1 or -1 .
Using the touchpad though , with Asus Smart Gesture drivers , two-finger scrolling returns multiple steps of 0 and scrolling does not work right.
Is it a crappy driver issue , or an issue with the callback ?
Native playlists views , scollbars and volume are working fine with the two-finger scroll.
function on_mouse_wheel(a, b, c) {
fb.trace("a: " + a);
fb.trace("b: " + b);
fb.trace("c: " + c);
}
Can you report the value of
b when you scroll up/down with your trackpad.
Down
b: -80
b: -82
b: -82
b: -46
b: -46
b: -46
b: -46
b: -46
b: -46
b: -46
b: -46
b: -46
b: -46
b: -46
b: -45
b: -45
b: -45
b: -45
b: -45
b: -45
b: -45
b: -44
b: -44
b: -44
b: -44
b: -44
b: -43
b: -43
b: -43
b: -43
b: -42
b: -42
b: -42
b: -42
b: -41
b: -41
b: -41
b: -40
b: -40
b: -40
b: -39
b: -39
b: -38
b: -38
b: -38
b: -37
b: -37
b: -36
b: -36
b: -35
b: -35
b: -35
b: -34
b: -34
b: -33
b: -33
b: -32
b: -31
b: -31
b: -30
b: -30
b: -29
b: -29
b: -28
b: -27
b: -27
b: -26
b: -26
b: -25
b: -24
b: -24
b: -23
b: -22
b: -22
b: -21
b: -20
b: -19
b: -19
b: -18
b: -17
b: -16
b: -16
b: -15
b: -14
b: -13
b: -13
b: -12
b: -11
b: -10
b: -9
b: -8
b: -7
b: -7
b: -6
b: -5
b: -4
b: -3
b: -2
b: -1
Up
b: 112
b: 112
b: 40
b: 64
b: 64
b: 64
b: 64
b: 64
b: 64
b: 64
b: 64
b: 64
b: 64
b: 64
b: 63
b: 63
b: 63
b: 63
b: 63
b: 63
b: 63
b: 62
b: 62
b: 62
b: 62
b: 62
b: 61
b: 61
b: 61
b: 61
b: 60
b: 60
b: 60
b: 60
b: 59
b: 59
b: 59
b: 58
b: 58
b: 58
b: 57
b: 57
b: 56
b: 56
b: 56
b: 55
b: 55
b: 54
b: 54
b: 53
b: 53
b: 52
b: 52
b: 52
b: 51
b: 50
b: 50
b: 49
b: 49
b: 48
b: 48
b: 47
b: 47
b: 46
b: 45
b: 45
b: 44
b: 44
b: 43
b: 42
b: 42
b: 41
b: 40
b: 40
b: 39
b: 38
b: 37
b: 37
b: 36
b: 35
b: 34
b: 34
b: 33
b: 32
b: 31
b: 30
b: 30
b: 29
b: 28
b: 27
b: 26
b: 25
b: 24
b: 24
b: 23
b: 22
b: 21
b: 20
b: 19
b: 18
b: 17
b: 16
b: 15
b: 14
b: 13
b: 12
b: 11
b: 10
b: 9
b: 8
b: 7
b: 6
b: 5
b: 4
b: 2
b: 1
b: 2
b: 2
b: 2
b: 2
b: 2
b: 2
b: 2
b: 2
b: 2
b: 2
b: 2
b: 2
b: 2
b: 2
b: 2
a = 0
c = 120
Can you try this updated component. It's just the dll but I'm sure you know where to put it.
edit: temporary link removed. I'll publish a proper update later.
Thanks for your help marc2003.
The updated component resolved the problem and works fine. :)
@marc2003 How can I change the Volume sample script so that it works vertically instead of horizontally?
Inside your panel, replace the
on_paint function with this:
function on_paint(gr) {
gr.FillSolidRect(volume.x, volume.y, volume.w, volume.h, volume.c1);
gr.FillSolidRect(volume.x, volume.y + volume.h - volume.pos(), volume.w, volume.pos(), volume.c2);
}
Then open
js_marc2003\js\volume.js and replace the
this.move function with this:
this.move = function (x, y) {
this.mx = x;
this.my = y;
if (this.trace(x, y)) {
y -= this.y;
var pos = y < 0 ? 1 : y > this.h ? 0 : 1 - (y / this.h);
this.drag_vol = 50 * Math.log(0.99 * pos + 0.01) / Math.LN10;
_.tt(this.drag_vol.toFixed(2) + " dB");
if (this.drag)
fb.Volume = this.drag_vol;
this.hover = true;
return true;
} else {
if (this.hover)
_.tt("");
this.hover = false;
this.drag = false;
return false;
}
}
and replace the
this.pos function with this:
this.pos = function () {
return _.ceil(this.h * (Math.pow(10, fb.Volume / 50) - 0.01) / 0.99);
}
Make sure reload the panel after editing the .js file.
@marc2003 I now have a vertical volume bar. Thank you!
marc2003, any way for different Autoplaylist panels to keep their own queries? As it is now, one will 'pick off' queries from another, and you'll end up with two panels with same queries on both.
Thanks for spotting that. The updated file can be downloaded using the same link:
https://raw.githubusercontent.com/19379/js-marc2003/master/js/thumbs.js
Hello !
Help please with thumbs. Is it possible to change the aspect of double-clicking on the screen?
I tried through window.SetProperty ( "2K3.THUMBS.ASPECT", 0);
window.SetProperty ( "2K3.THUMBS.ASPECT", 1);
window.SetProperty ( "2K3.THUMBS.ASPECT", 2);
window.SetProperty ( "2K3.THUMBS.ASPECT", 3);
but window.Repaint (); does not work here.
After window.Reload (); do not load next images from the Internet
How to refresh the screen? Thank you!
OoNebsoO, autoplaylists is meant to be single instance only. However, you could try hacking it like this
var list = new _.list("autoplaylists", 10, 24, 0, 0); //original line - do not touch
list.filename = folders.settings + "autoplaylists2.json"; //only add this/modify filename in extra panels. autoplaylists.json is the original filename so don't use that
list.update();
seriousstas,
thumbs.aspect++;
if (thumbs.aspect > 3)
thumbs.aspect = 0;
window.SetProperty("2K3.THUMBS.ASPECT", thumbs.aspect);
window.Repaint();
seriousstas,
thumbs.aspect++;
Thnx !
Much appreciated, yet again, marc. :)
Yet one question :):
Delete function for a single file:
this.delete_image = function () {
_.recycleFile (this.files [this.images]);
this.update (); }
How do delete all the files in the current folder?
this.delete_image = function () {
_.map(this.files, _.recycleFile);
this.update();
}
Seems like if a character tabulation (U+0009) is present in a tag and a script tries to access it the result is a crash.
https://en.wikipedia.org/wiki/Whitespace_character
(http://i.imgur.com/M6PNFAM.png)
Don't expect to have any in my tags, just thought I'd mention it anyway.
There is no problem accessing/displaying tags with these characters in. The error is caused by the script trying to create a new folder based on the tag value. I'll look at handling this better.
This is now fixed. Save this inside js_marc2003\js
https://raw.githubusercontent.com/19379/js-marc2003/master/js/helpers.js
The full zip has also been updated here...
https://github.com/19379/js-marc2003/releases
Thank you for your work marc!
marc, in your sample track info + seekbar + buttons is it possible to have a notch/mark on the seekbar at a certain percent? Any directions if you don't mind?
(http://i.imgur.com/e5GTSG7.jpg)
Look inside the
on_paint function for
if (fb.PlaybackLength > 0) and replace that section with this...
if (fb.PlaybackLength > 0) {
var pos = seekbar.pos();
gr.FillSolidRect(seekbar.x, seekbar.y + 7, pos, 6, colours.seekbar_progress);
gr.FillSolidRect(seekbar.x + _.round(seekbar.w * 0.2) + 13, seekbar.y + 7, 3, 6, colours.seekbar_knob); //20%
gr.FillSolidRect(seekbar.x + _.round(seekbar.w * 0.8) + 13, seekbar.y + 7, 3, 6, colours.seekbar_knob); //80%
gr.FillRoundRect(seekbar.x + pos, seekbar.y + 2, 16, 16, 8, 8, colours.seekbar_progress);
gr.FillRoundRect(seekbar.x + pos + 3, seekbar.y + 5, 10, 10, 5, 5, colours.seekbar_knob);
gr.GdiDrawText(_.tfe("%playback_time% "), panel.fonts.normal, colours.time, seekbar.x - 60, 0, 60, panel.h, RIGHT);
gr.GdiDrawText(_.tfe(" %length%"), panel.fonts.normal, colours.time, seekbar.x + seekbar.w + 16, 0, 60, panel.h, LEFT);
}
edit: top tip for anyone use imgur. Edit the url so it's https rather than http. That way, we get full size images like this...
(https://i.imgur.com/M6PNFAM.png)
(https://i.imgur.com/e5GTSG7.jpg)
Thank you so much :)
this.delete_image = function
THANX Again ! :)
I'm working on modifying the "track info + seekbar + buttons" sample script. I've noticed that cover art images are cropped by JScript Panel whereas foobar's Album Art Viewer renders them correctly.
In the attachment, the panel is sized to 400 px tall to result in a 400 x 400 image, which mimics the Art Viewer. This cover art is enlarged from 310 x 310, but the problem exists regardless of the size of the source image or the panel size.
This is the line that displays the image, compared to the original. The only modification is to place it at the right side of the panel as opposed to the left side.
img && _.drawImage(gr, img, 0, 0, panel.h, panel.h, image.centre); //original
img && _.drawImage(gr, img, panel.w - panel.h + 1, 0, panel.h, panel.h, image.centre);
Can this be fixed?
To get the image untouched, simply omit the last argument like this...
img && _.drawImage(gr, img, panel.w - panel.h + 1, 0, panel.h, panel.h);
Problem solved! Thank you.
Now I'm curious: is "image.centre" broken? If not, what would it be used for, given that behavior?
It's by design and was asked for as a feature request by someone else. It trims 5px off each edge of the original image before resizing it. This helps when you have less than perfect images. I may have done it for my thumbs script originally but it shares the same drawImage function with the artreader. I think you're the first person to notice it- or at least tell me about it.
Having the option to draw images untouched by omitting that last argument is also by design because it absolutely matters when making buttons where you could be using images as small as 16px to begin with.
It's by design and was asked for as a feature request by someone else. [-snip-]
Excellent explanation, thank you.
Another question, then: Is "image.center" the only possible argument, or are there others?
image.crop
image.crop_top
image.stretch
image.centre
Just load my artreader script and use the right click options to see each one in action.
(https://i.imgur.com/yXoLbCa.png)
It really helps if you make the panel an extreme rectangle rather than a square to see what it does.
Just load my artreader script and use the right click options to see each one in action.
Ah, I haven't looked at that script yet. (I should probably look at
all of them.) The menu image you posted is a good explanation.
Thanks!
While still working on modifying the "track info + seekbar + buttons" sample script, I moved the seekbar around a bit. I had trouble moving the %playback_time% and %length% text to follow it, as the text kept appearing above where I expected.
The panel height is currently 228 pixels. The var seekbar.y is (panel.h - 20) / 2, which is 104, and the seekbar is about where I expect it to be. So I figured I needed 104 or thereabouts for the gr.GdiDrawText 'h' value, but that doesn't work. I did some testing and came up with this...
//Test
// syntax: gr.GdiDrawText(str, IGdiFont, color, x, y, w, h, [format]);
gr.GdiDrawText("50h", _.gdiFont("Segoe UI", 12, 0), _.RGB(255, 255, 0), seekbar.x + seekbar.w + 60, 0, 40, 50, RIGHT);
gr.GdiDrawText("150h", _.gdiFont("Segoe UI", 12, 0), _.RGB(255, 255, 0), seekbar.x + seekbar.w + 60, 0, 40, 150, RIGHT);
gr.GdiDrawText("228h", _.gdiFont("Segoe UI", 12, 0), _.RGB(255, 255, 0), seekbar.x + seekbar.w + 60, 0, 40, 228, RIGHT);
gr.GdiDrawText("456h", _.gdiFont("Segoe UI", 12, 0), _.RGB(255, 255, 0), seekbar.x + seekbar.w + 60, 0, 40, 456, RIGHT);
gr.GdiDrawText("panel.h = " + panel.h, _.gdiFont("Segoe UI", 12, 0), _.RGB(255, 255, 255), 10, panel.h - 70, 900, 24, LEFT);
...which produces the result shown below. I see now that the value of 'h' needs to be double the pixel distance the text is to be moved below 'y' (which is zero in this case). Not what I expected, but at least it's not hard to remember.
Why does gr.GdiDrawText work this way?
The RIGHT variable is actually a combination of flags (see helpers.js) and one of them is to vertically centre the text. If you draw rectangles using the same co-ordinates as your text, you'll see a result like this.
(https://i.imgur.com/l2VX8MH.png)
This is working exactly as expected and I'm not really sure what your problem is???
Also, never use gdiFont inside on_paint like that. Just create a variable outside the function and re-use it
var font = _.gdiFont("Segoe UI", 12);
function on_paint(gr) {
gr.GdiDrawText("50h", font, _.RGB(255, 255, 0), 10, 10, 40, 50, RIGHT);
}
edited: because I don't really understand what you're asking.
It is working exactly as expected and your problem is how you've decided to increment the height of the rectangles rather than using a fixed height and adjusting the y position.
Also, never use gdiFont inside on_paint like that. Just create a variable outside the function and re-use it
var font = _.gdiFont("Segoe UI", 12);
function on_paint(gr) {
gr.GdiDrawText("50h", font, _.RGB(255, 255, 0), 10, 10, 40, 50, RIGHT);
}
So I'm basically making a box and putting text in it; okay, that makes sense now. Part of my confusion is that the original script left y at zero (to my befuddlement) and changed h (ditto), and I followed suit. I find it obvious now that it was done that way to allow the text to stay in the middle of the panel with the seekbar when the panel height changes. My panel will fit into a specific area, so I'm hard-coding the positioning.
The original script also uses panel.fonts and at the time I couldn't find where that was to make changes (panel.js, I now presume), so I went with what I knew would work. I'll definitely create variables for fonts and colors and such from here on out.
Thank you for the information. It is very much appreciated.
Hey guys :). I'd like to start work at a script for the JS Panel in Foobar. Where can I find some tutorials regarding the API of JSPanel? I already found this:
https://github.com/19379/foo-jscript-panel/wiki/Editor-Properties
And of course I can look at some source code from the existing scripts.
But is there any tutorial anywhere which covers some of the basics of setting up an UI and calling Foobar API?
I'm talking about stuff like this: fb.CreateContextMenuManager();
I'd like to see all the methods that the fb object has, along with signatures (arguments required, returned types).
Unfortunately, there aren't any tutorials as such. The main file you want to look at is the component folder>docs>Interfaces.txt
Most methods have a single line example but more complex ones like fb.CreateContextMenuManager will point you toward some scripts contained within the samples folder.
https://github.com/19379/foo-jscript-panel/blob/master/foobar2000/foo_jscript_panel/docs/Interfaces.txt#L87L102
kinda enjoyed the more plain look on the other wsh playlist
By the way do any of you know how to remove the track # for this playlist? I remember I did it on the other one with whs mod
If anyone uses my JSplaylist-mod, it has been updated so the minutes/seconds display text in the group header is replaced with just numbers.
https://github.com/19379/jsplaylist-mod
Hey marc :). Apparently you blocked PMs so...
I really like what you've done with the JS Panel and WSH Panel. You've helped / are helping a lot of people build components. I'd like to donate to you, as a sign of appreciation for your contributions.
I'm trying to run the "quicksearch for same" command on every new track and I guess jscript is the only way. Is there a script I can look at to understand how to do this? I mean a script that does something simple when a new track starts.
@Axonn, just sling a few pennies towards a charity of your choice.
@davideleo, you can do something like...
function on_playback_new_track() {
fb.RunContextCommand("path/to/command");
}
IIRC, you use columns UI so you can hide this panel.
@davideleo, you can do something like...
function on_playback_new_track() {
fb.RunContextCommand("path/to/command");
}
IIRC, you use columns UI so you can hide this panel.
Wow! That worked, thanks a lot!! :D
Now I'd like to make it a little bit more complicated: the quick search command should be different according to which panel is visible. I'm already using a PSS global variable which is called "quicksearch" and is set to the proper parameter (genre, artist or album) when I click on the panel switch.
I guess I have to declare a jscript variable and write something like:
var quicksearch = "the PSS global variable value";
var command = "Quicksearch for same/" + quicksearch;
function on_playback_new_track() {
fb.RunContextCommand(command);
}
Besides the syntax of what I wrote above, which is likely faulty here and there, can I recall PSS global variable values in the jscript panel?
Besides the syntax of what I wrote above, which is likely faulty here and there, can I recall PSS global variable values in the jscript panel?
I tried this:
var quicksearch = fb.TitleFormat("%quicksearch%");
var command = "Quicksearch for same/" + quicksearch;
function on_playback_new_track() {
fb.RunContextCommand(command);
}
I don't know if it makes sense, but it doesn't work.
can I recall PSS global variable values in the jscript panel?
Short answer: no
Longer answer: with lots of script hacking it may me possible. Basically you'd use $movepanel in PSS to resize the Jscript Panel based on the value of your global variable. JScript Panel can then detect its own height/width and adjust the command accordingly. I don't really have the time or inclination to spell it all out though.
BTW, fb.TitleFormat is used for reading tags from files and you need to use it in conjunction with Eval or EvalWithMetadb
Bit of a schoolboy error but I just realised my track info + seekbar + buttons didn't update the artist/title if tags were edited during playback, This has now been fixed.
https://github.com/19379/js-marc2003/releases
can I recall PSS global variable values in the jscript panel?
Short answer: no
Longer answer: with lots of script hacking it may me possible. Basically you'd use $movepanel in PSS to resize the Jscript Panel based on the value of your global variable. JScript Panel can then detect its own height/width and adjust the command accordingly. I don't really have the time or inclination to spell it all out though.
I actually found out all I need to do is put a jscript panel as a child in each of the PSS panels, with a different quicksearch command for each of them. You really made my day! Now my set up is almost perfect, thanks again.
You do realise all code in each panel will be executed at once? This is going to trigger your quicksearch command 3 times if the previous post about genre, artist and album was correct. If that was your intention, you can do it from a single panel/function.
You do realise all code in each panel will be executed at once? [...] If that was your intention, you can do it from a single panel/function.
I just did and nope, that was not my intention.
Longer answer: with lots of script hacking it may me possible. Basically you'd use $movepanel in PSS to resize the Jscript Panel based on the value of your global variable. JScript Panel can then detect its own height/width and adjust the command accordingly. I don't really have the time or inclination to spell it all out though.
Let me see if I got this right: you mean I could write a conditional statement in the jscript panel which outputs a different quicksearch command according to the size of the panel?
You can use window.Width and window.Height.
if (window.Height == 1)
or
switch (window.Height) {
case 1:
//do something
break;
case 2:
//do something else
break;
}
I managed! :)) Excellent! Thanks a lot marc!
@marc2003 When creating a volume object ...
var volume = new _.volume(0, 0, 0, 0);
... do the arguments take only numbers, i.e., are variables not allowed?
Of course you can use variables - so long as they are numbers.
var a = 200; //right
var b = "boo"; //wrong
var c = false; //wrong
Just remember that x,y,w,h set there can only be fixed values. If you need position/size relative to the overall panel size then you update in the
on_size callback like my sample already does.
function on_size() {
volume.w = window.Width;
volume.h = window.Height;
}
If you want it to float in the bottom right of the panel, you can do something like this...
function on_size() {
volume.x = window.Width - 200;
volume.y = window.Height - 20;
volume.w = 195;
volume.h = 15;
}
That makes sense, but why shouldn't this work...
var vx = (panel.w - panel.h) - 27;
var volume = new _.volume(vx, 70, 10, 110);
//vx result is 27 but should be 759
...while this does?
var vx = 759;
var volume = new _.volume(vx, 70, 10, 110);
I'm missing something.
panel.w and panel.h
There is no panel object in the volume/seekbar scripts. You really must have been sleeping!
But there is in 'track info + seekbar + buttons', which is the basis of this project. And this works:
function on_size() {
panel.size();
seekbar.x = 100;
seekbar.w = panel.w - panel.h - 300;
seekbar.y = (panel.h - 20) / 2;
volume.x = panel.w - panel.h - 27; //no problem
buttons.update();
}
I edited my last reply; you may need to re-read it. Oh, and the result for vx is -27, not 27. Has
on_size not run yet?
Docs\Notes & Hints...
https://github.com/19379/foo-jscript-panel/blob/master/foobar2000/foo_jscript_panel/docs/Notes%20%26%20Hints.txt#L10L11
I read that a while ago; I should probably review it every so often. Like daily. :-[
Thanks!
I'm trying your samples scripts and I have a little question.
The Allmusic review looks for the album review: can I change it to look for the title review?
And also for the Allmusic categories for the title?
Thanks.
I had a quick look at the underlying html of the song search results and it's quite different to the album results so it would require a good bit of work to get it done. I might have a look when I have more time.
Using the
const statement results in an error:
JavaScript compilation error:
Syntax error
File: <main>
Line: 66, Col: 1
const ppd = "■";
The
const keyword highlights in blue in the editor as expected. Using ASCII characters or numbers as opposed to the char shown produces the same result.
I understand the
const statement is a relatively new addition to JavaScript. Is it not supported by the version used for JScript Panel?
It probably uses Windows Scripting Host, which probably won't be updated for ES2015, which is required for the const keyword.
So, expect whatever level of JavaScript capability that will work with the version of Internet Explorer or cscript/wscript on your machine.
We're basically stuck with windows script host which is IE8 levels of Javascript support.
However, you can use libraries like lodash or underscore which provides all sorts of neat ES5 features like filter, map, bind, foreach etc. I already bundle lodash with my sample scripts and full docs for it can be found here...
https://github.com/lodash/lodash/blob/3.10.1/doc/README.md
Because it's included by your script I'm using as a base, I looked at lodash.js in Notepad++ () and found it rather dense, to say the least. I didn't think to search for it online, although that results in information overload. So many thanks for the link; it's exactly what I needed.
I see from a Microsoft support page that their browsers (including Edge) support const. Too bad they haven't extended that to WSH. Being a long-time user of VBA (and thus const), I'm kind of peeved about that.
Microsofts JavaScript engine Chakra has its own set of APIs which are incompatible with WSH. There are good reasons for that. With the COM based API of WSH some modern JavaScript features are hard* or impossible to implement or just plain slow**. With the new engine you gain a lot at the cost of settling for a single language.
You can embed the new engine in your own applications (see JavaScript Runtime Hosting (https://msdn.microsoft.com/en-us/library/dn249673(v=vs.94).aspx), JSRT). However this is not an option for foo_jscript_panel. The differences between JSRT and WSH are just too big, regarding both the APIs for embedding and the APIs available to scripts.
*: Try to store a function of the standard JS objects in a variable, e.g. Math.sin. Now do the same for a function implement by this component. It would be a hell of a lot of work to make this possible. With JSRT it is trivial.
**: An array in a WSH script is really a dictionary where the keys are the lexical representations of the indices. This means anArray[myIndex] is really the same as anArray[myIndex.toString()].
Well, I'll just have to take what I'm given and like it then! Fortunately, I do, even without const. Thanks for the explanation.
As to arrays, are they so slow that they should be avoided in JScript Panel scripts?
I looked at lodash.js in Notepad++ () and found it rather dense,
You missed a key part of the filename. It is
lodash.min.js which indicates it has been minified (https://en.wikipedia.org/wiki/Minification_%28programming%29)!
I should add that you should only refer to the document I linked to. Do not look at the current lodash website/docs as WSH is no longer supported and there have been significant changes to their API which don't apply to the version we're using.
As for arrays, I use them extensively when using web services or scraping websites. No one has complained about the milliseconds it takes to parse being too slow.
Yes, you got me--I missed the .min. But now I know what that signifies, so I've proven I can learn from my mistakes. And I won't make the mistake of deviating from the linked doc because I'd just confuse myself all the more. Thanks again.
I'm trying to switch to this from Biography View plugin, someone can point me out to a script similar to Thumbs but for automatically download ALBUM art from last.fm?
I'm not aware of any. I've never bothered myself because the quality is pretty bad. Although the same can be said of some artist images, there is some decent stuff to be found.
IIRC, the image functionality of that other component still works so there's no reason not to continue using it.
I use it primarily as a source for internal Album Art Viewer. So quality is not really bother me, just too lazy to search.
It downloads now only one picture 300x300, but i need biography and other stuff. Don't see the point to use 2 plugins with same functionality. I waited half year for update or something, time to move on i guess.
I'll take a look at the last.fm website later and see if it's an easy fix. If it's just a few lines of code, I can post an update.
As to arrays, are they so slow that they should be avoided in JScript Panel scripts?
No, as marc2003 said you should be fine. This is just one factor which makes WSH slower than a modern JavaScript engine. You probably should not try to use asm.js code in scripts though.
You probably should not try to use asm.js code in scripts though.
That shouldn't be a problem. I'm still basically a JavaScript noob, and I had to go look up what asm.js is.
I'll take a look at the last.fm website later and see if it's an easy fix. If it's just a few lines of code, I can post an update.
It'd be really great if you could get that going marc2003. I finally got around to putting together a build based on br3tt's old Kameleon using his new jscript smooth playlist panels and a number of yours including the last.fm bio script. It'd be really nice to have it auto-download album art. I'll get back here to post a few questions in a new thread.
No album art yet but I have posted some other updates.
Thumbs: Download limits have been increased and the default has been reset to 10. Also, automatic downloads are now an option but turned off by default. Simply use the right click menu to enable.
Automatic downloads only trigger when the following conditions are true:
- a new track begins and the artist is different from the previous track
- there are no existing images. Use the Download now option if you want to check for more.
- the last automatic check was more than an hour ago. Timestamps are maintained by the script to prevent unnecessary requests if there were no images found previously.
Musicbrainz: Now attempts to retry up to 5 times on failure.
https://github.com/19379/js-marc2003/releases
Also, I just want to make one thing very clear.... there is no support if automatic downloads don't work for you. Simply use another script/software/fix it yourself/whatever. ;D
It should work with dynamic stream changes but I haven't tested that. It would be good to get some confirmation on that.
Thumbs.txt in v3.0 is identical to thumbs.txt in v2.7?? ???
Correct. All the changes are to files inside the
js_marc2003\js folder.
edit: I just realised my wiki page was poorly worded so I've updated it.
Unlike previous versions, updates must be downloaded manually. Just extract the whole zip contents in to your existing js_marc2003 folder and overwrite the old files when prompted. On the rare occasion a script inside a panel needs updating, it will be mentioned on the releases page.
https://github.com/19379/js-marc2003/wiki/Updates-&-Support
You should be able to tell from the new right click menu options:
(https://i.imgur.com/gUIrFNh.png)
I'll take a look at the last.fm website later and see if it's an easy fix. If it's just a few lines of code, I can post an update.
I noticed, that your thumbs script keep rotating images, insted it stops and start again when download is finished..
If you need, here is fix for that(you can figure it out):
//Download Image
function download()
{
try {
if (lfm_folder=="<default>") {folder = fbfolder + "\\" + p.clean_filename(p.artist) + "\\";}
if (lfm_folder=="") {folder = fbfolder + "\\" + p.clean_filename(p.artist) + "\\";}
if (lfm_folder.indexOf(":\\") > 0) {folder = lfm_folder + "\\" + p.clean_filename(p.artist) + "\\";}
}catch (err) {{fb.trace("Biography Photos: " + "TypeError: 'folder path' undefined");} var folder;}
if (!p.fso.FolderExists(folder)) return;
{
if (p.artist == "" || p.artist == "?") return;
this.xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
this.xmlhttp.open("GET", "http://www.last.fm/music/" + encodeURIComponent(p.artist) + "/+images", true);
this.xmlhttp.send();
this.xmlhttp.onreadystatechange = function() {
if (this.xmlhttp.readyState == 4) {
if (this.xmlhttp.status == 200) {
var text = this.xmlhttp.responsetext;
try {
if (!im.doc) im.doc = new ActiveXObject("htmlfile");
im.doc.open();
var div = im.doc.createElement("div");
div.innerHTML = text;
var data = div.getElementsByTagName("img");
var urls = [];
for (i = 1; i < data.length; i++) {
if (data[i].src.indexOf("http://img2-ak.lst.fm/i/u/avatar170s/") == 0) urls.push(data[i].src.replace("avatar170s", size == "low" ? "300x300" : size == "medium" ? "500x500" : size == "high" ? "_" : "_"));
}
for (i = 0; i < Math.min(urls.length, im.limit, 50); i++) {
p.WshShell.Run("cscript //nologo \"" + p.script_path + "bio_photos.vbs\" \"" + urls[i] + "\" \"" + [folder + p.clean_filename(p.artist) + "_" + i] + urls[i].substring(urls[i].lastIndexOf("/")+1000) + ".jpg" + "\"",0,false);
}
//Update Images--------------------------------------------
var cicleTimerStarted2 = false;
var cicleTimer2 = null;
//Start Timer 2 (Func)
(function startTimer2(){
if(!cicleTimerStarted2){
cicleTimer2 = window.SetInterval(function() {on_timer();}, "500");
cicleTimerStarted2 = true;
}})();
//Stop Timer 2 (Func)
function stopTimer2(){
if(!cicleTimerStarted2) return;
window.ClearInterval(cicleTimer2);
cicleTimer2 = undefined;
cicleTimerStarted2 = false;
}
//Definitions
var pos = 0;
if(urls.length<im.limit) {var num = urls.length;}
else
if(urls.length>im.limit) {var num = im.limit;}
//*On Timer*
function on_timer(id) {
if(cicleTimer2 && id == cicleTimer2.ID){
//Check Files on Timer
var list = utils.Glob(folder + "\\*.jpg").toArray();
var a = [];
//fb.trace("files: " + list);
for (i = 0; i < list.length; i++) {
if (list[i]) a.push(list[i]);
}
//Length
l = list.length;
//Update On First Down.(Keep Position)
if(im.images.length==0 && l>0) {
im.update();
pos = list.toString();
if(pos.indexOf("_0")>0) {pos=0;}
else
if(pos.indexOf("_1")>0) {pos=1;}
else
if(pos.indexOf("_2")>0) {pos=2;}
else
if(pos.indexOf("_3")>0) {pos=3;}
else
if(pos.indexOf("_4")>0) {pos=4;}
else
if(pos.indexOf("_5")>0) {pos=5;}
}
//Stop Main Timer
stopTimer();
//Wait Untill All Images Are Down.
if(l<num) {return true;}
//Update All Images
im.update();
window.NotifyOthers("images", "update");
//Keep Image Position
im.index=pos;
//Stop Timer 2
stopTimer2();
//Start Main Timer
startTimer();
return false;
}}
//End Of Update--------------------------------------------
im.doc.close();
} catch (err) {im.doc.close();}
} else {
p.console("HTTP error: " + this.xmlhttp.status);
}}}}}
(https://i.imgur.com/43HrVqh.jpg)
Correct. All the changes are to files inside the js_marc2003\js folder.
Very, very nice marc2003.
I have four playlists which among them should contain every track in my library. To make sure of that, I post the number of tracks in each playlist along with their total and compare the total to the number of tracks in the Album List. I had been getting the latter figure by opening Properties on the
All Music entry at the top of the list and reading the number of items listed in the title bar, but thought there must be a way to let my script retrieve it. This is what I came up with...
LibraryTotalTracks = fb.GetLibraryItems().count;
..but in testing, I've determined that
fb.GetLibraryItems() gets handles for the tracks in the playlists rather than the Album List as I had led myself to believe. (I thought Library != Playlists. Oops!)
Is there a method to get the Album List number of tracks? Or do I need to revert to stare-and-compare?
..but in testing, I've determined that fb.GetLibraryItems() gets handles for the tracks in the playlists rather than the Album List as I had led myself to believe. (I thought Library != Playlists. Oops!)
I suggest you go away and test again. For you to think fb.GetLibraryItems has anything to do with playlist contents is quite insulting.
Remember that you need to use the
on_library_items_added and
on_library_items_removed callbacks if you want to track changes while foobar is running.
I suggest you go away and test again. For you to think fb.GetLibraryItems has anything to do with playlist contents is quite insulting.
I'm sorry if you feel insulted, as that is never my intent, but that is what it looked like to me. I'm still relatively new at both JavaScript and foobar, so I'm going to be confused on occasion. It's a good thing I learn from my mistakes, because I make a lot of them. And hey, I was right about fb.GetLibraryItems in the first place; I just blew the call on my results.
Remember that you need to use the on_library_items_added and on_library_items_removed callbacks if you want to track changes while foobar is running.
I didn't really know that in the first place, so memory couldn't have served. The problem is that I use Notepad++ to keep documentation files open for reference, but I didn't have Callbacks.txt onboard and didn't realize what I was missing. I would have searched on 'library' (which is how I found fb.GetLibraryItems), found the callbacks mentioned and, because
on_playlist_items_added and
on_playlist_items_removed are already in the script, would probably have eventually figured I needed those, too.
I wonder what the hell else I'm missing.
Anyway, thanks for setting me straight on the missing callbacks. I'll add them in, rip more CDs and see what I get.
No album art yet but I have posted some other updates.
Thumbs: Download limits have been increased and the default has been reset to 10. Also, automatic downloads are now an option but turned off by default. Simply use the right click menu to enable.
Automatic downloads only trigger when the following conditions are true:
- a new track begins and the artist is different from the previous track
- there are no existing images. Use the Download now option if you want to check for more.
- the last automatic check was more than an hour ago. Timestamps are maintained by the script to prevent unnecessary requests if there were no images found previously.
Musicbrainz: Now attempts to retry up to 5 times on failure.
https://github.com/19379/js-marc2003/releases
Also, I just want to make one thing very clear.... there is no support if automatic downloads don't work for you. Simply use another script/software/fix it yourself/whatever. ;D
It should work with dynamic stream changes but I haven't tested that. It would be good to get some confirmation on that.
my artist arts don't get downloaded at all, I even emptied the wsh_data folder, the bio got downloaded, but not the arts
is there any way to troubleshoot this ? I'm new to this foobar thing
my artist arts don't get downloaded at all, I even emptied the wsh_data folder, the bio got downloaded, but not the arts
is there any way to troubleshoot this ? I'm new to this foobar thing
Oh jeez never mind, turns out my .vbs file needed to be re-associated
btw there is no edit button for the post here ?
File associations shouldn't even matter because my script calls cscript.exe with the full path to the vbs file.
BTW, you can only edit during the first hour after posting. It's hidden away under the More button at the bottom right of each your posts.
I dunno what that cscript.exe is but I ran that whole command "csript //nologo "download.vbs" "url" "filename" and got the error "input error:there is no script engine for file extension ".vbs"" in command prompt
so I re-associate it with "assoc .vbs=VBSFile" and it's working the way it should be
That's weird. I just associated vbs files with Notepad++ and my script still works for me.
edit: just checked with assoc and it still says VBSFILE..
.vbs=VBSFile
I guess this goes beyond what I know about. :-X
Yea I just did the same experiment as you and it worked too. I guess it's another kind of association that was lost due to the long time use of windows (I haven't reinstalled since 2009).
It seems the echonest have shut down their API so I've removed the script from my package. Also, my thumbs script has been updated so it only downloads automatically when playing.
https://github.com/19379/js-marc2003/releases
Is it possible with a JScript panel script to utilize Windows API calls?
I seem to remember that since it uses the scripting engine, this was possible.
The reason why I ask is that I have constructed a panel layout using a Panel Stack Splitter to split that panel in several sections (2 rows of 3) to house some Channel Spectrum panels.
Now for the effect I am after, these Channel Spectrums need to have their border property set to to None. But the Panel Stack Splitter itself does not have an option to set the border style.
So I was thinking, if a JScript can access the Windows API, I could insert a very small JScript panel into this layout (got some playroom) to set the border style of the container Stack Panel to Static Edge (equals the "Grey" style from the border style dropdowns)
PS. hehe, was enumeriting the Foobar window to see if there's even a border style that could be set and noticed the developer(s) probably had some difficulties with certain panel groups :) saw some names like ..._STATUS_PAIN... and ..._TOOLBAR_PAIN :p
PS; I realize trial & error could possibly get me the answer, but I can barely manage to modify an existing script to do what I want, let alone write one from scratch. I don't mind going that route but then I would like to know up front if this is possible from within a JScript panel. Wouldn't want to spent a lot of time trying to master the intricacies of the JScript Panel only to find out it isn't possible.
Why not use the edge style options built in to the channel spectrum component? As for everything else, the answer is no.
Why not use the edge style options built in to the channel spectrum component?
Well, that's exactly what I didn't want to do since that kills the effect I was going for...
it also looks ugly having a bunch of little rectangular edges inside the main panel.
So I guess I have to stick with the ugly metro look for that panel. Flat....
thanks for preventing a wild goose chase.
You can probably mimic the effect by using $drawrect in your PSS.
By the way do any of you know how to remove the track # for this playlist? I remember I did it on the other one with whs mod
Still looking for a way to do this if any of you know please tell me
What playlist are you talking about? Falstaff's JSplaylist (which I modded for JScript Panel) uses columns like other playlists which you can toggle on/off. Press CTRL+t if you've hidden the column headers.
If you're using Falstaff's JSsmooth playlist, you might need to edit the script.
marc2003, using your old script for writing playcount from last.fm and getting following error with both the updated WSH and JScript Panel.
JScript Panel (Playcount Sync (file tags) by marc2003): Microsoft JScript runtime error:
Object doesn't support this property or method
File: D:\Apps\PortableApps\foobar2000\scripts\marc2003\common.js
Line: 130, Col: 16
<source text only available at compile time>
Error row:
if (g_metadb) window.UnwatchMetadb();
Any suggestion how to make it work again?
Thanks.
Panel code:
// ==PREPROCESSOR==
// @import "%fb2k_path%scripts\marc2003\common.js"
// @import "%fb2k_path%scripts\marc2003\tooltip_buttons.js"
// @name "Playcount Sync (file tags)"
// @author "marc2003"
// ==/PREPROCESSOR==
var playcount_tag_name = "LASTFM_PLAYCOUNT";
var loved_tag_name = "LASTFM_LOVED";
var bw = 32;
var bh = 32;
var top_margin = 0;
var left_margin = 0;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
var panel_id = window.GetProperty("panel_id", window.id);
var custom_background_file = settings_path + panel_id + "buttons_background";
var custom_background = read(custom_background_file);
var username_file = settings_path + "username";
var username = read(username_file);
var api_key_file = settings_path + "api_key";
var api_key = read(api_key_file);
var autolove_file = settings_path + "autolove";
var autolove = read(autolove_file);
window.GetProperty("auto_correct", true);
if(!g_metadb) Buttons = { but: new Button(left_margin,top_margin, bw, bh, {normal: images_path + "exclamation.png"}, null, "No selection") };
on_item_focus_change();
if(fb.IsPlaying) on_playback_new_track();
function on_notify_data(name, data) {
if(name == "lastfm_update" && data == 1) {
username = read(username_file);
api_key = read(api_key_file);
on_metadb_changed();
}
}
function on_metadb_changed() {
if(!g_metadb) return;
artist = fb.TitleFormat("%artist%").EvalWithMetadb(g_metadb);
track = fb.TitleFormat("%title%").EvalWithMetadb(g_metadb);
old_userloved = fb.TitleFormat("%" + loved_tag_name +"%").EvalWithMetadb(g_metadb) ==1 ? 1 : 0;
old_userplaycount = fb.TitleFormat("%" + playcount_tag_name + "%").EvalWithMetadb(g_metadb);
command = "Last.fm " + (old_userloved == 1 ? "Unlove" : "Love") + " Track '" + track + "' by '"+ artist + "'";
update_button();
}
function update_button() {
switch(true) {
case (username.length == 0):
case (api_key.length != 32):
n = "exclamation.png";
h = "exclamation.png";
tooltip = "Please use the context menu to set your Last.fm username and API KEY.";
func = null;
break;
case (!utils.CheckComponent("foo_softplaylists", true)):
n = "exclamation.png";
h = "exclamation.png";
tooltip = "The foo_softplaylists component is required to love tracks.";
func = null;
break;
default:
n = old_userloved == 1 ? "love_h.png" : "love.png";
h = old_userloved == 1 ? "love.png" : "love_h.png";
tooltip = command;
func = function() {lfm_track();}
break;
}
Buttons = {
but: new Button(left_margin,top_margin, bw, bh, {normal: images_path + n, hover: images_path + h}, func, tooltip)
};
window.Repaint();
}
function on_playback_new_track() {
on_item_focus_change();
time_elapsed = 0;
file_is_valid = true;
target_time = 10;
}
function on_playback_time(time) {
time_elapsed++;
if(time_elapsed == 1) {
switch(true) {
case (g_metadb.RawPath.indexOf("file://") != 0 || fb.PlaybackLength < 30 || fb.PlaybackLength > 10800 || g_metadb.Path.substring(g_metadb.Path.length - 3) == "cue"):
file_is_valid = false;
target_time = 5;
break;
case (fb.PlaybackLength == 0):
target_time = 10;
break;
case (fb.PlaybackLength >= 30):
target_time = Math.min(Math.floor(fb.PlaybackLength / 2),10);
break;
default:
target_time = 5;
}
}
if(time_elapsed == target_time) sync();
}
function lfm_track() {
fb.RunContextCommandWithMetadb(command, g_metadb);
sync();
}
function sync() {
if(username.length == 0 || api_key.length != 32) return(fb.trace("Playcount sync: Can't contact Last.fm. Check your username / API KEY settings."));
fb.trace("Playcount sync: Contacting Last.fm....");
lastfm("&method=track.getinfo&artist=" + encodeURIComponent(artist) + "&track=" + encodeURIComponent(track) + "&autocorrect=" + (window.GetProperty("auto_correct") ? 1 : 0), "foo_playcount_sync", function() {process();});
}
function process() {
fb.trace("Playcount sync: Last.fm responded 'OK'");
xmlDoc = xmlhttp.responseXML;
try { userplaycount = ++xmlDoc.getElementsByTagName("userplaycount")[0].childNodes[0].nodeValue; } catch(e) { userplaycount = fb.PlaybackLength < 30 ? 0 : 1;}
try { userloved = xmlDoc.getElementsByTagName("userloved")[0].childNodes[0].nodeValue; } catch(e) { userloved = 0; }
if(file_is_valid) {
if(fb.IsPlaying && time_elapsed >= target_time)
fb.trace("Old value: " + old_userplaycount);
fb.trace("New value: " + userplaycount);
if(fb.TitleFormat(autolove).Eval() == 1 && old_userloved == 0) {
fb.trace("Playcount Sync: Automatically loving this track....");
lfm_track();
}
// PREVENT LOWER VALUE FROM LAST.FM
if (old_userplaycount > userplaycount ) {
fb.trace("Last.fm playcount is lower, not updating tags!");
}
else { update_tag(playcount_tag_name,old_userplaycount,userplaycount); //ORIG
}
update_tag(loved_tag_name,old_userloved,userloved);
} else {
fb.trace("Can't write tags to this file! Possible reasons: too long, too short, it's a stream, it references an external cue sheet.");
old_userloved = userloved == 1 ? 1: 0;
update_button();
}
}
function update_tag(tag, o, n) {
if(o == "?") {o = 0;}
if(o != n) {
fb.trace("Playcount sync: Updating " + tag + " " + o + " > " + n);
g_metadb.UpdateFileInfoSimple(tag, n != 0 ? n : '');
} else {
fb.trace("Playcount sync: Not updating " + tag + ". No changes found.")
}
}
function on_size() {
ww = window.Width;
wh = window.Height;
}
function on_mouse_rbtn_up(x, y) {
var _menu = window.CreatePopupMenu();
var _au = window.CreatePopupMenu();
var _child = window.CreatePopupMenu();
var _auto = window.CreatePopupMenu();
var idx;
_au.AppendMenuItem(MF_STRING, 6, "Use spelling correction");
_au.CheckMenuItem(6, window.GetProperty("auto_correct"));
_menu.AppendMenuItem(MF_STRING | MF_POPUP, _au.ID, "Auto-updates");
_child.AppendMenuItem(MF_STRING, 101, "None");
_child.AppendMenuItem(MF_STRING, 102, (dui ? "Default UI " : "Columns UI ") + "default");
_child.AppendMenuItem(MF_STRING, 103, "Splitter");
_child.AppendMenuItem(MF_STRING, 104, "Custom ");
_child.AppendMenuItem(MF_SEPARATOR, 0, 0);
_child.AppendMenuItem(window.GetProperty("mode") == 104 ? MF_STRING : MF_GRAYED, 105, "Set custom colour...");
_child.CheckMenuRadioItem(101, 104, window.GetProperty("mode", 101));
_menu.AppendMenuItem(MF_SEPARATOR, 0, 0);
_auto.AppendMenuItem(window.GetProperty("auto_menu") ? MF_STRING : MF_STRING, 202, "Condition");
_auto.CheckMenuRadioItem(200, 201, window.GetProperty("auto_menu") ? 201 : 200);
_menu.AppendMenuItem(MF_STRING | MF_POPUP, _auto.ID, "Automatically love tracks");
_menu.AppendMenuItem(MF_SEPARATOR, 0, 0);
_menu.AppendMenuItem(MF_STRING, 2, "Set your Last.fm username...");
_menu.AppendMenuItem(MF_STRING, 3, "Set your API KEY...");
_menu.AppendMenuItem(MF_SEPARATOR, 0, 0);
_menu.AppendMenuItem(username.length > 0 ? MF_STRING : MF_GRAYED, 1, "Visit your Last.fm user profile page");
_menu.AppendMenuItem(MF_SEPARATOR, 0, 0);
_menu.AppendMenuItem(MF_STRING | MF_POPUP, _child.ID, "Background");
_menu.AppendMenuItem(MF_SEPARATOR, 0, 0);
if(utils.IsKeyPressed(0x10)) _menu.AppendMenuItem(MF_STRING, 9, "Properties");
_menu.AppendMenuItem(MF_STRING, 10, "Configure...");
idx = _menu.TrackPopupMenu(x, y);
switch(idx) {
case 1:
try {
WshShell.run("http://www.last.fm/user/" + encodeURIComponent(username));
} catch(e) {
fb.ShowPopupMessage("Unable to launch your default browser.", "Playcount Sync");
}
break;
case 2:
username = text_input_box("Playcount Sync", "Please enter your Last.fm username", username_file);
on_metadb_changed();
window.NotifyOthers("lastfm_update", 1);
break;
case 3:
api_key = text_input_box("Playcount Sync", "Please enter your Last.fm API KEY\n\nhttp://www.last.fm/api/account", api_key_file);
on_metadb_changed();
window.NotifyOthers("lastfm_update", 1);
break;
case 6:
window.SetProperty("auto_correct", !window.GetProperty("auto_correct"));
break;
case 7:
window.SetProperty("debug", !window.GetProperty("debug"));
break;
case 101:
case 102:
case 103:
case 104:
window.SetProperty("mode", idx);
window.Repaint();
break;
case 105:
custom_background = text_input_box("Playcount Sync", "Enter a custom colour for the background. Uses RGB. Example usage:\n\n234-211-74", custom_background_file);
window.Repaint();
break;
case 201:
window.SetProperty("auto_menu", idx == 200 ? false : true);
break;
case 202:
autolove = text_input_box("Playcount Sync", "The result of the title formatting set here must equal 1 for a track to be automatically loved.\n\nExample:\n\n$ifequal(%rating%,5,1,0)", autolove_file);
break;
case 9:
window.ShowProperties();
break;
case 10:
window.ShowConfigure();
break;
}
_menu.Dispose();
_auto.Dispose();
_au.Dispose();
_child.Dispose();
return true;
}
function on_paint(gr) {
buttons_background(gr);
buttonsDraw(gr);
}
You need WSH panel mod v1.5.6 for a script that old.
https://code.google.com/archive/p/foo-wsh-panel-mod/downloads
You need WSH panel mod v1.5.6 for a script that old.
https://code.google.com/archive/p/foo-wsh-panel-mod/downloads
It's such a good script, not willing to abandon it for a newer non-compliant version. O:)
Thanks for making it.
Problem with mouse wheel scrolling, in last fm bio text, steps are big, about 5 strings, and breaks appear in reading text. problem in the computer or in a script? changed computer mouse options does nothing
Put this in a panel and show me the results from the console when scrolling up and then down...
function on_mouse_wheel(a, b, c) {
fb.trace("a: " + a);
fb.trace("b: " + b);
fb.trace("c: " + c);
}
In the meantime, you can use the up/down buttons to scroll (install the font if you can't see them). If using the
now playing (basic) script, there is a bug where clicking too quickly will open the background image so this has been fixed.
https://github.com/19379/js-marc2003/releases
I've also added a
Stop button to
track info + seekbar + buttons.
Down
a: -1
b: -120
c: 120
Up
a: 1
b: 120
c: 120
using up/down buttons same too
Ah, you don't have the problem I was thinking of.
The default of 5 shouldn't be a problem so long as you don't do anything stupid like having a really small panel. If you want to change the default of 5 lines, you can open js_marc2003\js\text.js and look for the this.wheel function. Inside, change the number 5 to whatever.
If you're getting big gaps between lines/paragraphs then that will be because of how the source text is formatted on Last.fm. Anyone with an account can edit the wiki pages.
.......... I just solved my problem 5 minutes after this post. Dismiss this please.
Another problem came up.
It seems that if I create an empty image (gdi.CreateImage), and write some text in it (GdiDrawText), the edge of the characters' shape are seen as 1px dark lines. If the image is going to be used on a white background, the dark edges can be annoying.
Are there any methods to avoid them, without giving up using gdi.CreateImage? I thought this was due to SetTextRenderingHint, but soon it was denied in experiments.
screenshot: (http://i.imgur.com/SZqTbJI.png)
Try DrawString instead...
temp_gr.SetTextRenderingHint(4);
temp_gr.DrawString(...);
Try DrawString instead...
That works. Thanks!
I've knocked up a quick and dirty script for downloading album art from Last.fm if anyone wants to test it.
https://gist.github.com/19379/685a2fac5d45fd9a6231fe5fab156dc5
Make sure you edit the filename to match what you want and also update the main foobar2000 album art preferences to match.
It requires the js_marc2003 folder from my main samples (link in sig).
Seems to be working fine, thanks marc2003!
A suggestion: add a toggle to set whether art should be downloaded for all tracks, or tracks in the library only.
marc2003, thank you so much for replying here so often and supporting your component in this wonderful way. I flung more than a few pennies towards charities and artists and also supporting Foobar mobile & component developers. Yet, your support, time and effort is much appreciated and I'd still like to contribute somehow. So if money's not an option, let's see what scripts I can make :).
Now I have a question concerning hotkeys. I am quite keyboard-focused and for me it's essential to be able to navigate through a program using the keyboard. My question is this:
Is it possible for each JS Panel to hook into Foobar's keyboard shortcuts system and register a shortcut for bringing the keyboard focus to that panel? I'm asking this because I plan to have 2-3 JS Panels open, plus a ColumnsUI playlist and I'd like to navigate between them. In the same time, I'd like each panel to react to its own keyboard shortcuts only when I'm inside that panel (I've seen that scripts already do this, for example when doing name searches inside a JS Panel you see those letters show up that show what you've been typing).
Another question: are CTRL, ALT modifiers usable with the JS Panel?
A suggestion: add a toggle to set whether art should be downloaded for all tracks, or tracks in the library only.
Yep, I'll post in this thread when I update it.
Now I have a question concerning hotkeys.
Currently, the panel has to have focus to accept input. You can use modifiers like this...
var VK_SHIFT = 0x10;
var VK_CONTROL = 0x11;
var VK_ALT = 0x12;
function on_key_down(vkey) {
if (utils.IsKeyPressed(VK_CONTROL) && utils.IsKeyPressed(VK_ALT) && vkey == 65)
fb.ShowPopupMessage("ctrl + alt + a");
}
The likelihood of me creating keyboard shortcuts to focus a panel is pretty much zero but I think it would be possible to create main menu items which could trigger callbacks in all panels. Obviously those menu items have to be shared across all scripts from all users so my recommendation would be to implement them in personal scripts only and of course each user would have to bind these menu items to their own keyboard combinations in the main preferences.
I've updated my samples...
status bar: now shows playlist name next to stats. Use the right click menu to toggle details on/off. For existing users, this update requires importing the new txt file in to the panel.
All list/text based scripts have the mouse scroll step set to 3 lines.
https://github.com/19379/js-marc2003/releases
marc2003: I've checked the window structure of Foobar. I noticed that the JS panel windows have the class "uie_jscript_panel_class". Initially, I thought of a really ugly workaround: I will try to write a simple C++ application which can do the focusing of the JS panels for me, by using WIN32 API calls. But now I realize I could make a Foobar component that offers shortcuts for the user to set. I'd like to do this :), but a few pointers from you would be priceless to say the least. Here are 2 questions:
1. Can you indicate a way through which I can separate one JS Panel from another? They have the same class but no caption, no window title. A window title would be very handy, because I could use it when creating keyboard shortcuts for focusing the panels: <Activate JS Panel "Smooth Browser">, <Activate JS Panel "Custom Buttons">.
2. Can you (or anybody here knowledgeable in Foobar components) give me a link to a component that registers shortcuts in Foobar? An example always goes a long way :).
Thank you in advance! :)
^I have no idea. I have zero C++ knowledge and only created this component because a) WSH panel mod was already rock solid with barely any issues and b) adding new stuff from the foobar2000 SDK is easy enough when so much similar code already existed in the original component. I'm just good at copy/paste.
As I mentioned above, the code already exists for when the panel has focus and I believe the only way to create global shortcuts is by generating main menu or context menu items. These can then be bound to global keys in the main foobar preferences.
I've updated my samples so Last.fm chart data is now accurate. There was nothing wrong with my previous code - it's just that I stupidly followed Last.fm's documented methods which I no longer do.
https://github.com/19379/js-marc2003/releases
When playing tracks in Random order, as I do most of the time, the Previous button stops playback. Since I already have a Stop button, I decided to eliminate the redundancy by repurposing Previous to act as a Back button, which restarts playback of the current track from the beginning.
I changed this (slightly modified) line from marc2003's
"track info + seekbar + buttons" sample script...
this.buttons.previous = new _.button(722, 364, 36, 36, {normal : "mono\\appbar.control.rewind.png"}, function () { fb.Prev(); }, "Previous");
...to this:
this.buttons.previous = new _.button(722, 364, 36, 36, {normal : "mono\\appbar.control.rewind.png"}, plman.PlaybackOrder == random_order ? function () {fb.PlaybackTime = 0;} : function () { fb.Prev(); }, "Previous");
random_order is a var set to 3 to clarify what I'm testing for.
The Previous button works normally when not in Random order playback mode.
What playlist are you talking about? Falstaff's JSplaylist (which I modded for JScript Panel) uses columns like other playlists which you can toggle on/off. Press CTRL+t if you've hidden the column headers.
If you're using Falstaff's JSsmooth playlist, you might need to edit the script.
I am talking about the default one, I just want to remove the track numbers on the left.
Do you have any idea what thread you're posting in?
Hi, this is my litte work for auto tag from file name in playlist, I wrote it long time ago, grabbed from my foobar200 skin (http://forum.gamer.com.tw/Co.php?bsn=60030&sn=1589300).
If file name is "Artist - Title", and no tag, in playlist this code will make list itme show "Artist*" - "Title*", " * " means it grab from file name, then you can auto tag it, the sample code is use in playlist's context menu.
var tf_artist = fb.TitleFormat("$if(%length%,$if2(%artist%,$ifgreater($strchr(%filename%,-),0,$trim($substr(%filename%,1,$sub($strchr(%filename%,-),1)))*,?)),)");
var tf_title = fb.TitleFormat("$ifgreater($strchr(%filename%,-),0,$trim($substr(%filename%,$add($strchr(%filename%,-),1),100)*),%title%)");
//......make tf_artist & tf_title use in your playlist or elsewhere you want.
function new_context_menu(x, y, id, array_id) {
//......
list.metadblist_selection = plman.GetPlaylistSelectedItems(plman.ActivePlaylist);
var info = list.metadblist_selection.item(i).GetFileInfo();
var o_title = info.MetaValue(info.MetaFind("TITLE"), 0) ? tf_titleO : fb.TitleFormat("");
var o_artist = fb.TitleFormat("$ifequal($stricmp(%artist%,?),1,,%artist%)");
var o_album = fb.TitleFormat("$ifequal($stricmp(%album%,?),1,,%album%)");
//......
_menu.AppendMenuItem(list.metadblist_selection.count==1 && info.MetaValue(info.MetaFind("TITLE"), 0) && !tf_artist.EvalWithMetadb(list.metadblist_selection.item(i)).match(/\*/) ? MF_GRAYED|MF_DISABLED : MF_STRING, 3000, list.metadblist_selection.count==1 && ( !info.MetaValue(info.MetaFind("TITLE"), 0) || tf_artist.EvalWithMetadb(list.metadblist_selection.item(i)).match(/\*/) ) ? "Auto Tag *:" + (o_title.EvalWithMetadb(list.metadblist_selection.item(i)) ? "" : tf_title.EvalWithMetadb(list.metadblist_selection.item(i)).replace("*", "") + (o_artist.EvalWithMetadb(list.metadblist_selection.item(i)) ? "" : ", ")) + (o_artist.EvalWithMetadb(list.metadblist_selection.item(i)) ? "" : tf_artist.EvalWithMetadb(list.metadblist_selection.item(i)).replace("*", "")) : "Auto Tag *");
//......
case 3000:
for (i=0; i<list.metadblist_selection.count; i++) {
if (tf_title.EvalWithMetadb(list.metadblist_selection.item(i)).match(/\*/)) {
var title = tf_title.EvalWithMetadb(list.metadblist_selection.item(i)).replace("*", "");
list.metadblist_selection.item(i).UpdateFileInfoSimple("TITLE", title);
}
if (tf_artist.EvalWithMetadb(list.metadblist_selection.item(i)).match(/\*/)) {
var artist = tf_artist.EvalWithMetadb(list.metadblist_selection.item(i)).replace("*", "");
list.metadblist_selection.item(i).UpdateFileInfoSimple("ARTIST", artist);
}
}
break;
//......please shows source if you use this, thanks ;)......
I don't if it work in JScript Panel, just share, maybe useful for someone.
I'd like to adjust the size of JS panel with foobar resizing as follows.
In other words, the size of JS panel shoud change proportionally with the main foobar window size.
Is ther any method to retrieve the foobar window size into the JS panel for this purpose?
That's something foobar does by default with all panels - assuming you don't lock any splitters.
That's something foobar does by default with all panels - assuming you don't lock any splitters.
Thank you for your reply.
More specifically, what I want to do is
In the max foobar size, I fixed the JS panel width/height = 600/400.
function on_size() {
ww = window.Width;
wh = window.Height;
window.MinWidth = 600;
window.MaxWidth = 600;
window.MinHeight = 400;
window.MaxHeight = 400;
}
And,, then I resize the foobar window size to the x% of the max foobar size.
In this case, I want to resize JS panel width/height = (600/400) * x/100.
Is this possible?
Well of course it won't work if you're locking the size. Read my post again.
Well of course it won't work if you're locking the size. Read my post again.
I'm sorry for the uncertain question.
My question is, if I can adjust the values as follows with not fixed, but as variables
window.MinWidth = 600; --> window.MinWidth = 0.4 x (Foobar window width)
window.MaxWidth = 600; --> window.MinWidth = 0.4 x (Foobar window width)
I start off with a small window and my JScript Panel is just over one third of foobar's width. I resized the splitter manually...
http://i.imgur.com/jbzzp8Y.png
Now I max the window and foobar has kept the same proportions. No script, no locked splitters.
http://i.imgur.com/MQ6eKSu.png
edit: I don't think you will be able to set a min width because then foobar will forget the proportions when you start going larger again.
I suppose you could have another panel taking up the entire width and have that notify your other panel when it is resized. I'll post something for that later but I have to go out now.
I start off with a small window and my JScript Panel is just over one third of foobar's width. I resized the splitter manually...
http://i.imgur.com/jbzzp8Y.png
Now I max the window and foobar has kept the same proportions. No script, no locked splitters.
http://i.imgur.com/MQ6eKSu.png
OK. I got it. Thank you for your time and help.
I'm using "now playing (basic)" script after small modification like this
var ft1 = 50, ft2 = 42, ft3 = 30, y1 = 0, y2 = 75, y3 = 150;
//the track info section displays 4 lines of title formatted text. you can customise that here/////////////////////////////////////////////
var line1 = {
text: "", //leave this blank
tf: "$if2(%artist%,No Artist Info)", //enter any title formatting
font: _.gdiFont("Segoe UI", ft1, 1), //font name, size, style. 1 means bold and 0 is normal.
colour: _.RGB(40, 40, 40), //colour
y: y1 //change this value to move text up or down.
}
var line2 = {
text: "",
tf: "$if2(%title%,No Song Info)",
font: _.gdiFont("Segoe UI", ft2, 1),
colour: _.RGB(90, 90, 90),
y: y2
}
var line3 = {
text: "",
tf: "$if([%album% ]['('%date%')'],[%album% ]['('%date%')'],No Album Info)",
font: _.gdiFont("Segoe UI", ft3, 1),
colour: _.RGB(140, 140, 140),
y: y3
}
And, I'm trying to change the font & location of line1, line2, line3 after getting a notification from another panel.
I've put "window.NotifyOthers("width_notify",ww);" within 'function on_size()' in another panel.
So, I inserted the following code to change the font size and location.
function on_notify_data(name, info) {
if(name=="width_notify") {
if(info==1920) {
ft1 = 50, ft2 = 42, ft3 = 30, y1 = 0, y2 = 75, y3 = 150;
window.Repaint();
} else {
ft1 = 30, ft2 = 22, ft3 = 15, y1 = 0, y2 = 40, y3 = 80;
window.Repaint();
}
}
}
But this dosen't work for my purpose. I'm not familiar with the programming language.
So, please give me some hint.
You're basically doing this...
var a = 1;
var b = a;
function blah() {
a = 2; // now you're expecting "b" to take on the new value of "a" which is never going to work
}
You need to update the variables directly
line1.font = 50;
line1.y = 0;
...
You're basically doing this...
var a = 1;
var b = a;
function blah() {
a = 2; // now you're expecting "b" to take on the new value of "a" which is never going to work
}
You need to update the variables directly
line1.font = 50;
line1.y = 0;
...
Thank you for your help. The following is what I'm using now.
function on_notify_data(name, info) {
if(name=="width_notify") {
if(info==1920) {
line0.font = _.gdiFont("Cambria", 110, 1);
line0.y = 0;
window.Repaint();
} else {
line0.font = _.gdiFont("Cambria", 80, 1);
line0.y = 20;
window.Repaint();
}
}
}
Again, me.. :-[
Is there any method to make a shadow effect on the "now playing panel" text?
Draw the text twice and have a slight offset between each one's x and y positions. Also some contrasting colour would help.
Or if you want something more fancy, see the samples folder inside the component directory>glow text sample.txt
I've knocked up a quick and dirty script for downloading album art from Last.fm if anyone wants to test it.
https://gist.github.com/19379/685a2fac5d45fd9a6231fe5fab156dc5
This works great marc. Still am naming all my album cover art %album%, so it's nice this works since the last time (https://hydrogenaud.io/index.php/topic,103681.msg851682.html#msg851682) I stumbled around a script.
I wonder if you could help me with a problem I'm having with br3tt's smooth playlist (http://br3tt.deviantart.com/art/JS-Smooth-Playlist-571375892) script marc. For the thumbnail cache files created in '\js_br3tt\cache\imgcache' the script looks to the track's folder, and it seems like if it doesn't find any variations in the script, it selects the 1st jpg in the folder with *.* and uses that. I tried with limited success to change the code for name of the files the cache uses from:
masks: window.GetProperty("_PROPERTY: Cover art masks (used for the cache)","*front*.*;*cover*.*;*folder*.*;*.*"),
to just:
masks: window.GetProperty("_PROPERTY: Cover art masks (used for the cache)","%album%.*"),
It seemed like when a cache file wasn't already made, that tended to work. But in later attempts it seemed that wasn't the case, and the script would just choose the 1st jpg in the folder it pleased.
And I've found no way to clear the cached file for the thumbnails that are wrong without deleting the entire cache folder.
Any ideas on how to address these probs?
Another problem came up.
It seems that if I create an empty image (gdi.CreateImage), and write some text in it (GdiDrawText), the edge of the characters' shape are seen as 1px dark lines. If the image is going to be used on a white background, the dark edges can be annoying.
Are there any methods to avoid them, without giving up using gdi.CreateImage? I thought this was due to SetTextRenderingHint, but soon it was denied in experiments.
screenshot: (http://i.imgur.com/SZqTbJI.png)
I'd really love to have this set up in my build to enable quick playback order preferences. Anywhere I can grab the code for this and the graphic?
I need to rework that album art script because it doesn't account for people using title formatting with the filename. Currently it won't work if the album contains characters that are illegal in windows. I'll post an update later.
As for looking at Falstaff/Br3tt's other scripts... nope. I made some minor mods to jsplaylist because I use it everyday. I have no interest in other people's scripts that I don't use.
A suggestion: add a toggle to set whether art should be downloaded for all tracks, or tracks in the library only.
Sorry I forgot about this. It's now a variable you set at the start of the script.
https://gist.github.com/19379/685a2fac5d45fd9a6231fe5fab156dc5
It also handles illegal characters that may be contained in any title formatting used for the filename.
I need to rework that album art script because it doesn't account for people using title formatting with the filename. Currently it won't work if the album contains characters that are illegal in windows. I'll post an update later.
OK. I just set it up, so I haven't tested it a lot. Will keep an eye out for your update.
As for looking at Falstaff/Br3tt's other scripts... nope.
I haven't checked recently, but Br3tt never seemed to hang out in the forums very much. Think he'd notice if I addressed him here directly? Or maybe I'd have better luck posting on his DeviantArt page.
... I made some minor mods to jsplaylist because I use it everyday.
That's a WSH panel script from his DeviantArt page (http://br3tt.deviantart.com/art/JSPlaylist-509803158), right? I did give that try and had considered using it as an alternative. But since I last posted, I've confirmed that both jsplaylist and his smooth playlist prevent FB2K from completely shutting down in Windows 10. I had to delete panels 1 by 1 until I finally found the culprit. Wonder if your mod would be any different. Have you made it available for download anywhere?
Sorry I forgot about this. It's now a variable you set at the start of the script.
https://gist.github.com/19379/685a2fac5d45fd9a6231fe5fab156dc5
It also handles illegal characters that may be contained in any title formatting used for the filename.
This is crashing the panel when I replace the old code marc.
I've knocked up a quick and dirty script for downloading album art from Last.fm if anyone wants to test it.
https://gist.github.com/19379/685a2fac5d45fd9a6231fe5fab156dc5
Make sure you edit the filename to match what you want and also update the main foobar2000 album art preferences to match.
It requires the js_marc2003 folder from my main samples (link in sig).
It works good for me. Is there a simple script line I could add to automatically attach the picture to all the files in the folder after downloading it?
I've knocked up a quick and dirty script for downloading album art from Last.fm if anyone wants to test it.
https://gist.github.com/19379/685a2fac5d45fd9a6231fe5fab156dc5
Make sure you edit the filename to match what you want and also update the main foobar2000 album art preferences to match.
It requires the js_marc2003 folder from my main samples (link in sig).
It works good for me.
Actually I realized it doesn't show the online pictures, even though it downloads them correctly.
Actually I realized it doesn't show the online pictures, even though it downloads them correctly.
"online pictures"?? The script will crop a little of the borders. Resizing the panel will show the edges better. Not sure what you mean.
Actually I realized it doesn't show the online pictures, even though it downloads them correctly.
"online pictures"?? The script will crop a little of the borders. Resizing the panel will show the edges better. Not sure what you mean.
I mean when the album art picture is missing from the local directory, isn't the script supposed to show the picture from the lastfm online resource?
I mean when the album art picture is missing from the local directory, isn't the script supposed to show the picture from the lastfm online resource?
The script saves the graphic file in the same folder as the track, and is named: lastfm.jpg Check the track folder to see if its there.
I mean when the album art picture is missing from the local directory, isn't the script supposed to show the picture from the lastfm online resource?
The script saves the graphic file in the same folder as the track, and is named: lastfm.jpg Check the track folder to see if its there.
Yes, that works and I managed to change the default picture name as I wanted. I just thought I could see a preview of the picture on the panel.
The image should load when you skip forward a track, and then back up again if you have playback order set to default. But you have to set FB2K to recognize the file name lastfm.jpg in preferences:
Preferences > Display > Album Art > Front cover
What's your default cover art naming pattern?
The image should load when you skip forward a track, and then back up again if you have playback order set to default. But you have to set FB2K to recognize the file name lastfm.jpg in preferences:
Preferences > Display > Album Art > Front cover
What's your default cover art naming pattern?
$directory_path(%path%)\front.jpg (I edited the script accordingly at line 17) which I embed in the music files, so my jscript artreader is set to show the Icon. When there's no embedded icon (which usually means there's no front.jpg in the file directory either) the panel is a just a white background, even if the script finds the picture on lastfm and downloads it properly.
If you rename the downloaded file from lastfm.jpg to front.jpg, does the panel then display it?
If you rename the downloaded file from lastfm.jpg to front.jpg, does the panel then display it?
I edited the script so that it downloads it as "front.jpg" by default, but in order to see it in the panel I have to embed the picture first.
Okay... I missed what you'd written there. Sounds like you need the script to recognize 2 different cover art names... front.jpg for your embedded tags, and now lastfm.jpg that this script is creating. I had this problem of with another script a while ago where I wanted the script to look for art in a couple places. But as I recall, the script (I think in Br3tt's Kameleon) wouldn't allow it. marc2003 or someone else may be able to tell you if it's possible.
Or... you need something to automatically write the downloaded file to the tags... if I back up I think that's what you were asking.
directory_path(%path%)\front.jpg (I edited the script accordingly at line 17)
Wait... line 17 is from marc's lastest offering above. That crashed every copy of FB2k I tried pasting it into a jscript panel. Did you get it to work?
The code in that script is: var filename_tf = fb.TitleFormat("lastfm.jpg");
directory_path(%path%)\front.jpg (I edited the script accordingly at line 17)
Did you get it to work?
The code in that script is: var filename_tf = fb.TitleFormat("lastfm.jpg");
Sure, I simply edited "lastfm.jpg" to "front.jpg".
Man... This script? It's crashed every time I've tried putting into a jscript panel. Maybe I need the newer foo_jscript_panel-v1.1.4.
// ==PREPROCESSOR==
// @name "Last.fm Album Art Downloader"
// @author "marc2003"
// @import "%fb2k_profile_path%js_marc2003\js\lodash.min.js"
// @import "%fb2k_profile_path%js_marc2003\js\helpers.js"
// @import "%fb2k_profile_path%js_marc2003\js\panel.js"
// @import "%fb2k_profile_path%js_marc2003\js\albumart.js"
// ==/PREPROCESSOR==
// Affects downloads only. Album art will always be displayed if it's found via the patterns
// in the main preferences.
var library_tracks_only = false;
// Note that any attempt to use a folder that doesn't already exist will silently fail
var folder_tf = fb.TitleFormat("$directory_path(%path%)\\");
// Make sure File>Preferences>Display>Album art>Front matches this filename for the image
// to be displayed. Title formatting is supported.
var filename_tf = fb.TitleFormat("lastfm.jpg");
///////////////////////////////////////////////////////////////////////////////////////////////////
var panel = new _.panel("Last.fm Album Art Downloader", ["metadb", "custom_background"]);
var albumart = new _.albumart(0, 0, 0, 0);
var x = new ActiveXObject("Microsoft.XMLHTTP");
var ini = folders.settings + "album-art.ini";
_.createFolder(folders.settings);
panel.item_focus_change();
function on_size() {
panel.size();
albumart.w = panel.w;
albumart.h = panel.h;
}
function on_paint(gr) {
panel.paint(gr);
albumart.paint(gr);
}
function on_metadb_changed() {
albumart.metadb_changed();
var np = fb.GetNowPlaying();
if (panel.metadb && np && np.Compare(panel.metadb) && np.RawPath.indexOf("file://") == 0 && (!library_tracks_only || fb.IsMetadbInMediaLibrary(np))) {
var ar = panel.tf("%album artist%");
var al = panel.tf("%album%");
var f = folder_tf.EvalWithMetadb(panel.metadb) + _.fbSanitise(filename_tf.EvalWithMetadb(panel.metadb));
var tmp = _.q(_.fbSanitise(ar + al));
var n = _.round(_.now() / 1000);
var t = utils.ReadINI(ini, "Timestamps", tmp, 0);
switch (true) {
case !_.tagged(ar):
case !_.tagged(al):
case _.isFile(f):
case n - t < ONE_DAY:
break;
default:
utils.WriteINI(ini, "Timestamps", tmp, n);
x.open("GET", "http://www.last.fm/music/" + encodeURIComponent(ar) + "/" + encodeURIComponent(al) + "/+images", true);
x.setRequestHeader("If-Modified-Since", "Thu, 01 Jan 1970 00:00:00 GMT");
x.send();
x.onreadystatechange = function () {
if (x.readyState == 4) {
if (x.status == 200) {
var o = _.first(_.filter(_.getElementsByTagName(x.responsetext, "img"), {"className" : "image-list-image"}));
if (o) {
var u = o.src.replace("avatar170s", "ar0");
_.runCmd("cscript //nologo " + _.q(folders.home + "download.vbs") + " " + _.q(u) + " " + _.q(f), false);
window.SetTimeout(function () {
panel.item_focus_change();
}, 3000);
}
} else {
panel.console("HTTP error: " + x.status);
}
}
}
break;
}
}
}
function on_get_a
Man... This script? It's crashed every time I've tried putting into a jscript panel. Maybe I need the newer foo_jscript_panel-v1.1.4.
// ==PREPROCESSOR==
// @name "Last.fm Album Art Downloader"
// @author "marc2003"
// @import "%fb2k_profile_path%js_marc2003\js\lodash.min.js"
// @import "%fb2k_profile_path%js_marc2003\js\helpers.js"
// @import "%fb2k_profile_path%js_marc2003\js\panel.js"
// @import "%fb2k_profile_path%js_marc2003\js\albumart.js"
// ==/PREPROCESSOR==
// Affects downloads only. Album art will always be displayed if it's found via the patterns
// in the main preferences.
var library_tracks_only = false;
// Note that any attempt to use a folder that doesn't already exist will silently fail
var folder_tf = fb.TitleFormat("$directory_path(%path%)\\");
// Make sure File>Preferences>Display>Album art>Front matches this filename for the image
// to be displayed. Title formatting is supported.
var filename_tf = fb.TitleFormat("lastfm.jpg");
///////////////////////////////////////////////////////////////////////////////////////////////////
var panel = new _.panel("Last.fm Album Art Downloader", ["metadb", "custom_background"]);
var albumart = new _.albumart(0, 0, 0, 0);
var x = new ActiveXObject("Microsoft.XMLHTTP");
var ini = folders.settings + "album-art.ini";
_.createFolder(folders.settings);
panel.item_focus_change();
function on_size() {
panel.size();
albumart.w = panel.w;
albumart.h = panel.h;
}
function on_paint(gr) {
panel.paint(gr);
albumart.paint(gr);
}
function on_metadb_changed() {
albumart.metadb_changed();
var np = fb.GetNowPlaying();
if (panel.metadb && np && np.Compare(panel.metadb) && np.RawPath.indexOf("file://") == 0 && (!library_tracks_only || fb.IsMetadbInMediaLibrary(np))) {
var ar = panel.tf("%album artist%");
var al = panel.tf("%album%");
var f = folder_tf.EvalWithMetadb(panel.metadb) + _.fbSanitise(filename_tf.EvalWithMetadb(panel.metadb));
var tmp = _.q(_.fbSanitise(ar + al));
var n = _.round(_.now() / 1000);
var t = utils.ReadINI(ini, "Timestamps", tmp, 0);
switch (true) {
case !_.tagged(ar):
case !_.tagged(al):
case _.isFile(f):
case n - t < ONE_DAY:
break;
default:
utils.WriteINI(ini, "Timestamps", tmp, n);
x.open("GET", "http://www.last.fm/music/" + encodeURIComponent(ar) + "/" + encodeURIComponent(al) + "/+images", true);
x.setRequestHeader("If-Modified-Since", "Thu, 01 Jan 1970 00:00:00 GMT");
x.send();
x.onreadystatechange = function () {
if (x.readyState == 4) {
if (x.status == 200) {
var o = _.first(_.filter(_.getElementsByTagName(x.responsetext, "img"), {"className" : "image-list-image"}));
if (o) {
var u = o.src.replace("avatar170s", "ar0");
_.runCmd("cscript //nologo " + _.q(folders.home + "download.vbs") + " " + _.q(u) + " " + _.q(f), false);
window.SetTimeout(function () {
panel.item_focus_change();
}, 3000);
}
} else {
panel.console("HTTP error: " + x.status);
}
}
}
break;
}
}
}
function on_get_a
I'm talking about this script (https://hydrogenaud.io/index.php?msg=920337).
I found the problem davideleo ... I copied the code to the bottom of the github page marc posted, but I failed to notice I'd missed a little more that was underneath. My bad :-[ All's good now ;)
I'm new to jscript and after following the tutorials I built the following script. Everything displays correctly, but the loop I have keeps re-drawing the panel. Was wondering if there's a way to keep the loop from re-drawing or is there a way to just re-draw the section where time elapse and time remaining counts up and down?
Hope this makes sense :) Thanks in advance for any help or comments (also thanks for marc2003 for making the jscript plugin)
// ==PREPROCESSOR==
// @name "Title Header"
// @author "Chigaimaro"
// @feature "watch-metadb"
// @import "%fb2k_component_path%docs\flags.txt"
// @import "%fb2k_component_path%docs\helpers.txt"
// ==/PREPROCESSOR==
var setTitlefont = gdi.Font("Segoe UI", 16.5,0);
var artist_font = gdi.Font("Segoe UI", 13,0);
var album_font = gdi.Font("Segoe UI", 12,0);
var g_is_default_ui = window.InstanceType;
var g_font = null;
var ww = 0, wh = 0;
var g_textcolor = 0, g_textcolor_hl = 0;
var g_backcolor = 0;
var time_font = gdi.Font("Segoe UI", 18, 0);
var stat_font = gdi.Font("Segoe UI", 13, 0);
var counter = 0;
get_font();
get_colors();
function get_font() {
if (g_is_default_ui) { // DUI
g_font = window.GetFontDUI(FontTypeDUI.defaults);
} else { // CUI
g_font = window.GetFontCUI(FontTypeCUI.items);
}
}
function get_colors() {
if (g_is_default_ui) { // DUI
g_textcolor = window.GetColorDUI(ColorTypeDUI.text);
g_textcolor_hl = window.GetColorDUI(ColorTypeDUI.highlight);
g_backcolor = window.GetColorDUI(ColorTypeDUI.background);
g_selectcolor = window.GetColorDUI(ColorTypeDUI.selection);
} else { // CUI
g_textcolor = window.GetColorCUI(ColorTypeCUI.text);
g_textcolor_hl = window.GetColorCUI(ColorTypeCUI.text);
g_backcolor = window.GetColorCUI(ColorTypeCUI.background);
}
}
function on_size() {
ww = window.Width;
wh = window.Height;
}
function on_paint(gr) {
gr.FillSolidRect(0, 0, ww, wh, g_backcolor);
for(counter = 0; counter < 6; counter++){
var allMargin = ["0", "110", "220", "330", "440", "550"];
var time_tags = [fb.TitleFormat("%playback_time%").Eval(),
fb.TitleFormat("%playback_time_remaining%").Eval(),
fb.TitleFormat("%length%").Eval(),
fb.TitleFormat("$if2(%tracknumber%,'00')/$if2(%totaltracks%,'00')").Eval(),
fb.TitleFormat("$if(%discnumber%,$pad_right(%discnumber%,2),'00')$if(%totaldiscs%,'/'$pad_right(%totaldiscs%,2),)").Eval(),
fb.TitleFormat("[%replaygain_track_gain%]')").Eval()
]
var labels = ["Elapsed", "Remaining", "Length", "Track/Total", "Disc/Total", "Replaygain"];
var info_tags = [fb.TitleFormat("$info(encoding)").Eval(),
fb.TitleFormat("$info(codec)").Eval(true),
fb.TitleFormat("$if($info(bitrate),$info(bitrate)' kb/s','00 kb/s')").Eval(),
fb.TitleFormat("$channels()").Eval(true),
fb.TitleFormat("%__bitspersample%-bits").Eval(true),
fb.TitleFormat("$info(samplerate) hz").Eval()
]
tagNames = String(time_tags[counter]);
infoNames = String(info_tags[counter]);
labelNames = labels[counter];
xPosition = Number(allMargin[counter]);
gr.FillSolidRect(xPosition+5, wh - 30, 100, 20, RGBA(220,220,220,025));
gr.DrawRoundRect(xPosition+5, wh - 30, 100, 20, 4, 4, 1, g_selectcolor);
gr.FillGradRect(0,(wh / 2), ww, 2, 180, g_backcolor, (g_selectcolor + g_textcolor), focus = 0.5);
gr.GdiDrawText(labelNames, stat_font, (g_selectcolor + g_backcolor), xPosition+5, wh-75, 100, 30, DT_VCENTER| DT_CALCRECT | DT_CENTER);
if(fb.IsPlaying) {
gr.GdiDrawText(tagNames, time_font, g_textcolor_hl, xPosition+5, wh-58, 100, 30, DT_VCENTER| DT_CALCRECT | DT_CENTER);
gr.GdiDrawText(infoNames, stat_font, g_textcolor, xPosition+5, wh-35, 100, 30, DT_VCENTER| DT_CALCRECT | DT_CENTER);
gr.GdiDrawText(fb.TitleFormat("$if2(%TITLE%,'N/A')").Eval(), setTitlefont, g_textcolor, 0, 0, ww, wh, DT_WORDBREAK | DT_CALCRECT | DT_CENTER | DT_END_ELLIPSIS);
titleCount = gr.MeasureString(fb.TitleFormat("$if2(%TITLE%,'N/A')").Eval(), setTitlefont, 0, 0, ww, wh);
fb.trace(titleCount.Height);
gr.GdiDrawText(fb.TitleFormat("by: $if(%ARTIST%,%ARTIST%[' feat.'%ARTISTFEATURED%],'N/A')").Eval(), artist_font, g_textcolor_hl, 0, titleCount.Height+3, ww, wh, DT_WORDBREAK | DT_CALCRECT | DT_CENTER | DT_END_ELLIPSIS);
artistCount = gr.MeasureString(fb.TitleFormat("$if(%ARTIST%,%ARTIST%[' feat.'%ARTISTFEATURED%],'N/A')").Eval(), artist_font, 0, 0, ww, wh);
gr.GdiDrawText(fb.TitleFormat("On Album: $if(%ALBUM%,%ALBUM%$if(%RELEASE_DATE%,' ('%RELEASE_DATE%')',' ('%DATE%')'),'N/A')").Eval(), album_font, g_selectcolor, 0, (artistCount.Height + titleCount.Height + 5), ww, wh, DT_WORDBREAK | DT_CALCRECT | DT_CENTER | DT_END_ELLIPSIS);
}
}
}
function on_font_changed() {
get_font();
window.Repaint();
}
function on_colors_changed() {
get_colors();
window.Repaint();
}
function on_playback_stop(reason) {
if(reason != 2) window.Repaint();
}
function on_playback_new_track() {
window.Repaint();
}
function on_playback_time() {
window.RepaintRect(0, wh-60, 400, 25);
}
That's a WSH panel script from his DeviantArt page (http://br3tt.deviantart.com/art/JSPlaylist-509803158), right? I did give that try and had considered using it as an alternative. But since I last posted, I've confirmed that both jsplaylist and his smooth playlist prevent FB2K from completely shutting down in Windows 10. I had to delete panels 1 by 1 until I finally found the culprit. Wonder if your mod would be any different. Have you made it available for download anywhere?
I can't imagine why you'd have that issue with the original jsplaylist. The modifications I've made are very minor so are unlikely to change anything in that regard. It can be found via the link in my signature.
It works good for me. Is there a simple script line I could add to automatically attach the picture to all the files in the folder after downloading it?
No.
I edited the script so that it downloads it as "front.jpg" by default, but in order to see it in the panel I have to embed the picture first.
That would only happen if the file already has art embedded in it?? What gets displayed first depends on this setting:
File>Preferences>Advanced>Display>Album art>Embedded vs external.
or is there a way to just re-draw the section where time elapse and time remaining counts up and down?
I've not tried the script but it looks like you're already doing that with window.RepaintRect(x,y,w,h) ??
I can't imagine why you'd have that issue with the original jsplaylist. The modifications I've made are very minor so are unlikely to change anything in that regard. It can be found via the link in my signature.
I did some relatively extensive testing today marc. I found that if there is a panel with one of your jscripts in a very basic FB2K build that includes panels with either Br3tt's SP or your jsplaylist-mod (https://github.com/19379/jsplaylist-mod), FB2K will not fully shut down in Windows 10. I detailed the tests I did on SP in a reply to Br3tt on DA (http://br3tt.deviantart.com/art/JS-Smooth-Playlist-571375892).
Had the same problem with Br3tt's older wsh panel mod JSPlaylist (http://br3tt.deviantart.com/art/JSPlaylist-509803158).
Try a brand new portable install with no components except JScript panel. Add jsplaylist-mod as the only panel in the layout so it looks like the screenshot on my github page. Now play some music and see if foobar closes.
I'll try that later today marc. I'm pretty sure foobar will shut down fine. As I pointed out to Br3tt, it's only been when I have one of his scripts in a panel in foobar along with just 1 of 3 of your jscripts that Win10 that doesn't fully shut down: 'thumbs', 'now playing' & 'Last.fm Album Art Downloader'. Just 2 panels and nothing else. I don't think any of your other scripts cause the problem, but I'll test them
Edit: DA seems to be down at the moment.
Edit 2: jsplaylist-mod set up quickly. I didn't find the Github screenshot, but I used 'View > Layout > Enable layout mode editing' to clear what was there, add a jscript panel and pasted in jsplaylist-mod.
Added tracks played fine, and foobar shut down in Win10 fine.
I edited the script so that it downloads it as "front.jpg" by default, but in order to see it in the panel I have to embed the picture first.
That would only happen if the file already has art embedded in it?? What gets displayed first depends on this setting:
File>Preferences>Advanced>Display>Album art>Embedded vs external.
Of course, my foobar is set to display the embedded art first and that's exactly how I want it to be, it's not an issue. What I was asking for is if it is possible to preview the lastfm picture before I embed it or even download it, like the foo_uie_biography (https://hydrogenaud.io/index.php/topic,70955.0.html) component does. I would actually like the features of both the biography view component and your script. If I can remember correctly one of your WSH album art reader would show an online picture instead of the blank background.
If you want to preview images before downloading, I suggest using dedicated app like album art downloader. It has many more options and sources that are much better than the crap on last.fm.
https://hydrogenaud.io/index.php/topic,57392.0.html
Or you could just use my standard artwork panel right click option that launches google images in a browser with the artist/album as search terms.
Or you could just use my standard artwork panel right click option that launches google images in a browser with the artist/album as search terms.
That's what I've been doing with a run service script. Clicking your panel is a lot more convenient method to launch a browser search though. Kudos marc... it's brillant :)
If you want to preview images before downloading, I suggest using dedicated app like album art downloader. It has many more options and sources that are much better than the crap on last.fm.
https://hydrogenaud.io/index.php/topic,57392.0.html
I know that software, but I never found it really useful. I prefer a foobar component because it allows me to check the album art on the go, while I'm listening and eventually preview the new picture in the exact size and context it will actually look in the player once it is downloaded and embedded.
Anyway, I just found out the biography view component has an automatically download option which I never noticed until today!
Clicking your panel is a lot more convenient method to launch a browser search though. Kudos marc... it's brillant :)
I think google images is pretty much the best way to source art. It will usually have high quality art from amazon or the artist's own site/record label near the top of the search results and of course you can filter the image size. I then right click a playlist entry>open containing folder and drag the file straight from the browser in to explorer. Then with the file highlighted, press F2 to rename it. OK, it's a few manual steps but it's worth it.
I think google images is pretty much the best way to source art. It will usually have high quality art from amazon or the artist's own site/record label near the top of the search results and of course you can filter the image size. I then right click a playlist entry>open containing folder and drag the file straight from the browser in to explorer. Then with the file highlighted, press F2 to rename it. OK, it's a few manual steps but it's worth it.
Wow... drag and drop. Nice. I've been going a similar route, but I start with opening the track folder, copying the path, right-clicking the art panel and selecting google search. When I find the cover art I select 'View Image', right-click and select 'Save Image As', paste the path to the track's folder, save it, rename it. I like your method better marc. :)
Try a brand new portable install with no components except JScript panel. Add jsplaylist-mod as the only panel in the layout so it looks like the screenshot on my github page. Now play some music and see if foobar closes.
Well I learned how to set up foobar via "Enable Layout Editing Mode' in the default UI today instead of using columns UI as I have for years. I downloaded jsplaylist-mod from GitHub (https://github.com/19379/jsplaylist-mod), extracted the zip, renamed 'js-marc2003-master' to just 'js-marc2003 and copied it to the foobar root directory. In the default foobar installation I went to preferences > components and added foo_jscript_panel-v1.1.4.fb2k-component. Enabled layout editing and deleted the 2 existing sections of the layout, inserted just one JScript Panel. and copied the script from "jsplaylist main script.txt" to it Added tracks and played them. Stopped playback and shut down foobar. Foobar shut down in Win10 completely.
(http://oi63.tinypic.com/ib9ts5.jpg)
So I took it to the next step, and starting from scratch added marc's Now Playing JScript panel to what I'd just made. That 1st involved downloading the latest js-marc2003 scripts from GitHub (https://github.com/19379/js-marc2003/releases), and then extracting the contents of the zip to the \js_marc2003 folder in foobar. This time I configured a left / right (horizontal in Columns UI) splitter, added 2 JScript panel panels, and put the "now playing (basic).txt" script in one and "jsplaylist main script.txt" in the other. That got me this:
(http://oi63.tinypic.com/34fcx77.jpg)
Unfortunately after playing a few tracks, stopping, and then shutting down foobar, it remained in Windows 10's Task Manger and I had to end task in order to completely shut down foobar and restart it.
If that wasn't disconcerting enough, when I started it up again and began playback, on the 3rd or 4th track, I was presented with a whole new issue:
(http://oi63.tinypic.com/jgkumw.jpg)
http://xxxx.tinypic.com/xxxxxx.jpg
Ads... >:( They weren't displayed when I was previewing the post or when I was reviewing the message after submitting it. Am open to suggestions for an alternative ad-free image hosting site. imgur?
If that wasn't disconcerting enough, when I started it up again and began playback, on the 3rd or 4th track, I was presented with a whole new issue:
Here's the script's error message:
JScript Panel (np_basic by marc2003): Microsoft JScript runtime error:
Permission denied
File: C:\Foobar2000\js_marc2003\js\thumbs.js
Line: 526, Col: 6
<source text only available at compile time>
var url = item.src.replace("avatar170s", "ar0");
this.success = function (base) {
_(_.getElementsByTagName(this.xmlhttp.responsetext, "img"))
.filter({"className" : "image-list-image"})
.take(this.download_limit)
.forEach(function (item) {
var url = item.src.replace("avatar170s", "ar0");
var filename = base + url.substring(url.lastIndexOf("/") + 1) + ".jpg";
_.runCmd("cscript //nologo " + _.q(folders.home + "download.vbs") + " " + _.q(url) + " " + _.q(filename), false);
})
.value();
}
Can you run process explorer and see if anything is showing as "child" of foobar2000.exe? Also, right click foobar2000.exe>Properties>Threads tab and see if anything is using any CPU?
https://technet.microsoft.com/en-us/sysinternals/processexplorer.aspx
As for the script error, not had that before and I even tested using the same artist as you just now and it was fine. I guess you could try this...
this.success = function (base) {
_(_.getElementsByTagName(this.xmlhttp.responsetext, "img"))
.filter({"className" : "image-list-image"})
.take(this.download_limit)
.forEach(function (item) {
var src = item.src;
var url = src.replace("avatar170s", "ar0");
var filename = base + url.substring(url.lastIndexOf("/") + 1) + ".jpg";
_.runCmd("cscript //nologo " + _.q(folders.home + "download.vbs") + " " + _.q(url) + " " + _.q(filename), false);
})
.value();
}
Can you run process explorer and see if anything is showing as "child" of foobar2000.exe? Also, right click foobar2000.exe>Properties>Threads tab and see if anything is using any CPU?
I see nothing as a child:
(http://i.imgur.com/OQwGbTF.jpg)
There are a few threads using minimal CPU:
(http://i.imgur.com/GSqhKaD.jpgg)
Will try your code later on. Meanwhile Br3tt replied to my test results on DA (http://br3tt.deviantart.com/art/JS-Smooth-Playlist-571375892) and found my link between SP and your scripts to be interesting & something he'll look into.
Were those screenshots taken at a time you were unable to close foobar? I forgot to mention it but I thought it would be obvious....
edit: Just looked at DA and I don't understand this...
"During my tests today I did see a connection between SP and marc2003's jscripts. His Album Art Downloader panel will notice the thumbnail SP creates for mp3s lacking album tags"
IIRC, smooth playlist creates a cache of artwork inside the js_br3tt folder and my script uses the main foobar2000 preferences. Did you really configure your setup to look inside that folder?
edit2: jsplaylist-mod (and the original jsplaylist for WSH panel mod) don't use any external cached images and use the same main preferences as my scripts.
As for the script error, not had that before and I even tested using the same artist as you just now and it was fine. I guess you could try this...
More power with E Power ;) ...Sounds like a slogan for an alternative energy company.
No luck with the script modification. It may download thumbs for 1 or 2, or up to 8 or 10 successive tracks before it crashes. I've been having this problem with test builds on both Win7 PC and Win10 Notebook for the past month. To get a lot downloaded I left foobar with both NP and thumbs panels play overnight as background music while I was sleeping. The crash doesn't prevent the script from downloading the graphics. Wonder if it could be something in my MP3Tag tagged lame / dbpoweramp encoded files.
Were those screenshots taken at a time you were unable to close foobar? I forgot to mention it but I thought it would be obvious....
Thats what PE was displaying while foobar was running. I'm not all that quick. You might have intended for me to do the check after I'd closed foobar. That;d make more sense. I'll do it again.
IIRC, smooth playlist creates a cache of artwork inside the js_br3tt folder and my script uses the main foobar2000 preferences. Did you really configure your setup to look inside that folder?
No. Not at all. I think I set up everything the way both of you specify. His scripts in \js_br3tt and yours in \js_marc2003.
edit2: jsplaylist-mod (and the original jsplaylist for WSH panel mod) don't use any external cached images and use the same main preferences as my scripts.
As you pointed out, his scripts create thumnails in his \js_br3tt\cache\imgcache folder all randomly named with no extension... right? I have no idea how Last.fm Album Art Downloader picked up on that and displayed them in its panel. I tested it a couple times.
If you tried to close foobar and it wouldn't, it would still be running.... right?
I have no idea how Last.fm Album Art Downloader picked up on that and displayed them in its panel. I tested it a couple times.
It's fortunate that my album art panel has tooltips showing the path of being displayed so you can provide proof of this.
After shutting down foobar, Process Explorer shows no child or and it's the only thing in the threads tab this time showing no CPU usage at all
(http://i.imgur.com/MHI38aP.jpg)
(http://i.imgur.com/f2c7HYL.jpg)
After shutting down foobar
I'm done. I'm not wasting any more of my time on this.
If you tried to close foobar and it wouldn't, it would still be running.... right?
I just went back to my test build and can now explain what's happening. As I told Brett, his script looks for the 1st art file named %album%.jpg alphabetically a-z among several in a 'Various Tracks" folder where I have a lot of >very< old mp3s that lack any album tag. It then creates thumbs based on that 1 jpg for every single mp3 lacking that tag.
I just tested it again by removing all but 1 cover art jpg in that folder. I delete all cached files in Br3tt's and WSH folders: \js_br3tt\cache\imgcache and \wsh_settings and \wsh_data, and start this test foobar. SP instantly creates thumbs for every track missing the album tag from that one jpg. And Album Art Downloader is associating that one art jpg with every track that lacks the tag. So the 2 scripts aren't interacting. They're both just both producing similar results.
Sorry if this has been confusing marc. It's late here and I'm not as focused as I should be.
If you tried to close foobar and it wouldn't, it would still be running.... right?
It closes its GUI, but its exe remains active. I can't start foobar again unless I end task on it. If I start foobar again without ending task on the 1st copy, a 2nd foobar2000 will appear in task manager and I have to end task on both in order to start foobar again.
Today I finally remembered one of the primary rules of troubleshooting computer related problems, probably 2nd only to simply rebooting: Disable any antivirus program. It wasn't effecting Windows 7, but in Windows 10 for some reason was causing marc's Now Playing script to crash. That as well as keeping every copy of foobar that had both marc's and Br3tt's scripts set in JScript panels to remain in task manger after closing foobar, preventing it from restarting. My most sincere apologies to you marc for what I ended up putting you through the other day.
That solved 2 of the 3 issues I was having. But both marc's Album Art Downloader & Br3tt's Smooth Playlist scripts are still displaying the same cover art jpg for every mp3 in my 'Various Tracks' folder / playlist that doesn't have an album tag set. Here's what's I'm seeing in a copy of foobar with those panels. The 1st track has an album track, the next 4 don't:
(http://i.imgur.com/QYQviGo.gif)
Stupid here.
Is there any way of getting specific album image data (such as the color of a pixel, for instance?). I know this is possible with canvas, but I don't know about the internals of this plugin
I'm trying to make a method that will get the average color of an image. I want the walls to match the furniture, so to speak.
You can use GetColorScheme like this...
var img = utils.GetAlbumArtV2(fb.GetFocusItem(), 0);
if (img) {
var arr = img.GetColorScheme(1).toArray();
var col = arr[0];
}
You can increase the number 1 to get more colours. The first is the most dominant and so on...
Is there a way to make a value calculated in the script available to the whole program as a global variable or can it only be displayed in the panel where the script is written?
Nope, no global variables.
I've got a problem where I think JScript Panel might just be the thing that could solve it.
Current situation
I'm using m-TAGs in Foobar2000 to tag my files.
I'm also using KeyFinder to determine key values. But that is oblivious to the existence of m-TAG.
Which means I have media files that have been read by m-TAG to collect tag info and have gotten their tag info updated by an external soft.
Now, m-TAG only reads the media file tags upon creation of a tags file, after that it don't touch the media file no more for that.
now, if those m-TAG files hadn't already acquired additional information it would be just a case of wiping the .tags files and let m-TAG recreate them to pickup said changed/new information. Sadly that is not an option, order of processing is not fixed, plus I didn't start using KeyFinder from the beginning so a lot of files are already m-TAGged to which substantial tag info has been added since.
Still with me?
Scripting would be the only way I see to prevent me from having to manually extract the Key value from the media file and update the m-TAG reference.
Since both the m-TAG playlist entry and the actual media file playlist entry are an exact duplicate of each other, only differing on the changed/new added Key value, in my mind it should be a piece of cake if a scripting option existed that I could instruct like
"Ok, I've got these two identical entries except for tag now go out and find each m-TAG entry, match the duplicate entry that has the new tag and copy the content to the m-TAG entry"
I thought maybe masstagger had the solution but if it has I don't see how, it's basically the same as mp3tag's actions system which also has no way of doing this. Even if it did, it don't know about m-TAG either so that route is closed anyway.
Since JScript panel uses scripting like there is no tomorrow, I was hoping it could modify tag values too I've no clue about that, I'm not familiar enough with the component to know if it can change tags directly through scripting.
I'm not familiar with m-tags but from what I gather, you use the properties dialog to edit "tags" in the same way you do with normal files. If that it the case, simply add all the m-tags to one playlist and add all the real audio files to another. Then you can use this technique for copying tags from one set of files to another.
http://wiki.hydrogenaud.io/index.php?title=Foobar2000:How_to_transfer_tags_between_two_sets_of_tracks
I'm not familiar with m-tags but from what I gather, you use the properties dialog to edit "tags" in the same way you do with normal files. If that it the case, simply add all the m-tags to one playlist and add all the real audio files to another. Then you can use this technique for copying tags from one set of files to another.
http://wiki.hydrogenaud.io/index.php?title=Foobar2000:How_to_transfer_tags_between_two_sets_of_tracks
Damn, so simple....
[walks off silently with bowed head]
Thanks :)
EDIT: WOOT! Works like a charm, would'ave thunk?! LOL
Is anyone using jScript panel and marc's scripts on mac ox (via crossover or vine) ??
Some simple scripts works but not marc's scripts or
WilB's scripts :( No console massages are shown for
WilB's scripts and for marc's scripts,JScript Panel (Allmusic review by marc2003): Parsing file "C:\users\crossover\Application Data\foobar2000\js_marc2003\js\lodash.min.js"
[size=2]JScript Panel (Allmusic review by marc2003): Parsing file "C:\users\crossover\Application Data\foobar2000\js_marc2003\js\helpers.js"[/size]
[size=2]JScript Panel (Allmusic review by marc2003): Parsing file "C:\users\crossover\Application Data\foobar2000\js_marc2003\js\panel.js"[/size]
JScript Panel (Allmusic review by marc2003): Parsing file "C:\users\crossover\Application Data\foobar2000\js_marc2003\js\text.js"
You need IE8 installed in wine for the internet stuff to work. Also, search the WSH script thread for all references to winetricks because there are some other packages needed as well.
Is there a way to meta-test certain fields in the Properties script from the samples? In particular, play count, first played, and rating. Image below shows the fields in question. I'd like them to not show until they become populated if possible.
(http://i.imgur.com/PcfBHsD.png)
Marc, is it possible to have the Thumbs script point to a specific file in a folder and only that file instead of pointing it to a folder with multiple image files. I know there are other components I can use that do this but none of those have the crop functionality your thumbs script has, which is really handy for non square images,
Use the album art script - assuming you're not already using all of the available types?? Just configure the main preferences with the filename.
Is anyone using jScript panel and marc's scripts on mac ox (via crossover or vine) ??
Some simple scripts works but not marc's scripts or WilB's scripts :(
No console massages are shown for WilB's scripts
and for marc's scripts,
Yes, I'm using marc's JScript panel in foobar2000 under wine 1.6.2 in Linux (Ubuntu, Mint) and most everything I've tried works except downloading artist images in his thumbs script. You'll need to install these dll's using winetricks in this order (very important).
gdiplus_winxp
wsh57
fontsmooth=rgb
msscript
ie8
msls31
w_workaround_wine_bug-25648
msxml3
wmp10
vb6run
vcrun2010
I did try WilB's Library Tree script and it worked, but I didn't care much for it. So I went back to a WSH panel mod script I modified earlier for myself. marc's older WSH panel mod scripts also work well. Except for (wait for it...) thumbs artist art and love button. Thanks last.fm. A few of Falstaff's (br3tt) older WSH panel mod scripts work also.
Hope this helps. :)
Hey everyone!
Is it possible to check panel visibility state from WSH\Jscript? E.g. I have a few heavy panels that are not ever visible simultaneously, so if it's possible to analyze the state of the panel, then I can avoid all the useless art reloading\repainting and etc.
PS:
@marc2003 , what's your position on pull requests to https://github.com/19379/js-marc2003/tree/master/js?
A question about the allmusic review script. Why is it saving the json of the album review in the data folder even if no album review is found on allmusic? Is this intended behavior?
@TheQwertiest
First of all, you should find nothing happens in on_paint if the panel is hidden in tab. Also, there is window.IsVisible. Take this example bit of code
window.SetInterval(function () {
fb.trace("Timer: " + new Date());
window.Repaint();
}, 1000);
function on_paint(gr) {
fb.trace("paint: " + window.IsVisible);
}
When in a visible tab, the output is...
Timer: Sat Jun 11 18:27:51 UTC+0100 2016
paint: true
Timer: Sat Jun 11 18:27:52 UTC+0100 2016
paint: true
Timer: Sat Jun 11 18:27:53 UTC+0100 2016
paint: true
Timer: Sat Jun 11 18:27:54 UTC+0100 2016
paint: true
Now select another tab so the panel is hidden and you only get...
Timer: Sat Jun 11 18:28:06 UTC+0100 2016
Timer: Sat Jun 11 18:28:07 UTC+0100 2016
Timer: Sat Jun 11 18:28:08 UTC+0100 2016
Timer: Sat Jun 11 18:28:09 UTC+0100 2016
Timer: Sat Jun 11 18:28:10 UTC+0100 2016
Timer: Sat Jun 11 18:28:11 UTC+0100 2016
Timer: Sat Jun 11 18:28:12 UTC+0100 2016
Timer: Sat Jun 11 18:28:13 UTC+0100 2016
Timer: Sat Jun 11 18:28:14 UTC+0100 2016
Timer: Sat Jun 11 18:28:15 UTC+0100 2016
Timer: Sat Jun 11 18:28:16 UTC+0100 2016
Timer: Sat Jun 11 18:28:17 UTC+0100 2016
Timer: Sat Jun 11 18:28:18 UTC+0100 2016
You can also experiment by putting
fb.trace(window.IsVisible); inside the timer to see it change to false when hidden.
As for my repo, it's just my personal files that happen to be online so I'm unlikely to accept requests unless it's a bug fix for something I'm not aware of.
@jazzthieve, yes it's intentional. Having an empty file present prevents the script from looking up again too soon. It checks the age of the file is over 24 hours before making another request to their servers.
It is possible to go even further regarding timers in inactive panels. You can stop the timer when the panel is not visible. The easiest way is to use one-shot timers and restart them in on_paint. For example:
function timerCallback() {
fb.trace("Timer: " + new Date());
window.Repaint();
}
function on_paint(gr) {
fb.trace("on_paint: " + new Date() + " " + window.IsVisible);
window.SetTimeout(timerCallback, 1000);
}
window.SetTimeout(timerCallback, 1000);
If you need the timer to trigger at specific times, for example on a full second, you need to calculate the timeout in the on_paint function accordingly.
I've made some minor updates to a couple of my scripts:
https://github.com/19379/js-marc2003/releases
@ marc2003
I think I've found a small bug in your np_basic script. Line 38 (thumbs.mode = 5;) seems to override the saved property value for the thumbs mode. The symptom is that the thumbs setting is always reset to off whenever the script is started or foobar is started.
It's intentional. The "bug" is the thumbs menu being there when it really shouldn't be. Surely you must realise it looks like crap when you enable one of the options because the text is in the way. Thumbs should be left off.
edit: This updated version of thumbs.js properly hides the menu. Save it inside js_marc2003\js
https://raw.githubusercontent.com/19379/js-marc2003/master/js/thumbs.js
@marc2003 I've got a problem in some code that I've adapted from yours. I'm trying to enumerate through files in a folder and using the following code;
if (_.isFolder(folder)) {
var files = [];
var fl = fso.GetFolder(folder);
fb.trace("File Count", fl.files.count);
var en = new Enumerator(fl.files);
var i = 0;
for (; !en.atEnd(); en.moveNext())
i = i + 1;
fb.trace("i total", i);
}
What I see in the console output is;
File Count 48
i total 19
I think that both lines should give me the same output ie 48. What am I doing wrong?
Edit: After restarting foobar both values are the same. Curious!
Hello,
i would need help regarding Br3tt's / Falstaffs "JS Smooth Browser" [1]
it is similar to facets and has the ability to group library/playlist into an artists/albums with corresponding artist/cover pictures.
album grouping works fine, but when using artists it looks for an "artist.jpg" in the folder the audiofiles are located and uses that
for display. however i would like to use the artist pics that marcs script once scraped into this folder (%appdata%\foobar200\wsh_data\artists\%artist%\%artist%*.*)
i thought that the "tf_path_artist" property would set the path where to look for the artistart but it seems that does nothing.
even if i hardcode it to one specific file it won't display.
is anyone using his script and found out how to make that work?
i guess i have to modify the portion of the code where it loads the images (line ~270):
image_cache = function () {
this._cachelist = {};
this.hit = function (metadb, albumIndex) {
var img = this._cachelist[brw.groups[albumIndex].cachekey];
if (typeof(img) == "undefined" || img == null) { // if image not in cache, we load it asynchronously
//if(!isScrolling && !cScrollBar.timerID) { // and when no scrolling
if(ppt.enableDiskCache) {
brw.groups[albumIndex].crc = check_cache(metadb, albumIndex);
if(brw.groups[albumIndex].crc && brw.groups[albumIndex].load_requested == 0) {
// load img from cache
if(!timers.coverLoad) {
if(!isScrolling && !cScrollBar.timerID) {
timers.coverLoad = window.SetTimeout(function() {
try {
brw.groups[albumIndex].tid = load_image_from_cache(metadb, brw.groups[albumIndex].crc);
brw.groups[albumIndex].load_requested = 1;
}; catch(e) {};
timers.coverLoad && window.ClearTimeout(timers.coverLoad);
timers.coverLoad = false;
}, 5);
}; else {
timers.coverLoad = window.SetTimeout(function() {
try {
brw.groups[albumIndex].tid = load_image_from_cache(metadb, brw.groups[albumIndex].crc);
brw.groups[albumIndex].load_requested = 1;
}; catch(e) {};
timers.coverLoad && window.ClearTimeout(timers.coverLoad);
timers.coverLoad = false;
}, 20);
};
};
};
};
if(!ppt.enableDiskCache || !(ppt.enableDiskCache && brw.groups[albumIndex].crc && brw.groups[albumIndex].load_requested == 0)) {
if(brw.groups[albumIndex].load_requested == 0) {
// load img default method
if(!timers.coverLoad) {
timers.coverLoad = window.SetTimeout(function() {
if(ppt.albumArtId==5) { // genre
var arr = brw.groups[albumIndex].groupkey.split(" ^^ ");
try {
var genre_img = gdi.Image(images.path + "genres\\" + arr[0] + ".jpg");
} catch(e) {
var genre_img = gdi.Image(images.path + "genres\\" + "default.jpg");
};
brw.groups[albumIndex].cover_img = g_image_cache.getit(metadb, albumIndex, genre_img);
brw.repaint();
}; else {
this.albumArtId = ppt.albumArtId == 0 ? albumIndex + 5 : ppt.albumArtId;
utils.GetAlbumArtAsync(window.ID, metadb, this.albumArtId, true, false, false);
};
timers.coverLoad && window.ClearTimeout(timers.coverLoad);
timers.coverLoad = false;
}, (!isScrolling && !cScrollBar.timerID ? 5 : 20));
};
};
};
//};
};
return img;
};
and insert another exception like "if(ppt.albumArtId==5) { // genre" for genre.
i tried this:
first i added a new property called
tf_path_artist_source: fb.TitleFormat(window.GetProperty("_PROPERTY: Artist Images Folder (source)", fb.ProfilePath+"\\wsh_data\\artists\\$meta(album artist,0)\\")),
and added in the function "image_cache"
if(ppt.albumArtId==4) { // test for album art
try {
var artist_img = gdi.Image(ppt.tf_path_artist_source.EvalWithMetadb(metadb) + "test.jpg");
} catch(e) {
var artist_img = gdi.Image(ppt.tf_path_artist_source.EvalWithMetadb(metadb) + "test.jpg");
};
brw.groups[albumIndex].cover_img = g_image_cache.getit(metadb, albumIndex, artist_img);
brw.repaint();
};
so far so good, the test.jpg in the corresponding artist folder is being displayed, yay! however i have no idea how to do wildcard calls, because the files are called something like "artist_1235123.jpg" or "artist_123412.png".
I don't think that's trivial but there are already masks defined in the properties to look for *cover*.* front.* *.jpg and last *.* so i guess that's already implemented in some way, i just have no idea how to do this.
you probably laugh at me now, but i'm proud that i made it this far :D
any help is appreciated :) for now i have set the AlbumArtID for artist grouping to display the front cover, that's ok for me too, but it would be nice to have real artist pics displayed.
[1] http://br3tt.deviantart.com/art/JS-Smooth-Browser-571376160
I think you need to delete all the cached images that were generated after the script first ran. IIRC, the folder is inside js_br3tt,
marc2003, how do you feel about the possibility of adding a secondary/fallback titleformatting pattern in your scripts that pull album/artist art (presumably from last.fm), for cases when the primary pattern have failed to retrieve anything?
Would be useful in scenarios where artists have changed names multiple times, are simply known under two different names (like Japanese writing vs Latin letters) or really just whenever ALBUM ARTIST and ARTIST are different and one might retrieve useful information while the other would not. The last.fm database is not exactly consistent enough to commit to one style of formatting and it wouldn't be desired to do so either.
Also noticed you 'added library tracks only' support for the last.fm cover art downloader script (was a while ago, but only checked it now), thanks for that.
Previously someone asked for multiple artist support for collaborations etc and I said no because it would be a real PITA. Buf if it's for different variants of the same artist which can share the same folder, it could be doable.
Well, what I'm asking should be a lot more simple than that.
Run query with %artist%. If a match has been found, save cover art to $directory_path(%path%)\lastfm.jpg and stop.
Otherwise run another query with %album artist%. If a match has been found, save cover art to $directory_path(%path%)\lastfm.jpg and stop.
(If the identical filenames are a problem, the result of the second query can just always be saved as lastfm2.jpg instead.)
I didn't realise you were talking about the album art script. Modifying that should be easier.
About 'now playing (basic)', is it possible to change fallback font?
Samples updated: https://github.com/19379/js-marc2003/releases
michtar, what do you mean by "fallback"??
what do you mean by "fallback"??
The font that replaces regular font when it can't can't display certain characters or script can't recognize font at all (name).
Looks like this (it's draw.string but with GdiDrawText it's the same). Looks like Microsoft Sans Serif to me:
(http://i.cubeupload.com/iNSAWI.png)
http://i.cubeupload.com/iNSAWI.png
Well I don't know anything about that. Use something else to display the track title. It's not like there is a shortage of alternatives.
Of course, it was only a question. Thanks for scripts anyway.
I guessed it was the soundtrack for the Amelie movie so found the track title on wikipedia. It looks OK with all these different fonts??
(https://i.imgur.com/O4pWEdc.png)
The code for the above...
// ==PREPROCESSOR==
// @import "%fb2k_profile_path%js_marc2003\js\lodash.min.js"
// @import "%fb2k_profile_path%js_marc2003\js\helpers.js"
// ==/PREPROCESSOR==
var tag = "La valse d'Amélie";
var text_colour = _.RGB(192, 192, 192);
var font_names = ["Segoe UI", "Tahoma", "Microsoft Sans Serif", "Verdana", "Calibri", "Impact"];
var fonts = _.map(font_names, function (item) {
return _.gdiFont(item, 32);
});
function on_paint(gr) {
gr.FillSolidRect(0, 0, window.Width, window.Height, _.RGB(30, 30, 30));
_.forEach(fonts, function (item, i) {
gr.GdiDrawText(item.Name, item, text_colour, 5, 5 + (i * 45), window.Width - 10, 40, LEFT);
gr.GdiDrawText(tag, item, text_colour, 5, 5 + (i * 45), window.Width - 10, 40, RIGHT);
});
}
- Yes, it is clearly this particular font problem, no doubt about it at any stage. It cannot display certain characters (incl. national).
- I thought that fallback font option is included somewhere in scripts and you can change it, for example: if you put Ariol instead of Arial :) certain default font is displayed
- it's not - not a problem, must be some system setting(? or whatever),
- I thought that fallback font option is included somewhere in scripts and you can change it, for example: if you put Ariol instead of Arial :) certain default font is displayed
It looks like the gdi.Font function built in to the component handles that...
var font = gdi.Font("ariol", 12);
fb.trace(font.Name); // outputs "Microsoft Sans Serif"
Can anyone link a biography script that fetches the bio from Wikipedia?
Now that foo_uie_biography seems to have stopped working, I'm looking for something that (upon selection/playing) downloads artist art (from last.fm or where ever) and saves it to a predefined folder (if there isn't already one).
I think that the thumbs sample does almost what I want it to, however I have a couple of questions:
1. Is it possible to change the path the images get downloaded to as well as the way the images are named? I looked through the code and I suspect I found the lines I would have to change...but yeah, I can't code, so I stopped before breaking something...
2. In contrast to the biography viewer, thumbs seems rather slow with respect to fetching the images. Is there something I can do about this? By slow I mean 5 seconds instead of ~ 1.
3. Biography viewer somehow only downloaded square images...is this also possible with thumbs? For layout reasons I'd prefer the same ratio for all the pictures...
Thank you very much in advance!
1) No, I'm not providing help on how to change filenames. They must keep the ID from the source on last.fm to prevent them being downloaded again.
The album art preferences in foobar support wildcards so you can specify a path to the folder meaning any component like EsPlaylist/facets/etc can use the images...
D:\path\to\wsh_data\artists\%artist%\*.jpg
2) I have no way to detect when images are downloaded so the script runs on a timer checking the folder for changes every 3 seconds.
The script used to detect when an image had completed and refreshed itself but that prevented you from closing foobar while it was running so I had to remove that feature.
3) Use a square panel with one of the crop options enabled.
Basically, if you don't like how it works... don't use it.
Not quite what I was hoping for :)
Thanks anyway, keep up your great work!
Hi,
I noticed a weird thing with the LastFM biography JScript : quite often, informations about a specific artist disapear (the LastFM biography file for the artist is still on my HDD, but when I open this file using Notepad or a similar software, it’s blank. The biography text isn’t here anymore).
Each time, I have to delete the empty file stored on my HDD in order to be able to recover the artist biography… It’s quite disturbing. I noticed, most of the time, it happens with artists I listen very often (e.g : Pink Floyd)
It looks to me that, from time to time, LastFM biography script tries to update informations already stored on the dedicated local folder and, somehow, fail to do so.
So far, I assumed when LastFM biography script found a file with the artist biography stored in the local folder, it didn’t try to connect to LastFM site in order to update biography, but maybe I was wrong … Was I ?
If there is some kind of « automatic update » feature included in the script, is there a way to disable it ?
Thanks a lot for the help !
YOGAMAN
P.S. Obviously, english is not my mother tongue, so please, excuse my french ;-).
Hello !
I really enjoy your Jscript plugin. Thanks for the hard work.
I'm not a programmer, but through errors I've made many modifications to your basic examples in order to fit my needs.
Unfortunately, one thing I can't do no matter what.
I want to have toggle buttons - when I press a button it should stay pressed and activate an option. When I press it once more, it should deselect itself and deactivate that option.
I've tried modifying your example with Simple themed buttons, but with no success.
PS: Any work around would be OK for me if my requirement can't be done with this plugin.
Screenshot - Foobar - My buttons (https://snag.gy/dtuiJ1.jpg)
Here is the original script:
// vi:set ft=javascript ff=dos ts=4 sts=4 sw=4 et:
// ==PREPROCESSOR==
// @name "SimpleThemedButton"
// @author "T.P Wang"
// ==/PREPROCESSOR==
function RGB(r, g, b) {
return (0xff000000 | (r << 16) | (g << 8) | (b));
}
ButtonStates = {
normal: 0,
hover: 1,
down: 2,
hide: 3
}
var DT_TOP = 0x00000000;
var DT_CENTER = 0x00000001;
var DT_VCENTER = 0x00000004;
var DT_WORDBREAK = 0x00000010;
var DT_CALCRECT = 0x00000400;
var DT_NOPREFIX = 0x00000800;
var g_theme = window.CreateThemeManager("Button");
var g_font = gdi.Font("Tahoma", 12);
function SimpleButton(x, y, w, h, text, fonClick, state) {
this.state = state ? state : ButtonStates.normal;
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.text = text;
this.fonClick = fonClick;
this.containXY = function (x, y) {
return (this.x <= x) && (x <= this.x + this.w) && (this.y <= y) && (y <= this.y + this.h);
}
this.changeState = function (state) {
var old = this.state;
this.state = state;
return old;
}
this.draw = function (gr) {
if (this.state == ButtonStates.hide) return;
switch (this.state)
{
case ButtonStates.normal:
g_theme.SetPartAndStateId(1, 1);
break;
case ButtonStates.hover:
g_theme.SetPartAndStateId(1, 2);
break;
case ButtonStates.down:
g_theme.SetPartAndStateId(1, 3);
break;
case ButtonStates.hide:
return;
}
g_theme.DrawThemeBackground(gr, this.x, this.y, this.w, this.h);
gr.GdiDrawText(this.text, g_font, RGB(0,0,0), this.x, this.y, this.w, this.h, DT_CENTER| DT_VCENTER | DT_CALCRECT | DT_NOPREFIX);
}
this.onClick = function () {
this.fonClick && this.fonClick();
}
}
function drawAllButtons(gr) {
for (var i in $buttons) {
$buttons[i].draw(gr);
}
}
function chooseButton(x, y) {
for (var i in $buttons) {
if ($buttons[i].containXY(x, y) && $buttons[i].state != ButtonStates.hide) return $buttons[i];
}
return null;
}
$buttons = {
Console: new SimpleButton(5, 5, 80, 26, "Console", function () {
fb.ShowConsole();
}),
Configure: new SimpleButton(5, 40, 80, 26, "Configure", function () {
window.ShowConfigure();
})
}
var cur_btn = null;
var g_down = false;
// --- APPLICATION START
function on_paint(gr) {
drawAllButtons(gr);
}
function on_mouse_move(x, y) {
var old = cur_btn;
cur_btn = chooseButton(x, y);
if (old == cur_btn) {
if (g_down) return;
} else if (g_down && cur_btn && cur_btn.state != ButtonStates.down) {
cur_btn.changeState(ButtonStates.down);
window.Repaint();
return;
}
old && old.changeState(ButtonStates.normal);
cur_btn && cur_btn.changeState(ButtonStates.hover);
window.Repaint();
}
function on_mouse_leave() {
g_down = false;
if (cur_btn) {
cur_btn.changeState(ButtonStates.normal);
window.Repaint();
}
}
function on_mouse_lbtn_down(x, y) {
g_down = true;
if (cur_btn) {
cur_btn.changeState(ButtonStates.down);
window.Repaint();
}
}
function on_mouse_lbtn_up(x, y) {
g_down = false;
if (cur_btn) {
cur_btn.onClick();
cur_btn.changeState(ButtonStates.hover);
window.Repaint();
}
}
// --- APPLICATION END
Samples updated: https://github.com/19379/js-marc2003/releases
Hi Marc,
I noticed most of the jscripts you created are no longer stored on GitHub (error 404). Maybe you choose to remove them for some reason (in that case, I hope they'll be back soon because they're so helpfull. Thanks by the way !), but if the removal wasn't done on purpose, then there is a problem with GitHub.
can anyone post a working script that mimics the biography component/panel (artist and album)?
thx
Does someone have "foo_uie_wsh_panel.dll"?
It's not foo_uie_wsh_panel_mod.
Could you post please?
@necozy what for ? this dll is old and wsh panel mod (and now jscript panel) offer the same in better ...
thanx Falstaff
I got foo_uie_wsh_panel.dll already.Thank you for your trouble.
But I am looking for "foo_uie_trackinfo.dll" also not mod one
for some theme and skins this time.
I do not know the reason why "mod" does not work.
Those theme and skins are required original.
thank you
Finally I found "foo_uie_trackinfo.dll" .
thank you anyway.
cheers
Jesus different version!
I'd like use http://br3tt.deviantart.com/art/KUNG-FOO-foobar-config-96607000
So somebody post all dlls that are necessary please.
This thread is for jscript discussions. None of what you ask has anything to do with jscript and you should ask your questions in the relevant thread either existing or new. TOS #5 (https://hydrogenaud.io/index.php/topic,3974.html#post_tos5)
Perhaps a moderator could intervene?
jazzthieve and everyone
Very sorry if you know suitable thread notice me please.
thank you
Is it possible with jscript to hide or show a columns ui panel? In other words to trigger the panelshow command of panel stack splitter?
davideleo
thank you for reply.
I don't understand details for java script.
I just want to use "kung-foo_black_1.3a".
So I need foo_uie_trackinfo.dll for correct version for this.
I have visited many sites.
Link is still there but the file is not exist anymore.
Now a days, 8 years ago is really long long time ago.
I will wait and I am not in hurry.
thank you
The following scripts from my old samples are now bundled with the component itself:
albumart.txt
autoplaylists.txt
menu button.txt
playback buttons.txt
properties.txt
rating.txt
seekbar.txt
track info + seekbar + buttons.txt
volume.txt
Also included is jsplaylist-mod. When you right click the blank panel of the latest component, there is an "Open component folder" menu item which takes you directly to the folder containing all the docs and samples.
https://github.com/19379/foo-jscript-panel/releases
Apologies cause this is gonna be slightly off-topic, but not sure there's a better place for it.
Hey guys, I'm a longtime WSH/JPanel user. I love what it can do and I've built out pretty extensive themes with it. Here's the thing, it's not great for graphical stuff, especially if you want any kind of animation. Using setInterval for this sort of thing sucks. It's not predictable, it's processor intensive. Having to repaint portions of the screen is also dumb, and can be difficult to manage. JPanel has a ton of great drawing features, but frankly using GDI kinda sucks. It's 2016. Javascript wasn't designed for this kinda stuff.
You know what is designed for all this stuff? HTML. CSS. And Javascript works so much better with those than GDI bitmaps.
Wouldn't it be great if we had a plugin where we could display HTML and execute Jscript code too? Wouldn't it be so much better to create dom elements for text/images. Wanna rotate an image? Just use CSS: transform: rotate(7deg);. Wanna do a progressbar? No more messing with draw stuff in fast setInterval's. You could just do { transition: 1s; transition-timing-function: linear } along with a setInterval for 1000ms that just sets the element width and now you've got a beauitful, perfectly smooth progressbar. To see if a button or element was clicked on, just add a click handler to the DOM, no more checking x,y coords to see if the object you're interested in was clicked on.
Obviously you'd still need some of the JScript Panel interfaces to retrieve artwork/metadata and make it available to the HTML, but I think a lot of the other JScript interfaces/methods could be completely stripped out.
Has anybody looked into building something like this before? I feel like the WebBrowser control offers everything you need except for the JScript/Foobar connection already. My C++ is a little lacking (I'm a JS/WebDev), but I'd be happy to help out if someone got this project going.
Thoughts?
Wouldn't it be great if we had a plugin where we could display HTML and execute Jscript code too?
need some of the JScript Panel interfaces to retrieve artwork/metadata and make it available to the HTML
There is a component to meet your needs. It uses HTML/CSS and compatible WSH component interfaces. But because no one uses or writes scripts, the component is currently in a state of death/freeze. If you have plenty of time to explore/try to write script examples (just like WSH component contains examples), perhaps you can urge the author to continue to update the component.
There is a component to meet your needs. It uses HTML/CSS and compatible WSH component interfaces. But because no one uses or writes scripts, the component is currently in a state of death/freeze. If you have plenty of time to explore/try to write script examples (just like WSH component contains examples), perhaps you can urge the author to continue to update the component.
What's the component?
Just in case it's what you're referring to, foo_httpcontrol is not what I'm looking for. That obviously exists outside foobar (and I use it for certain cases like remote control of foobar), and it doesn't have a lot of the abilities/features that JScript/WSH already does.
What's the component?
Sciter UI (is different from DUI or CUI.)
Note: the component is unable to get foobar2000 's context menu and cover.
Installation:
1.foobar2000\components\foo_ui_sciter.dll
2.foobar2000\sciter32.dll
3.foobar2000\ui\default.htm (Create and write.)
4.sciter32.dll can be downloaded from here: (github.com/c-smile/sciter-sdk), while you can find some examples.
If you do not know please do not download and try it.
Upload a new version of SUI and an imperfect sample. Recommended to use with UiHacks components.
There is a component to meet your needs. It uses HTML/CSS and compatible WSH component interfaces. But because no one uses or writes scripts, the component is currently in a state of death/freeze.
Maybe an official component page and an own discussion thread would help. This component sounds very promising, but I never heard of it and I believe this is the only post in the forum where it is mentioned. Previous to this I only found this 2007 post (https://hydrogenaud.io/index.php/topic,54506.msg490163.html#msg490163) where stormgren says he would like to implement something similar, is he the developer?
There is a component to meet your needs. It uses HTML/CSS and compatible WSH component interfaces. But because no one uses or writes scripts, the component is currently in a state of death/freeze.
Maybe an official component page and an own discussion thread would help. This component sounds very promising, but I never heard of it and I believe this is the only post in the forum where it is mentioned. Previous to this I only found this 2007 post (https://hydrogenaud.io/index.php/topic,54506.msg490163.html#msg490163) where stormgren says he would like to implement something similar, is he the developer?
no, it is @ohyeah the developer.
I downloaded the latest version of jsplaylist-mod from github. When scrolling up and down, the playlist area overlaps the Information Panel and Header Toolbar.
Luckily that bug is only in master and is not part of the current component download.
Thanks for spotting.
Is it possible to have two separate Jscript panel instances in the toolbar?
can anyone post a working script that mimics the biography component/panel (artist and album)?
thx
Seconded. The Last.Fm Bio sample that was included with the plugin no longer works.
Is it possible to have two separate Jscript panel instances in the toolbar?
Yes. Hold
Shift when selecting it.
Yes. Hold Shift when selecting it.
Perfect, thanks!
What's the component?
Sciter UI (is different from DUI or CUI.)
Note: the component is unable to get foobar2000 's context menu and cover.
Installation:
1.foobar2000\components\foo_ui_sciter.dll
2.foobar2000\sciter32.dll
3.foobar2000\ui\default.htm (Create and write.)
4.sciter32.dll can be downloaded from here: (github.com/c-smile/sciter-sdk), while you can find some examples.
If you do not know please do not download and try it.
@ohyeah Thanks for sharing.
One question.
Is it possible instead of a complete UI replacement for this component to be compiled to be used with DUI or CUI as a panel?
I like the possibilities after trying it out , but I don't like the limitation not to be able to be used in conjunction with other panels.
Currently using dockable or pop-up panels as a workaround .
Is it possible instead of a complete UI replacement for this component to be compiled to be used with DUI or CUI as a panel?
ohyeah had ideas as you say, but now either the new UI or new components are stopped. Due to pressure of work, the current spare time is mainly used to maintain the ESLyric components.
I will ur..ge.. him to develop.
I like the possibilities after trying it out , but I don't like the limitation not to be able to be used in conjunction with other panels.
Currently using dockable or pop-up panels as a workaround .
How? I have both sciter UI and popup panels installed, but in the popup panels context menu I can't see a sciter panel option.
What's the component?
Sciter UI (is different from DUI or CUI.)
Note: the component is unable to get foobar2000 's context menu and cover.
Installation:
1.foobar2000\components\foo_ui_sciter.dll
2.foobar2000\sciter32.dll
3.foobar2000\ui\default.htm (Create and write.)
4.sciter32.dll can be downloaded from here: (github.com/c-smile/sciter-sdk), while you can find some examples.
If you do not know please do not download and try it.
@ohyeah
Thanks for sharing.
One question.
Is it possible instead of a complete UI replacement for this component to be compiled to be used with DUI or CUI as a panel?
I like the possibilities after trying it out , but I don't like the limitation not to be able to be used in conjunction with other panels.
Currently using dockable or pop-up panels as a workaround .
Both using sciter as child window and using DUI/CUI panels in Sciter UI are possible, but I have not try yet.............
Is there a way to mimic this PSS code in something like the 'track info + buttons + seekbar sample'? Not sure if context menu items can be used in that script.
$textbutton(,,,,,,)
$imagebutton($sub(%_width%,23),$sub(%_height%,32),24,24,$get(button)\gray.png,$get(button)\red.png,CONTEXT:'Slow Tagger/Toggle love tag')
https://github.com/19379/foo-jscript-panel/blob/e93048c9bbd1dcbb2e38a8b38229dc46b3fd7841/component/docs/Interfaces.txt#L225L234
Thanks. I was looking in the wrong place (callbacks).
What's the component?
Sciter UI (is different from DUI or CUI.)
Note: the component is unable to get foobar2000 's context menu and cover.
Installation:
1.foobar2000\components\foo_ui_sciter.dll
2.foobar2000\sciter32.dll
3.foobar2000\ui\default.htm (Create and write.)
4.sciter32.dll can be downloaded from here: (github.com/c-smile/sciter-sdk), while you can find some examples.
If you do not know please do not download and try it.
@ohyeah
Thanks for sharing.
One question.
Is it possible instead of a complete UI replacement for this component to be compiled to be used with DUI or CUI as a panel?
I like the possibilities after trying it out , but I don't like the limitation not to be able to be used in conjunction with other panels.
Currently using dockable or pop-up panels as a workaround .
Both using sciter as child window and using DUI/CUI panels in Sciter UI are possible, but I have not try yet.............
So I believe you will try. :D
Is there any way to "convert" textstrings to "normal script"?
I use the Properties window for creating custom buttons. The "user" only needs to write the command here and needs to select between different "command styles":
0 = main menu command (the command will be executed as fb.RunMainMenuCommand(string))
1 = context menu command (the command will be executed as fb.RunContextCommandWithMetadb(string, fb.GetSelections(), 8 ))
2 = scripted command
But with the latter i have a problem since the properties window only transfers the input text as textstring.
For example:
var abc = 1 + 2 + 3; var def = 4 + 5 + 6;fb.ShowPopupMessage( abc + def);
becomes:
"var abc = 1 + 2 + 3; var def = 4 + 5 + 6;fb.ShowPopupMessage( abc + def);"
For the moment i use this:
var str_arr = string.split(";"),
for (var i in str_arr) eval("(" + str_arr[i] + ")");
to convert the textstring to "script".
It works but not at all... so it seems to not being possible to "create" local variables (e.g. var abc = "blablabla") here.
Also the try/catch method doesn't works... (okay... the window is really small for this purposes ;) ... but i don't want to force the users to scamp my scripts :D)
Has anyone a better idea how to convert textstrings to "script"?
EDIT: Or at least an idea how i get local variables and try/catch and maybe others i haven't tested so far to work with my method?
I don't know why you're splitting the string at ; just eval the whole thing. It seems to work here.
var a = window.GetProperty("a", "test");
function on_mouse_lbtn_dblclk() {
try {
eval(a);
} catch(e) {
fb.trace(e);
}
}
Use the properties window to add your code...
var abc = 1 + 2 + 3; var def = 4 + 5 + 6;fb.ShowPopupMessage( abc + def);
Double click the panel and it pops up 21.
Hmm... works for me too, but not in my script.
I send the string to a function called "AddBtnCmd()" and call this in the button.
This works for main menu and context menu, but not for the "scripted commands"...
Could you take a look at my whole script?
Maybe i made a really big mistake in it... and haven't found it so far...
(Haven't scripted for a long time... and maybe i think too complicated...)
http://pastebin.com/nv8bvkv7
It is a big script now... because i have inserted all preprocessors to get it working in every JScript panel (without the images of course).
There must be a big issue in it, because it doesn't works here... and i need to split the command at all with my script or i get an error...
From line 250 i create the function that creates the window.GetProperty() and the AddBtnCmd().
From line 372 the panel script is written (this should be the parts where my issue must have been).
(the this.funcOption comes from the TextButton the AddBtnCmd will work as command).
This works fine, I simply replaced your string split code with my try/catch??
function AddBtnCmd() {
var str = this.funcOption.CmdString;
this.funcOption.CmdStyle == 0 && fb.RunMainMenuCommand(str);
this.funcOption.CmdStyle == 1 && fb.RunContextCommandWithMetadb(str, fb.GetSelections(), 8);
if (this.funcOption.CmdStyle == 2) {
try {
eval(str);
} catch (e) {
fb.trace("Custom button error: " + e);
}
}
}
I'd write it like this but it's purely cosmetic and doesn't change anything...
function AddBtnCmd() {
switch (this.funcOption.CmdStyle) {
case 0:
fb.RunMainMenuCommand(this.funcOption.CmdString);
break;
case 1:
fb.RunContextCommandWithMetadb(this.funcOption.CmdString, fb.GetSelections(), 8);
break;
case 2:
try {
eval(this.funcOption.CmdString);
} catch (e) {
fb.trace("Custom button error: " + e);
}
break;
}
}
:o
That's odd... so easy? :D
I'm confused... and it really works!
Big thanks!!!
I hope you haven't found another big issue in my script...
This makes me wonder if its possible to determine if a command is executed as fb.RunMainMenuCommand, fb.RunContextMenuCommandWithMetadb or eval().
So i could implement an automatic switch and not have to force the user to enter a number for the switch manually (when the entry is executed with one of the commands on first click i could set the property with window.SetProperty() automatically and on every next click it will again executed with the command thats binded to this property).
Any ideas?
EDIT: Nevermind. Found it out :)
Damn... doesn't works as expected...
I made a quick test to determine the kind of command and set the panel property with this:
var test = window.GetProperty("command style", 0);
var command = window.GetProperty("command", "");
function on_mouse_lbtn_up () {
fb.RunMainMenuCommand(command) && window.SetProperty("command style", 1);
fb.RunContextCommandWithMetadb(command, fb.GetSelections(), 8) && window.SetProperty("command style", 2);
try {
eval(command) && window.SetProperty("command style", 3);
} catch(e) {
fb.ShowPopupMessage("Optional button: " + e + "\n\nPlease correct your command string!")
}
fb.trace(window.GetProperty("command style");
}
Works for the both fb.Run... commands, but not for eval().
The command will be executed (when its a correct command) but the property will not be set.
Where is my logical flaw?
Obviously eval is not returning true/false like the fb.Run... commands. What made you think it does that?
Also, I wouldn't even bother trying to determine the "style". I'd just do it on the fly each time.
function on_mouse_lbtn_up(x, y) {
if (fb.RunMainMenuCommand(command)) {
return;
} else if (fb.RunContextCommandWithMetadb(command, fb.GetSelections(), 8)) {
return;
} else {
try {
eval(command);
} catch(e) {
fb.ShowPopupMessage("Optional button: " + e + "\n\nPlease correct your command string!")
}
}
}
Obviously eval is not returning true/false like the fb.Run... commands. What made you think it does that?
I hoped it... :D
I ended up with exactly the same idea to not determine the style in the meantime.
And nearly exactly the same code as yours ;)
Because i realised that the button may stop working if the command will be changed and the previous command was binded to a "style"... that would force the user to change the style manually again...
But thanks again for your quick reply :)
I may have asked this before, but is there a non-filthy way to pull this PSS script off with a jscript variant?
$if($isvisible_c(H1),
$imagebutton($sub(%_width%,26),$sub(%_height%,35),30,30,$get(button)\ex2.png,$get(button)\ex2h.png,PANELSHOW:H1:0;REFRESH,,),
$imagebutton($sub(%_width%,26),$sub(%_height%,35),30,30,$get(button)\ex1.png,$get(button)\ex1h.png,PANELSHOW:H1:1;REFRESH,,))
I know this (https://hydrogenaud.io/index.php?topic=63984.msg912994#msg912994) configuration uses wsh scripting to trigger panel changes. However, it doesn't seem to be be able to toggle visibility of a single panel and is pretty specific to that setup.
Why?
If you want to replace PSS completely its not possible at all...
If you only want a button, why don't stick with PSS?
But if its really needed to create the button in JScript panel it is possible like its done in the config you linked to.
But be aware of that JScript panel will not be able to determine if a panel is visible or not!
And you have to refresh the PSS to take effect immediately (otherweise the panel switch would take effect only on track change).
I'd do it like this (please replace <PATH> with your path to the file!):
(Code for JScript panel)
var fso = new ActiveXObject("Scripting.FileSystemObject");
var PANELoff = <PATH> + "H1_0";
var PANELon = <PATH> + "H1_1";
fso.FileExists(PANELoff) || fso.FileExists(PANELon) ? null : fso.CreateTextFile(PANELoff, true);
function PanelSwitch() {
fso.FileExists(PANELoff) ? fso.MoveFile(PANELoff, PANELon) : fso.MoveFile(PANELon, PANELoff);
if (fb.IsPlaying || fb.IsPaused) {
fb.PlayOrPause();
fb.PlayOrPause();
} else {
fb.Play();
fb.Stop();
}
}
Call the function as command for your button simply as
PanelSwitch.
In PSS you will have to enter this lines (as replacement for your button):
$init_ps_global(panel.toggle,0)
$set_ps_global(panel.toggle,$right($findfile(<PATH>H1_*),1))
$showpanel_c(H1,%panel.toggle%)
If i haven't made a mistake this should work (but haven't tested it yet... have written it from scratch now...)
if you wish to switch panels using jscript I would like to introduce you shutter by jensen and dreamxis whitch doesnot use pss script at all.
Switching panels from JScript panel without PSS?
Is there a JScript Splitter i've never heard of?
Would be great... so i could finally dispose the old PSS...
Switching panels from JScript panel without PSS?
Is there a JScript Splitter i've never heard of?
Would be great... so i could finally dispose the old PSS...
pss component is still needed.
(another panel stack component is mega panel splitter but the author afk long time ago.)
Why?
If you want to replace PSS completely its not possible at all...
If you only want a button, why don't stick with PSS?
I do not want to replace PSS. I want to trigger a hidden panel. The reason is pretty simple really. To do this you need to have the parent splitter exposed
somewhere in your configuration to be able to use a button of some sort to trigger action.
While maybe not practical currently, I'd like to just have a button drawn on my JScript control bar. This would eliminate the need to do UI gymnastics (placement issues) of leaving some part of the parent splitter exposed to get at that trigger.
Anyway, I managed to get the script to not crash the panel but the actual command to trigger the action is eluding me. I've tried looking at all examples in the interfaces that may be relevant but no luck.
@marc2003 : Hey again, do you know if there is any difference (performance-wise) between using pseudo-transparency in Jscript panel and plain old gr.FillSolidRect in the said Jscript panel? I.e. using background color with pseudo-transparency vs painting my own background.
Thanks in advance =)
PS: Uhm, could you please check my PR on JScript? Or is it only PRs with bugfixes that are acceptable?
I do not want to replace PSS. I want to trigger a hidden panel. The reason is pretty simple really. To do this you need to have the parent splitter exposed somewhere in your configuration to be able to use a button of some sort to trigger action.
While maybe not practical currently, I'd like to just have a button drawn on my JScript control bar. This would eliminate the need to do UI gymnastics (placement issues) of leaving some part of the parent splitter exposed to get at that trigger.
Anyway, I managed to get the script to not crash the panel but the actual command to trigger the action is eluding me. I've tried looking at all examples in the interfaces that may be relevant but no luck.
Do you mean something like this? (.gif under spoiler) (right-click is handled via JScript, Spectrum is a PSS panel)
(https://i.imgur.com/SVohIhp.gif)
@marc2003 : it seems that you are ignoring me, but hey, no hard feelings =). Anyways, I think I might've found a bug, when using arrays with your latest
helpers.js, caused by
Array.prototype.srt. Here is an example that illustrates the bug:
Script:
// ==PREPROCESSOR==
// @name "Test Script"
// @import "%fb2k_component_path%samples\complete\js\lodash.min.js"
// @import "%fb2k_component_path%samples\complete\js\helpers.js"
// ==/PREPROCESSOR==
var my_array = ["a", "b", "c"];
for (var i in my_array){
fb.trace("my_array: ", i);
}
Result:
my_array: 0
my_array: 1
my_array: 2
my_array: srt
PS: Yay for the triple-post!
Do you mean something like this? (.gif under spoiler) (right-click is handled via JScript, Spectrum is a PSS panel)
Indeed. Although I'd probably opt for a button instead of the r-click. Did you alter cattrox for that?
Indeed. Although I'd probably opt for a button instead of the r-click. Did you alter cattrox for that?
Well, my version of CaTRoX had been mostly rewritten: replaced WSH with JScript, integrated marc2003's helpers, refactored code, optimizations, new features and etc. Music spectrum toggle is one of those additions.
The idea behind this is the usual PSS switch via file communication (and the only way to communicate between script from PSS panel and JScript AFAIK): you use some file to store a variable, which you can change from JScript. On every such change you execute Play and Pause from JScript. This triggers PSS PerTrack script, in which you can change panel's positions and\or size.
If you need, I can post a source code with an example later. Or if you want to figure it out yourself, you can Google "PSS Switch" =)
if you wish to switch panels using jscript I would like to introduce you shutter by jensen and dreamxis whitch doesnot use pss script at all.
WSH-splitter is used in the Shutter. A gif:
WSH-splitter is used in the Shutter.
I've tried searching for Shutter and WSH-splitter, but could not find anything. Do you by chance have a link to either of them?
[EDIT]: Nvm, found it on some chinese site. Wow, that is a lot of hacks in a single script =) Thanks for pointing it out ;)
Shutter
—— by Jensen (coding) & dReamxis (design)
(http://imgur.com/a/T7Tc1)
(http://imgur.com/a/xzdgA)
>FB_Shutter_v1.1_U(Original version): based on wsh panel mod v1.5.6 & foo_ui_hacks.dll+dsound.dll+AutoItX3.dll+dynwrapx.dll
>FB_Shutter_v1.1_U+(Modified a little, may have bugs): based on wsh panel mod plus v1.5.7.4, without foo_ui_hacks.dll+dsound.dll+AutoItX3.dll+dynwrapx.dll. Replace WSH Lyric with ESLyric. Replace Albumlist with Library Tree.
>ShutterIcon: specifically designed for the shutter.
>Wsh-splitter_by_jensen(Original version): based on wsh panel mod v1.5.6 & foo_ui_hacks.dll+dsound.dll+AutoItX3.dll+dynwrapx.dll. Use Chinese to write the interface description. Looking for a good translator.
Download! (https://1drv.ms/f/s!AnFvs7Iqm0IrgdsqnuVrUBRi3tAZAQ)
Anyways, I think I might've found a bug, when using arrays with your latest helpers.js, caused by Array.prototype.srt.
Yes, it's a side effect of me messing around with the prototype. But I'll be keeping it as it has no effect on my own scripts.
Lots of workarounds...
#1
var my_array = ["a", "b", "c"];
for (var i in my_array){
if (my_array.hasOwnProperty(i))
fb.trace("my_array: ", i);
}
#2
var my_array = ["a", "b", "c"];
for (var i = 0; i < my_array.length; i++){
fb.trace("my_array: ", i);
}
#3
var my_array = ["a", "b", "c"];
_.forEach(my_array, function (item, i) {
fb.trace("my_array: ", i);
});
_.forEach is a lodash function documented here... https://lodash.com/docs/3.10.1#forEach
#4
// ==PREPROCESSOR==
// @name "Test Script"
// @import "%fb2k_profile_path%your_scripts\your_helpers.js"
// ==/PREPROCESSOR==
Yes, it's a side effect of me messing around with the prototype. But I'll be keeping it as it has no effect on my own scripts.
Thanks for the suggestions!
I've googled a bit and it seems that using "for var in" is considered a bad practice in JavaScript
precisely because of things like that (properties and methods appearing while looping)... Additionally, "for var in" is worse performance-wise than classical "for; ;" loop and _.forEach loop. I.e. no reason at all for using "for var in" =)
Shutter
—— by Jensen (coding) & dReamxis (design)
Thanks for the wsh_splitter tip! Incorporated needed functions in JScript from WSH-Plus and now panel toggles are much more manageable! And I can resize everything without editing every var manually =)
Though now I will have to recompile JScript every release, because of these hacks -_-""
Wohoo! list.js got back it's last.fm and musicbrainz support!
@marc2003: was it intentional? =)
Does anyone know, how to get filename of the .js from .js itself?
Well there are no .txt files to support the changes to list.js so I have no idea what you're talking about. :P
I don't understand your last post or what you're trying to do.
Well there are no .txt files to support the changes to list.js so I have no idea what you're talking about. :P
That is unless I don't have your old scripts saved =)
I don't understand your last post or what you're trying to do.
Here is what I'm trying to do.
Let's say I have
my_script.js:
function Func()
{
fb.trace("script name is ", GetMyName() );
}
function GetMyName()
{
/* magic here */
}
The result output of
Func() should be "script name is my_script.js"
So I was wondering if it is possible to make such
GetMyName() function (googling didn't help).
If you have the old .txt files then you more than likely have the old .js files. :/
As for your script name thing, it's beyond nonsensical. It serves no purpose. Type it in manually if you must.
edit: you must realise each preprocessor must contain functions that have unique names for the them to work properly. If you define the same function multiple times with the same name, only the last instance will ever get called.
If you have the old .txt files then you more than likely have the old .js files. :/
Yeah, but now it went from "unsupported legacy" script to "supported up-to-date" script. I.e. bug-fixes and all =)
As for your script name thing, it's beyond nonsensical. It serves no purpose. Type it in manually if you must.
Well, there is at least some value in my usage scenario: since I'm fiddling a lot with scripts, I have "Edit this script" menu item in every panel, which opens the required script file in the editor (e.g. _.run("notepad++.exe " + pathToScriptFolder + "Panel_MainScript.js") ). And if there was a way to get a script name, I could use the same code everywhere, without editing it manually.
edit: you must realise each preprocessor must contain functions that have unique names for the them to work properly. If you define the same function multiple times with the same name, only the last instance will ever get called.
Yes, of course. As far as I understand, @import is somewhat like #include, so unique name for every globally accessible function/var is a must.
I still don't get it. If you have a single preprocessor file then you'd use a variable containing the file name inside the .js file itself.
var script_name = "helpers.js";
Getting the filename dynamically isn't doing anything for you. If you're constantly renaming your file... then stop being a doofus.
If you have multiple preprocessor files, I'd do one of 2 things.
a) Get all .js files in a given folder in to an array and have a custom menu that lists them all. Use utils.glob or if using my helpers.js, there is my _.getFiles function
var scripts = _.getFiles(path_to_folder, "js"); // if you want to get more than one file type, separate each one with | like "txt|log"
b) Always import a given file first and initialise a new array inside that .js file..
var scripts = ["my_script.js"];
Then in any subsequent files, add this code
scripts.push("my_script2.js");
Now build a custom menu and it will only contain menu items for the specific files used by the current script.
If you're constantly renaming your file... then stop being a doofus.
I probably
should stop...
Now build a custom menu and it will only contain menu items for the specific files used by the current script.
Now that's a neat idea! Not sure how to implement it in my existing code yet, but I do like the concept!
Sorry for disturbing back again...
If GdiDrawText is called in gdi.CreateImage(), is it impossible to avoid the black edge, even if having filled a solid background behind that?
(http://i.imgur.com/iv7FrYw.png)
The highlighted "Oh Nana" was drawn in an image created, with the pink background just behind it in the same image, while the "(2016)" was drawn directly in on_paint() callback.
I know that drawstring() could solve this problem, but I just do not like its look, and wonder if there is a way to perfectly use GDI.
Thanks for any help or hints...
By the way, my reason to use temp images, is to make some scrolling effect. Like this:
(http://i.imgur.com/zHyTIwP.png)
This seems to work??
// ==PREPROCESSOR==
// @import "%fb2k_component_path%samples\complete\js\lodash.min.js"
// @import "%fb2k_component_path%samples\complete\js\helpers.js"
// ==/PREPROCESSOR==
var font = _.gdiFont("Segoe UI", 16, 1);
var white = _.RGB(255, 255, 255);
var black = _.RGB(0, 0, 0);
var x = 0;
var img = gdi.CreateImage(100, 30);
var gb = img.GetGraphics();
gb.gdiDrawText("JScript", font, white, 0, 0, 100, 30, CENTRE); //using my own CENTRE flag, normally you'd combine your own DT_XXX
img.ReleaseGraphics(gb);
function on_paint(gr) {
gr.FillSolidRect(0, 0, window.Width, window.Height, black);
gr.DrawImage(img, x, 0, 100, 30, 0, 0, 100, 30);
}
window.SetInterval(function () {
if (x < window.Width - 100) {
x++;
window.Repaint();
}
}, 10);
This seems to work??
// ==PREPROCESSOR==
// @import "%fb2k_component_path%samples\complete\js\lodash.min.js"
// @import "%fb2k_component_path%samples\complete\js\helpers.js"
// ==/PREPROCESSOR==
var font = _.gdiFont("Segoe UI", 16, 1);
var white = _.RGB(255, 255, 255);
var black = _.RGB(0, 0, 0);
var x = 0;
var img = gdi.CreateImage(100, 30);
var gb = img.GetGraphics();
gb.gdiDrawText("JScript", font, white, 0, 0, 100, 30, CENTRE)
img.ReleaseGraphics(gb);
function on_paint(gr) {
gr.FillSolidRect(0, 0, window.Width, window.Height, black);
gr.DrawImage(img, x, 0, 100, 30, 0, 0, 100, 30);
}
window.SetInterval(function () {
if (x < window.Width - 100) {
x++;
window.Repaint();
}
}, 10);
It doesn't. The black edge is unsurprisingly hard to recognize when the background is also black... And if the background is red, it looks like this:
(http://i.imgur.com/KJZDYSs.png)
Just change "var black = _.RGB(0, 0, 0);" to any brighter color, and you'll notice the difference......
It's frustrating to see a... feature? bug? like this. I guess it's Windows's fault. Now I have to use some dirty hacks, such as caching the pseudo-transparent background and use it to overlay the hidden parts. I feel sorry of my CPU for the extra process to do...
Well I used black because I thought your 2nd image was your desired end result!
I very much doubt I'll be able to do anything but I'll have a look.
Forgot to say, even if adding "gb.FillSolidRect(0, 0, 100, 30, black);" in the temp image part, the problem remains the same.
// ==PREPROCESSOR==
// @import "%fb2k_component_path%samples\complete\js\lodash.min.js"
// @import "%fb2k_component_path%samples\complete\js\helpers.js"
// ==/PREPROCESSOR==
var font = _.gdiFont("Segoe UI", 16, 1);
var white = _.RGB(255, 255, 255);
var black = _.RGB(200, 0, 0);
var x = 0;
var img = gdi.CreateImage(100, 30);
var gb = img.GetGraphics();
gb.FillSolidRect(0, 0, 100, 30, black);
gb.gdiDrawText("JScript", font, white, 0, 0, 100, 30, CENTRE)
img.ReleaseGraphics(gb);
function on_paint(gr) {
gr.FillSolidRect(0, 0, window.Width, window.Height, black);
gr.DrawImage(img, x, 0, 100, 30, 0, 0, 100, 30);
}
window.SetInterval(function () {
if (x < window.Width - 100) {
x++;
window.Repaint();
}
}, 10);
Well I used black because I thought your 2nd image was your desired end result!
I very much doubt I'll be able to do anything but I'll have a look.
Sorry for the confusion. The second image is "what it looks if left alone", and if the mouse hovers on the text, it should have a grey background to highlight itself. In the first image I used pink to have a trial...
And the background in the second image is not "black"... It's 20-20-20, and you can recognize the 0-0-0 black edge if looking carefully.
Interestingly, it seems that, when selection is changed, if you have Window.Repaint() inside on_playlist_items_selection_change, on_paint method won't be called, not until on_item_focus_change is called :\
This works for me without an on_item_focus_change function.
var path = fb.GetFocusItem() ? fb.GetFocusItem().Path : "<nothing selected>";
var font = gdi.Font("Segoe UI", 12);
function on_playlist_items_selection_change() {
path = fb.GetFocusItem() ? fb.GetFocusItem().Path : "<nothing selected>";
window.Repaint();
}
function on_paint(gr) {
gr.GdiDrawText(path, font, 0, 0, 0, window.Width, window.Height, 0);
}
I also added an empty one and it works the same.
This works for me without an on_item_focus_change function.
What I meant is a little different. Here is an example:
var path = fb.GetFocusItem() ? fb.GetFocusItem().Path : "<nothing selected>";
var font = gdi.Font("Segoe UI", 12);
function on_playlist_items_selection_change() {
fb.trace("on_playlist_items_selection_change");
path = fb.GetFocusItem().Path;
window.Repaint();
}
function on_item_focus_change()
{
fb.trace("on_item_focus_change");
window.Repaint();
}
function on_paint(gr) {
fb.trace("on_paint");
gr.GdiDrawText(path, font, 0, 0, 0, window.Width, window.Height, 0);
}
Trace log when focus is changed:
on_playlist_items_selection_change
on_playlist_items_selection_change
on_item_focus_change
on_paint
on_paint was called only once instead of thrice. It might be an optimization feature, but it's not very intuitive and I could not find any mention about it in docs =)
[EDIT]: Do you know the difference between
on_playlist_items_selection_change and
on_selection_changed? What I gathered from docs is that
on_selection_changed might not always work, but then why use it at all instead of always using
on_playlist_items_selection_change?
Yes, it looks like if you call window.Repaint in rapid succession, it doesn't process. This timer is using 2ms whereas I suspect those callbacks were happening much closer together.
var x = 0;
var timer = window.SetInterval(function () {
x++;
if (x > 100)
window.ClearInterval(timer);
fb.trace("timer " + x);
window.Repaint();
}, 2);
function on_paint(gr) {
fb.trace("on_paint " + x);
}
Result:
on_paint 0
timer 1
timer 2
on_paint 2
timer 3
timer 4
timer 5
on_paint 5
timer 6
timer 7
on_paint 7
timer 8
timer 9
timer 10
on_paint 10
timer 11
on_paint 11
timer 12
on_paint 12
Yes, it looks like if you call window.Repaint in rapid succession, it doesn't process. This timer is using 2ms whereas I suspect those callbacks were happening much closer together.
Darn, guess I'll have to take it into account when making scripts... Thanks for figuring it out.
[EDIT]:
it might be linked to monitor refresh rate: 60HZ == 1 refresh every 16,(6) ms. Will test it out on 120HZ monitor later.[EDIT2]: Nah, I was wrong, it seems it depends purely on CPU, i.e. how fast it can process Repaint calls. Because I have logs like this
timer 60
on_paint 60
timer 61
on_paint 61
timer 62
on_paint 62
timer 63
on_paint 63
timer 64
on_paint 64
timer 65
on_paint 65
timer 66
on_paint 66
timer 67
on_paint 67
timer 68
timer 69
on_paint 69
[EDIT]: Do you know the difference between on_playlist_items_selection_change and on_selection_changed? What I gathered from docs is that on_selection_changed might not always work, but then why use it at all instead of always using on_playlist_items_selection_change?
on_selection_changed gets called when selecting tracks in Library viewers like Album List, not just playlists.
window.Repaint(force) maps to HostComm::Repaint (https://github.com/19379/foo-jscript-panel/blob/a39c3d56d23a93f80fccbfbebb97f9e309509234/foo_jscript_panel/host.cpp#L39) on the C++ side. With force set to false it just marks the window as as dirty, i.e. it sets a flag which tells the window manager that this window needs to be redrawn. With force set to true it causes the window to be redrawn immediately. The idea is to use the delayed redraw (with force set to false) whenever possible because redrawing a window is usually an expensive operation (compared to setting a flag, adding two numbers or formatting a string). You should generally use a delayed redraw inside a callback from foobar2000, i.e. for playback events or playlist changes.
Sorry for disturbing back again...
If GdiDrawText is called in gdi.CreateImage(), is it impossible to avoid the black edge, even if having filled a solid background behind that?
(http://i.imgur.com/iv7FrYw.png)
The highlighted "Oh Nana" was drawn in an image created, with the pink background just behind it in the same image, while the "(2016)" was drawn directly in on_paint() callback.
I know that drawstring() could solve this problem, but I just do not like its look, and wonder if there is a way to perfectly use GDI.
Thanks for any help or hints...
Use g.DrawString instead of gdiDrawText, and g.SetTextRenderingHint(4) before that.
window.Repaint(force) maps to HostComm::Repaint (https://github.com/19379/foo-jscript-panel/blob/a39c3d56d23a93f80fccbfbebb97f9e309509234/foo_jscript_panel/host.cpp#L39) on the C++ side. With force set to false it just marks the window as as dirty, i.e. it sets a flag which tells the window manager that this window needs to be redrawn. With force set to true it causes the window to be redrawn immediately. The idea is to use the delayed redraw (with force set to false) whenever possible because redrawing a window is usually an expensive operation (compared to setting a flag, adding two numbers or formatting a string). You should generally use a delayed redraw inside a callback from foobar2000, i.e. for playback events or playlist changes.
Completely forgot about the "force". I've never had to use it myself and I don't think I've seen it anyone else's scripts either. I don't think real world usage needs it. Like you say, the whole point is to reduce redrawing if you can.
Sorry for disturbing back again...
If GdiDrawText is called in gdi.CreateImage(), is it impossible to avoid the black edge, even if having filled a solid background behind that?
(http://i.imgur.com/iv7FrYw.png)
The highlighted "Oh Nana" was drawn in an image created, with the pink background just behind it in the same image, while the "(2016)" was drawn directly in on_paint() callback.
I know that drawstring() could solve this problem, but I just do not like its look, and wonder if there is a way to perfectly use GDI.
Thanks for any help or hints...
Use g.DrawString instead of gdiDrawText, and g.SetTextRenderingHint(4) before that.
I know. As you see, I mentioned it in the original post.
I'm just not in favor of what it looks like... And the fact that gdidrawstring() resulting weirdly, even if with a solid background, seems strange to me. I hope it can be fixed somehow... Or I have to use those dirty, dirty hacks...
Even this snippet which saves as .png has the same problem. I doubt I'll find out how to fix this.
// ==PREPROCESSOR==
// @import "%fb2k_component_path%samples\complete\js\lodash.min.js"
// @import "%fb2k_component_path%samples\complete\js\helpers.js"
// ==/PREPROCESSOR==
var font = _.gdiFont("Segoe UI", 72, 1);
var white = _.RGB(255, 255, 255);
var img = gdi.CreateImage(400, font.Height);
var gb = img.GetGraphics();
gb.gdiDrawText("JScript", font, white, 0, 0, 400, font.Height, CENTRE | DT_VCENTER)
img.ReleaseGraphics(gb);
img.SaveAs("z:\\test.png"); //png is default, no need to specify type
Even this snippet which saves as .png has the same problem. I doubt I'll find out how to fix this.
// ==PREPROCESSOR==
// @import "%fb2k_component_path%samples\complete\js\lodash.min.js"
// @import "%fb2k_component_path%samples\complete\js\helpers.js"
// ==/PREPROCESSOR==
var font = _.gdiFont("Segoe UI", 72, 1);
var white = _.RGB(255, 255, 255);
var img = gdi.CreateImage(400, font.Height);
var gb = img.GetGraphics();
gb.gdiDrawText("JScript", font, white, 0, 0, 400, font.Height, CENTRE | DT_VCENTER)
img.ReleaseGraphics(gb);
img.SaveAs("z:\\test.png"); //png is default, no need to specify type
As I know, gdidrawtext() needs a background to run, and if it is running on a transparent background, as in the snippet above, it will use black (0-0-0) as a background by default.
So, technically, there is no bug in that snippet. And my real problem is, in a temp graphic part, even if a (colorful) background is defined before, the gdidrawtext() still runs as the background is black; while the problem don't appear with normal gr. in on_paint() callbacks.
Hope I successfully delivered what I thought...
// ==PREPROCESSOR==
// @import "%fb2k_component_path%samples\complete\js\lodash.min.js"
// @import "%fb2k_component_path%samples\complete\js\helpers.js"
// ==/PREPROCESSOR==
var font = _.gdiFont("Segoe UI", 72, 1);
var white = _.RGB(255, 255, 255);
var img = gdi.CreateImage(400, font.Height);
var gb = img.GetGraphics();
//Pre-define a background
gb.FillSolidRect(0, 0, 400, font.Height, 0xffabcdef);
gb.gdiDrawText("JScript", font, white, 0, 0, 400, font.Height, CENTRE | DT_VCENTER);
img.ReleaseGraphics(gb);
img.SaveAs("z:\\test.png"); //png is default, no need to specify type
Hope this may somehow result a smooth image...
The component creates image objects which use premultiplied alpha (see https://github.com/19379/foo-jscript-panel/blob/master/foo_jscript_panel/script_interface_impl.cpp#L1122).
PNG on the other hand uses non-premultiplied alpha (see https://www.w3.org/TR/PNG-Rationale.html#R.Non-premultiplied-alpha).
One would hope that GDI+ did the right thing when drawing an image. On the other hand your experiments indicate that it uses the blend formula for non-premultiplied alpha. As a quick search reveals other people have noticed this behaviour as well (see http://stackoverflow.com/questions/19809506/drawing-pixelformat32bpppargb-images-with-gdi-uses-conventional-formula-instead).
Changing the pixel format would solve this problem. Some part of the code may require changes as well if they expect premultiplied alpha.
Forgive me if I'm being dense but I'm not sure any of that is relevant given DrawString works fine?? You'll have to ask Scrummble why it's not good enough.
You have a point there. I should have paid closer attention. I might have noticed that GdiDrawText does not use GDI+ but plain old GDI.
It's possible to trick it, ala what I did in foo_osd for GDI text drawing: Render an alpha mask separately, by rendering the text again using solid white on solid black, and capture the green channel of the result as the alpha level, and treat the correctly colored text on black background as the color channels pre-multiplied.
My assumption is that changing PixelFormat32bppPARGB to PixelFormat32bppARGB may works in this issue. Had anyone given it a try? I'm afraid I do not have any knowledge of C++, so please teach me if there's anything wrong.
It's possible to trick it, ala what I did in foo_osd for GDI text drawing: Render an alpha mask separately, by rendering the text again using solid white on solid black, and capture the green channel of the result as the alpha level, and treat the correctly colored text on black background as the color channels pre-multiplied.
Thanks for the alternative method, but it will dispose of the LCD specified rendering. I haven't give it a try, but I guess it may look just like SetTextRenderingHint(4). I think I should stick on the "all on_paint and concealing with fake background" hack anyway...
Thanks for the alternative method, but it will dispose of the LCD specified rendering. I haven't give it a try, but I guess it may look just like SetTextRenderingHint(4). I think I should stick on the "all on_paint and concealing with fake background" hack anyway...
Actually, it only tosses out the LCD rendering for the alpha mask, where it would be impossible to calculate an alpha mask anyway. The red/blue hinting would still exist on the RGB colored text that is rendered separately as the pre-scaled RGB channels. Assuming your GDI rendering code doesn't force grayscale hinting.
And even if that doesn't work, you can always render your own LCD hinted text, simply by scaling the text up to 3x size, then using an RGB matrix to downscale the horizontal part to 1/3 size with just the right R/G/B crosstalk. Search for the old "Clearize" demo for Allegro for an example reduction matrix.
E: Disregard "Clearize" tip, said site and software no longer exists. But there's still this (http://everything2.com/title/ClearType).
I've fixed up all 3 of Falstaff/Br3tt's JS Smooth scripts so they work in the latest version of JScript Panel. It was some badly formatted if/else statements that prevented it working with the Chakra engine.
https://github.com/19379/JS-Smooth-Scripts-By-Br3tt
@Falstaff, if you read this sometime, the new component didn't like you coding like this...
if (something) {
};
else {
}
It had to be replaced with
} else {
edit: Just realised I missed the catch statements so an updated version has been uploaded.
Hi everyone,
How i can get rid of the white border around the cover in the Js Smooth Playlist ?
Can't spot the function. :(
Do you mean jsplaylist-mod? I can't see any border in the Smooth version.
edit: Seems to be line 770 in user-components\foo_jscript_panel\samples\jsplaylist-mod\js\WSHPlaylist.js. Either change the colour or comment the entire line out. Remember that any future component update would overwrite changes so make sure you save a copy elsewhere.
I have been using JScript Panel along with marc's last.fm bio.txt and thumbs.txt. Both worked admirably up until some time this week. At some point after updating JScript to v1.2.0, both now are displaying blank windows for new artists but still showing bio/pics for existing artists (cached I assume). Is anyone else having this issue? I tried rolling back the JScript to v 1.1.3--no luck
Any help would be much appreciated.
fb2k v1.3.14
Windows 10
I have been using JScript Panel along with marc's last.fm bio.txt and thumbs.txt. Both worked admirably up until some time this week. At some point after updating JScript to v1.2.0, both now are displaying blank windows for new artists but still showing bio/pics for existing artists (cached I assume). Is anyone else having this issue? I tried rolling back the JScript to v 1.1.3--no luck
Any help would be much appreciated.
fb2k v1.3.14
Windows 10
Yeah, I think Last.fm may have done something to break the bio panel on their end. This is what I get when I try to download artist art with the Bio Script:
"np_basic: HTTP error: 0"
I have been using JScript Panel along with marc's last.fm bio.txt and thumbs.txt. Both worked admirably up until some time this week. At some point after updating JScript to v1.2.0, both now are displaying blank windows for new artists but still showing bio/pics for existing artists (cached I assume). Is anyone else having this issue? I tried rolling back the JScript to v 1.1.3--no luck
Any help would be much appreciated.
fb2k v1.3.14
Windows 10
Yep, here too. Had foreseen this was to happen considering last.fm's track record. Lucky I cached as much as I could before it stopped working.
Last.fm have updated their website to use https therefore the scripts need to be updated. Edit your text.js/thumbs.js files and replace
http with
https.
text.js
var url = "https://" + this.bio_lastfm_sites[this.bio_lastfm_site] + "/music/" + encodeURIComponent(this.artist) + "/+wiki";
thumbs.js
this.xmlhttp.open("GET", "https://www.last.fm/music/" + encodeURIComponent(this.artist) + "/+images", true);
Cross-posting here since it slipped my mind there was a separate discussion/help thread when replying in the other thread and I can't now delete it.
JSplaylist is now bundled with the component itself.
https://github.com/19379/foo-jscript-panel/tree/master/component/samples
Ah, good to know.
With regard to force sorting in the panel, any ideas? I find I have to right-click the columns header>Groups>Apply group sorting to override the filename sorting and apply track number order, but the option doesn't seem to be able to be permanently set.
Last.fm have updated their website to use https therefore the scripts need to be updated. Edit your text.js/thumbs.js files and replace http with https.
text.js
var url = "https://" + this.bio_lastfm_sites[this.bio_lastfm_site] + "/music/" + encodeURIComponent(this.artist) + "/+wiki";
thumbs.js
this.xmlhttp.open("GET", "https://www.last.fm/music/" + encodeURIComponent(this.artist) + "/+images", true);
Thanks!
Is it possible with jscript to hide or show a columns ui panel? In other words to trigger the panelshow command of panel stack splitter?
I finally learned a workaorund for this: you can create and delete an empty text file with the
CreateTextFile and
DeleteFile methods which than PSS can check out with the
$findfile function to trigger any command you like.
I have to credit the russian forum for this.
I've fixed up all 3 of Falstaff/Br3tt's JS Smooth scripts so they work in the latest version of JScript Panel. It was some badly formatted if/else statements that prevented it working with the Chakra engine.
https://github.com/19379/JS-Smooth-Scripts-By-Br3tt
@Falstaff, if you read this sometime, the new component didn't like you coding like this...
if (something) {
};
else {
}
It had to be replaced with
} else {
edit: Just realised I missed the catch statements so an updated version has been uploaded.
ok, seen, i'll be aware of that.
There is a js-script panel which changes in the size according to the toggle notify. (for example, h1 = 500, h2=1)
In other word,
for toggle --> panel height = h1
for !toggle --> panel height = h2
What I want to do is (%path% is "youtube.com/watch~~~~")
for toggle and %path% include 'youtube' --> panel height = h1
for toggle, and %path% Not include 'youtube' --> panel height = 10
for !toggle --> panel height = h2
So, I tried like this,
var chk_yt = "$left(%path%,7)";
function on_notify_data(name, info) {
switch(name) {
case "center_panel":
toggle = !toggle;
window.SetProperty("toggle", toggle);
if(toggle) {
if(chk_yt == "youtube") {
window.MinHeight = h1;
window.MaxHeight = h1;
} else {
window.MinHeight = 10;
window.MaxHeight = 10;
};
} else {
window.MinHeight = h2;
window.MaxHeight = h2;
};
break;
}
}
But, it doesn't work as I wanted. Could anyone give me some hint to make this work?
First replace ..
var chk_yt = "$left(%path%,7)";
with
var chk_yt = fb.TitleFormat("%path%").Eval().substring(0,7);
That bit of code needs to go inside the function, If it runs outside the function at script startup, the value will never update.
If unsure, you can always output stuff to the console to check the value is what you expect it to be.
fb.trace(chk_yt);
zeremy & marc2003,
Thank you for your kind help. It was very helpful.
Even though my current foobar is very close to the final target, there is a small problem.
When I change tracks between 'youtube' songs and 'non-youtube' songs, I want the size(panel height) of jsscript panel to automatically be changed according to the source of track.
youtube track --> panel height = h1
non-youtube track --> panel height = 1Could you let me know how to change the following scripts for that purpose?
function on_size() {
ww = window.Width;
wh = window.Height;
var chk_yt = fb.TitleFormat("%path%").Eval().substring(0,7);
if(chk_yt == "youtube") {
if(toggle) {
window.MinHeight = h1;
window.MaxHeight = h1;
} else {
window.MinHeight = 1;
window.MaxHeight = 1;
};
} else {
window.MinHeight = 1;
window.MaxHeight = 1;
};
window.MinWidth = 1;
window.MaxWidth = 1;
}
function on_notify_data(name, info) {
switch(name) {
case "height_notify":
max_h = (info - 3);
case "width_notify":
height = Math.round(info * 0.5625);
if(height >= max_h) {
h1 = max_h;
} else {
h1 = Math.round(info * 0.5625)-1;
};
window.MinHeight = 1;
window.MaxHeight = 1;
break;
case "center_pane":
toggle = !toggle;
window.SetProperty("toggle", toggle);
var chk_yt = fb.TitleFormat("%path%").Eval().substring(0,7);
if(chk_yt == "youtube") {
if(toggle) {
window.MinHeight = h1;
window.MaxHeight = h1;
} else {
window.MinHeight = 1;
window.MaxHeight = 1;
}
} else {
window.MinHeight = 1;
window.MaxHeight = 1;
};
break;
}
}
I see you are using function on_notify_data(name, info).
Could you clarify if you need to notify from a jscript panel another second jscript panel with window.NotifyOthers .
Are they two separate panels or do you just want one jscript panel height to change when youtube is playing?
What is the purpose of the variable toggle?
I see you are using function on_notify_data(name, info).
Could you clarify if you need to notify from a jscript panel another second jscript panel with window.NotifyOthers .
Are they two separate panels or do you just want one jscript panel height to change when youtube is playing?
What is the purpose of the variable toggle?
My configuration is like this.
I have several panels such as "playlists, album art, biography, play control, foo_youtube, etc"
I want 'foo_youtube' panel to be size-adjusted according to the foobar window & other panel sizes, and to be toggled by 'toggle buttons' in a different jscript panel.
For this purpose, I made created two panels with 'left/right'splitter. And 'foo_youtube is implemented in the left panel, and the above code is implemented in the right panel.
So, by changing the height of the right panel, I can hide/show the foo_youtube panel which has 16:9 ratio.
"height_notify" and "width_notify" are notified from the other jscript panels and are used to adjust the right panel height.
At this moment, I can toggle the foo_youtube panel by clicking the 'toggle button'.
The purpose of toggle : "Sometimes I want to see the youtube video, sometimes only want to listen the youtube audio by hiding 'foo_youtube' panel."
But, some playlists have mixes of "youtube songs" and 'non-youtube songs."
For those playlists, it would be nice if the 'foo_youtube' panel can be hide/show automatically by checking if the now-playing song is coming from 'youtube' site.
I hope that the above explanation make clear my intention.
Thank you agian for your interest and help.
You can send the value if "youtube" from your "control panel" on each new track played with:
function on_playback_new_track(){
var chk_yt = fb.TitleFormat("%path%").Eval().substring(0,7);
window.NotifyOthers("center_pane",chk_yt);
}
In the panel to be notified add:
function on_notify_data(name, info) {
switch(name) {
case "center_pane":
if(info == "youtube") {
if(toggle) {
window.MinHeight = h1;
window.MaxHeight = h1;
} else {
window.MinHeight = 1;
window.MaxHeight = 1;
}
} else {
window.MinHeight = 1;
window.MaxHeight = 1;
};
break;
}
}
toogle and h1 will have to be defined beforehand for it to work though.
The panel cannot be in a PSS https://github.com/19379/foo-jscript-panel/blob/master/component/docs/Interfaces.txt#L759 (https://github.com/19379/foo-jscript-panel/blob/master/component/docs/Interfaces.txt#L759)
I lost you when you referred to showing/hiding the video panel ( even after a cup of coffee :D ) , you can only change the jscript panel size,
toogle and h1 will have to be defined beforehand for it to work though.
I lost you when you referred to showing/hiding the video panel ( even after a cup of coffee :D ) , you can only change the jscript panel size,
Thank you very very much for your help.
With minor optimization for your above code, my foobar is fianlly working as I wanted
For the reference, I leave my final code for my purpose.
In the foobar control jscript panel,
function on_playback_new_track(){
var chk_yt = fb.TitleFormat("%path%").Eval().substring(0,7);
window.NotifyOthers("chk_yt",chk_yt);
}
In the target jscript paenl,
function on_notify_data(name, info) {
switch(name) {
case "center_pane":
toggle1 = !toggle1;
window.SetProperty("toggle1", toggle1);
toggle = toggle1;
if(chk_yt == "youtube") {
if(toggle1) {
window.MinHeight = h1;
window.MaxHeight = h1;
} else {
window.MinHeight = 1;
window.MaxHeight = 1;
};
} else {
toggle = false;
window.MinHeight = 1;
window.MaxHeight = 1;
};
break;
case "chk_yt":
chk_yt = info;
if(info == "youtube") {
toggle = toggle1;
if(toggle1) {
window.MinHeight = h1;
window.MaxHeight = h1;
} else {
window.MinHeight = 1;
window.MaxHeight = 1;
};
} else {
toggle = false;
window.MinHeight = 1;
window.MaxHeight = 1;
};
break;
}
}
I have a question about on_playback_stop() & on_playback_new_track()
Now, I'm using the below code to notify 'stop' to the other panel.
function on_playback_stop() {
window.NotifyOthers("stop_notify","");
buttons.update();
window.Repaint();
}
Function "on_playback_new_track()" don't have any NotifyOthers. But, whenever a new track is played according to the plalist queue, it looks like 'stop_notify' is activated.( playback_new_track --> playback_stop + playback_starting ?)
How can I notify 'stop_notify' only when I "Really" stop playing foobar?
docs\callbacks.txt
https://github.com/19379/foo-jscript-panel/blob/master/component/docs/Callbacks.txt#L133L134
Something like
function on_playback_stop(reason) {
if (reason < 2) {
window.NotifyOthers("stop_notify","");
}
buttons.update();
window.Repaint();
}
docs\callbacks.txt
https://github.com/19379/foo-jscript-panel/blob/master/component/docs/Callbacks.txt#L133L134
Something like
function on_playback_stop(reason) {
if (reason < 2) {
window.NotifyOthers("stop_notify","");
}
buttons.update();
window.Repaint();
}
Wow. It's so simple. I didn't know that there are those documents under jscript-panel plugin.
Thank you for your help.
Hi marc2003,
Firstly, thank you for your work on JScript Panel, and thank you for sharing it with the fb2k community.
I'm using your album art script example, and I noticed that the included shadow overlay PNG didn't blend so well at the edges - so I made another version in Photoshop that fixes this and wanted to share it with you snd the community.
Here's the download to the revised shadow.png: http://i.imgur.com/js04cN8.png
And here's the comparison against your original version: http://i.imgur.com/plXl0Nw.png
On a side note, I disabled the forced crop/fill option that you specify when using the CD case background, because some of the releases in my collection are in mini-CD single format, which looks bad when forced to fill the extents of the jewel case. Perhaps you might want to consider making this a toggle that can be selected when using the CD case?
I'll use your updated image in the next release. Thanks.
As for the aspect, I always thought cropping the image was best without giving a choice. I think gaps around non square images look bad on the case background?? Still, I suppose I can restore the option to let people choose.
edit: changes have been made in this commit (https://github.com/19379/foo-jscript-panel/commit/d606f953ef6bc1c2ab78123ef46c448ef7a14020).
I think gaps around non square images look bad on the case background?? Still, I suppose I can restore the option to let people choose.
Well, it definitely is not realistic for a tall, rectangular cover to sit inside a CD jewel case tray, but for the few releases I have with album art in that format, it doesn't bother me - seeing the entire album art is a higher priority.
Thanks for the commit! :)
I have a perhaps silly question about debugging scripts running inside JSPanel. Here's an example error:
JScript Panel (Rating by marc2003): Microsoft JScript runtime error:
'_' is undefined
File: <main>
Line: 13, Col: 1
<source text only available at compile time>
What does "source text only available at compile time" mean? Can I actually see more debug info during... compile time? What does "compile time" mean? Can I somehow debug the C++ component using Visual Studio if I launch foobar? Or can I debug the JS script from a tool such as Webstorm? (although this second variant I guess would be a bit more technically challenging to perform since it requires somehow connecting the IDE to the browser VM running under Foobar).
Just ignore the stuff you don't understand. Line 13 and '_' is undefined is actually all the information you need. No fancy IDE/debugger is going to be any more helpful.
Anyway, the reason for that error is that important files are missing because you didn't install the component properly. I did link to the foolproof instructions but I guess you decided you were bit of a gangster and extracted the dll only?
http://wiki.hydrogenaud.io/index.php?title=Foobar2000:How_to_install_a_component
Hey :). I managed to fix the error because the next error was quite clear. Yes, I initially only extracted the DLL. But it wasn't because I wanted more street cred' :). It was because "docs" and "samples" didn't seem to me to need to belong in the components folder. But I'm fine with whatever! :). The component ROCKS and I'm very enthusiastic to work with it now that I finally managed to set some time for this.
I'm trying to build a multi-tag tool. Something that allows to set multiple tags to song and filter on them. Things like a song's style, mood, vocal style, lyrical theme, tempo. What I'm aiming is to allow a user to create auto playlists by requesting, for example, "all songs that feature female vocals, have a slow tempo and have a mystic atmosphere". I plan to perhaps build relations between tags so that similar suggestions are found based on the selected tags.
I do have a few questions to start with:
There is no dropdown list component from what I see? I can probably achieve a similar functionality by creating context menus with options, something I've already seen used in some of your samples. But what if there are more items that fit on the screen? What is your recommendation in that case? Should I use GDI to create my own component?
I'd like to implement an autocomplete textbox. The purpose being that when you start typing any tag, you get a suggestion that you can "tab" to autocomplete. This should be pretty easy right? Just create a hotkey hook. I hope TAB... won't tab me out of the panel :).
I'm kind of aiming to go into the Columns UI code anyway and see if I can find a way to install shortcuts for focusing on various panels, as I am very keyboard driven and would love to operate Foobar as much as possible using keyboard only.
If the menu doesn't fit on screen, there will be arrows to scroll up/down. Example....
// ==PREPROCESSOR==
// @import "%fb2k_component_path%samples\complete\js\lodash.min.js"
// @import "%fb2k_component_path%samples\complete\js\helpers.js"
// ==/PREPROCESSOR==
var items = _.range(0, 1000);
function on_mouse_lbtn_up(x, y) {
var m = window.CreatePopupMenu();
_.forEach(items, function (i) {
m.AppendMenuItem(MF_STRING, i + 1, "Menu Item " + i);
});
var idx = m.TrackPopupMenu(x, y);
if (idx > 0)
fb.ShowPopupMessage("You selected item " + (idx - 1));
m.Dispose();
}
Falstaff/Wilb both have scripts available with fully functioning text boxes that you can type in. Look at jsplaylist-mod (included with component) or Wilb's Library tree script.
Perfect. Thank you for all the pointers :). Helpful as usual. Thank you for your patience as you explain these things. I've always been impressed by the quality of work that went into extending Foobar's functionality by all the community.
It's awesome that you implemented autocompletion in the panel editor itself! I suppose this is the preferred method of editing the scripts?
I like to browse various code samples in parallel with coding my own script, especially since I'm quite new at this. For now I'm using IntelliJ for that, since it helps a bit with the coloring. I don't suppose there are ways to make an IDE do code completion based on your .api files. The only reason I'm asking is because code navigation is easier with an IDE thanks to things like "go to definition" and various hover hints, etc etc.
Whoops. Only now after a bit more investigation I realized that all UI work done in a JSPanel has to be done using GDI calls. Basically components have to be created from scratch.
I am probably missing something here :).
I don't really understand why not to develop the component in Visual Studio then, where there is the possibility of using Win32 API to create comboboxes and such. Plus, there's a tighter integration with the rest of the Foobar ecosystem such as Columns UI.
If I'm failing to see something important, please tell me. I haven't yet started any actual coding :). Still investigating SDKs. I got some Visual Studio builds going too. I know my way around C++, although I never went in-depth with it.
I don't really understand why not to develop the component in Visual Studio then, where there is the possibility of using Win32 API to create comboboxes and such. Plus, there's a tighter integration with the rest of the Foobar ecosystem such as Columns UI.
That's the entire point of JScript: (kinda) user-friendly way to create 'components'. Especially useful, when you need a simple panel (e.g. a panel that displays some text, or may be a button) - creating a separate full component for every such panel is just pointless.
Just compare writing a JS program (with run-time compilation) in JScript windows w\o any need of external software or IDE vs writing a full component based on foobar SDK with all the dependencies, build parameters, dll's and etc, which can't be done without having a proper build environment (compiler/IDE).
But, yeah, if you want to develop a high performance component with the full usage of WinApi, then JScript is not really suitable for your needs.
Last.fm have updated their website to use https therefore the scripts need to be updated. Edit your text.js/thumbs.js files and replace http with https.
thumbs.js
this.xmlhttp.open("GET", "https://www.last.fm/music/" + encodeURIComponent(this.artist) + "/+images", true);
I applied the same edit to the
last.fm albumart downloader script, which I just found out is not working anymore, but it doesn't solve the problem. Is there anyway to get the script back to work? Did it actually stop working in the first place or did I mess up something?
Last.fm have updated their website to use https therefore the scripts need to be updated. Edit your text.js/thumbs.js files and replace http with https.
thumbs.js
this.xmlhttp.open("GET", "https://www.last.fm/music/" + encodeURIComponent(this.artist) + "/+images", true);
I applied the same edit to the last.fm albumart downloader script, which I just found out is not working anymore, but it doesn't solve the problem. Is there anyway to get the script back to work? Did it actually stop working in the first place or did I mess up something?
Sorry, answering myself: yes, I did mess up something. The script had been updating the album-art.ini file even if the download didn't work and after editing the script I tested it on the same tracks. After erasing the last added lines in the ini file the script was able to download the album covers.
I'm trying to create a simple menu button but I can't figure out how to display a "pressed" image that appears while the contextmenu popup is open. The default button only has normal and hover states, and no matter what I try I can't seem to swap the normal image for the pressed one on-the-fly. Any help would be much appreciated. My code is below:
// ==PREPROCESSOR==
// @name "MainMenuManager All-In-One"
// @author "YBStone / T.P Wang / marc2003"
// @import "%fb2k_component_path%docs\flags.txt"
// @import "%fb2k_component_path%docs\helpers.txt"
// ==/PREPROCESSOR==
var tooltip = window.CreateTooltip();
// buttons is defined in docs\helpers.txt
var b = new buttons();
var mhx = false;
var pressed = false;
var img1 = "C:\\fooTest\\test01.png";
var img2 = "C:\\fooTest\\test02.png";
var img3 = "C:\\fooTest\\test03.png";
var img4 = "C:\\fooTest\\test04.png";
var img5 = "C:\\fooTest\\test05.png";
var imgN;
var imgH;
var imgP;
if(pressed == true)
imgP = img1;
else
imgP = img2;
//button is defined in docs\helpers.txt
//arguments are x, y, w, h, {normal image, hover image is optional}, function, tooltip
b.buttons.menu = new button(0, 0, 60, 60, {normal : imgP, hover: img5},function () { menu(); }, "");
function on_paint(gr) {
b.paint(gr);
}
function on_mouse_move(x, y) {
b.move(x, y);
}
function on_mouse_lbtn_up(x, y) {
if( mhx == false ){
b.lbtn_up(x, y);
mhx = true;}
else if ( mhx == true ){
mhx = false;}
if( pressed == false ){
pressed = true;}
else if( pressed = true ){
pressed = false;}
}
function on_mouse_leave(x, y) {
b.leave();
mhx = false;
}
function menu() {
var basemenu = window.CreatePopupMenu();
var contextman = fb.CreateContextMenuManager();
contextman.InitNowPlaying();
var child1 = window.CreatePopupMenu(); //File
var child2 = window.CreatePopupMenu(); //Edit
var child3 = window.CreatePopupMenu(); //View
var child4 = window.CreatePopupMenu(); //Playback
var child5 = window.CreatePopupMenu(); //Library
var child6 = window.CreatePopupMenu(); //Help
var child7 = window.CreatePopupMenu(); //Now playing
var child8 = window.CreatePopupMenu(); //cherry test
var child9 = window.CreatePopupMenu(); //apple test
var menuman1 = fb.CreateMainMenuManager();
var menuman2 = fb.CreateMainMenuManager();
var menuman3 = fb.CreateMainMenuManager();
var menuman4 = fb.CreateMainMenuManager();
var menuman5 = fb.CreateMainMenuManager();
var menuman6 = fb.CreateMainMenuManager();
// MF_STRING is defined in docs\flags.txt
child1.AppendTo(basemenu, MF_STRING, "File");
child2.AppendTo(basemenu, MF_STRING, "Edit");
child3.AppendTo(basemenu, MF_STRING, "View");
child4.AppendTo(basemenu, MF_STRING, "Playback");
child5.AppendTo(basemenu, MF_STRING, "Library");
child6.AppendTo(basemenu, MF_STRING, "Help");
child7.AppendTo(basemenu, MF_STRING, "Now Playing");
basemenu.AppendMenuSeparator();
child8.AppendTo(basemenu, MF_STRING, "CHERRY");
child8.AppendMenuItem(MF_STRING, 7501, "cherries in my mouth [Console]");
child8.AppendMenuItem(MF_STRING, 7502, "cherries in my hand [Open]");
basemenu.AppendMenuItem(MF_STRING, 8000, "Preferences (Apple)");
menuman1.Init("file");
menuman2.Init("edit");
menuman3.Init("View");
menuman4.Init("playback");
menuman5.Init("library");
menuman6.Init("help");
menuman1.BuildMenu(child1, 1, 200);
menuman2.BuildMenu(child2, 201, 200);
menuman3.BuildMenu(child3, 401, 300);
menuman4.BuildMenu(child4, 601, 300);
menuman5.BuildMenu(child5, 901, 300);
menuman6.BuildMenu(child6, 1201, 100);
contextman.InitNowPlaying();
contextman.BuildMenu(child7, 1301, -100);
var menuY = b.buttons.menu.h + b.buttons.menu.y + 4;
ret = basemenu.TrackPopupMenu(b.buttons.menu.x, menuY);
switch (true) {
case(ret >= 1 && ret < 201):
menuman1.ExecuteByID(ret - 1);
break;
case (ret >= 201 && ret < 401):
menuman2.ExecuteByID(ret - 201);
break;
case (ret >= 401 && ret < 601):
menuman3.ExecuteByID(ret - 401);
break;
case (ret >= 601 && ret < 901):
menuman4.ExecuteByID(ret - 601);
break;
case (ret >= 901 && ret < 1201):
menuman5.ExecuteByID(ret - 901);
break;
case (ret >= 1201 && ret < 1301):
menuman6.ExecuteByID(ret - 1201);
break;
case (ret >= 1301 && ret < 2000): //case (ret >= 1301):
contextman.ExecuteByID(ret - 1301);
break;
case (ret == 7501):
fb.RunMainMenuCommand("View/Console");
break;
case (ret == 7502):
fb.RunMainMenuCommand("File/Open...");
break;
case (ret == 8000):
fb.RunMainMenuCommand("File/Preferences");
break;
}
basemenu.Dispose();
contextman.Dispose();
menuman1.Dispose();
menuman2.Dispose();
menuman3.Dispose();
menuman4.Dispose();
menuman5.Dispose();
menuman6.Dispose();
}
I encountered a error about WSH Cover Panel scripts running inside the new JScript. I can't fix this error (line: 1984). Who can fix it? please. Code is too long, it is in Skins.7z.
// ==PREPROCESSOR=====================================
// @name "WSH Cover Panel"
// @version "2.0.1"
// @author "Jensen"
// @email "jensen-yg@163.com"
// ==/PREPROCESSOR====================================
//ThisPanelsName = "WSHCoverPanel";
//===================================
// Flags, used by Menu -----------------
var MF_STRING = 0x00000000;
var MF_DISABLED = 0x00000002;
var MF_CHECKED = 0x00000008;
I'm trying to create a simple menu button but I can't figure out how to display a "pressed" image that appears while the contextmenu popup is open. The default button only has normal and hover states, and no matter what I try I can't seem to swap the normal image for the pressed one on-the-fly. Any help would be much appreciated.
Your code is ...uhm... to put it lightly ... it's bad. I don't even know where to start...
This code:
if(pressed == true)
imgP = img1;
else
imgP = img2;
Executes only once, so your imgP won't change after script initialization. But that wouldn't have worked anyway, since 'button' object has it's images initialized on creation.
@ColdChemical, I've updated the code. You can change the images and remove the background colour I added - I just used them fr contrast.
// ==PREPROCESSOR==
// @name "MainMenuManager All-In-One"
// @author "YBStone / T.P Wang / marc2003"
// @import "%fb2k_component_path%docs\flags.txt"
// @import "%fb2k_component_path%docs\helpers.txt"
// ==/PREPROCESSOR==
var tooltip = window.CreateTooltip();
var b = new buttons();
var normal_img = fb.ComponentPath + "samples\\complete\\images\\misc\\menu white.png";
var hover_img = fb.ComponentPath + "samples\\complete\\images\\misc\\menu black.png";
b.update = function (pressed) {
this.buttons.menu = new button(0, 0, 60, 60, {normal : pressed ? hover_img : normal_img, hover: hover_img},function () { menu(); }, "");
window.Repaint();
}
b.update();
function on_paint(gr) {
gr.FillSolidRect(0, 0, window.Width, window.Height, RGB(255, 0, 0));
b.paint(gr);
}
function on_mouse_move(x, y) {
b.move(x, y);
}
function on_mouse_lbtn_up(x, y) {
b.lbtn_up(x, y);
}
function on_mouse_leave(x, y) {
b.leave();
}
function menu() {
var basemenu = window.CreatePopupMenu();
var contextman = fb.CreateContextMenuManager();
contextman.InitNowPlaying();
var child1 = window.CreatePopupMenu(); //File
var child2 = window.CreatePopupMenu(); //Edit
var child3 = window.CreatePopupMenu(); //View
var child4 = window.CreatePopupMenu(); //Playback
var child5 = window.CreatePopupMenu(); //Library
var child6 = window.CreatePopupMenu(); //Help
var child7 = window.CreatePopupMenu(); //Now playing
var child8 = window.CreatePopupMenu(); //cherry test
var child9 = window.CreatePopupMenu(); //apple test
var menuman1 = fb.CreateMainMenuManager();
var menuman2 = fb.CreateMainMenuManager();
var menuman3 = fb.CreateMainMenuManager();
var menuman4 = fb.CreateMainMenuManager();
var menuman5 = fb.CreateMainMenuManager();
var menuman6 = fb.CreateMainMenuManager();
// MF_STRING is defined in docs\flags.txt
child1.AppendTo(basemenu, MF_STRING, "File");
child2.AppendTo(basemenu, MF_STRING, "Edit");
child3.AppendTo(basemenu, MF_STRING, "View");
child4.AppendTo(basemenu, MF_STRING, "Playback");
child5.AppendTo(basemenu, MF_STRING, "Library");
child6.AppendTo(basemenu, MF_STRING, "Help");
child7.AppendTo(basemenu, MF_STRING, "Now Playing");
basemenu.AppendMenuSeparator();
child8.AppendTo(basemenu, MF_STRING, "CHERRY");
child8.AppendMenuItem(MF_STRING, 7501, "cherries in my mouth [Console]");
child8.AppendMenuItem(MF_STRING, 7502, "cherries in my hand [Open]");
basemenu.AppendMenuItem(MF_STRING, 8000, "Preferences (Apple)");
menuman1.Init("file");
menuman2.Init("edit");
menuman3.Init("View");
menuman4.Init("playback");
menuman5.Init("library");
menuman6.Init("help");
menuman1.BuildMenu(child1, 1, 200);
menuman2.BuildMenu(child2, 201, 200);
menuman3.BuildMenu(child3, 401, 300);
menuman4.BuildMenu(child4, 601, 300);
menuman5.BuildMenu(child5, 901, 300);
menuman6.BuildMenu(child6, 1201, 100);
contextman.InitNowPlaying();
contextman.BuildMenu(child7, 1301, -100);
var menuY = b.buttons.menu.h + b.buttons.menu.y + 4;
b.update(true);
ret = basemenu.TrackPopupMenu(b.buttons.menu.x, menuY);
b.update();
switch (true) {
case(ret >= 1 && ret < 201):
menuman1.ExecuteByID(ret - 1);
break;
case (ret >= 201 && ret < 401):
menuman2.ExecuteByID(ret - 201);
break;
case (ret >= 401 && ret < 601):
menuman3.ExecuteByID(ret - 401);
break;
case (ret >= 601 && ret < 901):
menuman4.ExecuteByID(ret - 601);
break;
case (ret >= 901 && ret < 1201):
menuman5.ExecuteByID(ret - 901);
break;
case (ret >= 1201 && ret < 1301):
menuman6.ExecuteByID(ret - 1201);
break;
case (ret >= 1301 && ret < 2000): //case (ret >= 1301):
contextman.ExecuteByID(ret - 1301);
break;
case (ret == 7501):
fb.RunMainMenuCommand("View/Console");
break;
case (ret == 7502):
fb.RunMainMenuCommand("File/Open...");
break;
case (ret == 8000):
fb.RunMainMenuCommand("File/Preferences");
break;
}
basemenu.Dispose();
contextman.Dispose();
menuman1.Dispose();
menuman2.Dispose();
menuman3.Dispose();
menuman4.Dispose();
menuman5.Dispose();
menuman6.Dispose();
}
@always.beta - that script loads fine for me. Behaviour seems buggy but it doesn't crash.
@always.beta - that script loads fine for me. Behaviour seems buggy but it doesn't crash.
Use jscript_panel-v1.2.0.1, after a few seconds, it crashes. Please, need your help. Use WSH 1.5.6, it works. But I don't want to install two components, only jscript_panel is enough.
JScript Panel (WSH Cover Panel v2.0.1 by Jensen)
JavaScript 运行时错误:
类型不匹配
File: <main>
Line: 1984, Col: 13
<source text only available at compile time>
Top: JScript Panel v1.2.0.1 - cover disappears when I click something but doesn't crash - gif is 15 seconds...
Bottom WSH Panel Mod v1.5.6 - works fine???
(https://i.imgur.com/MWmOo1e.gif)
Bottom WSH Panel Mod v1.5.6 - works fine???
Sorry, do not use it for a long time, I made a mistake. WSH Panel Mod v1.5.6 needs other DLL files. WSH Panel Mod Plus works fine.
Top: JScript Panel v1.2.0.1, gif is 53 seconds.
Bottom: WSH Panel Plus
(http://imgur.com/a/SvkS9)
edit: The proper fix is to remove the
on_metadb_changed callback at line 2370...
function on_metadb_changed(metadb, fromhook) {
MainController.Refresh(true, metadb);
}
This function never ran in WSH panel because it needs these directives set in the preprocessor section but they are missing in this script.
// @feature "v1.4"
// @feature "watch-metadb"
If you were to add them , it would crash just like JScript Panel.
edit: I thought it was a bug in the component but it's not. Phew!
edit: The proper fix is to remove the on_metadb_changed callback at line 2370...
I removed the on_metadb_changed callback at line 2370, need to manually refresh to display the picture.
(http://imgur.com/a/xmP4w)
The WSH Cover Panel script is included in the Shutter configuration, it works fine with wsh_v1.5.6 in the original configuration.
Shutter
—— by Jensen (coding) & dReamxis (design)
>FB_Shutter_v1.1_U(Original version): based on wsh panel mod v1.5.6 & foo_ui_hacks.dll+dsound.dll+AutoItX3.dll+dynwrapx.dll
>FB_Shutter_v1.1_U+(Modified a little, may have bugs): based on wsh panel mod plus v1.5.7.4, without foo_ui_hacks.dll+dsound.dll+AutoItX3.dll+dynwrapx.dll. Replace WSH Lyric with ESLyric. Replace Albumlist with Library Tree.
>ShutterIcon: specifically designed for the shutter.
>Wsh-splitter_by_jensen(Original version): based on wsh panel mod v1.5.6 & foo_ui_hacks.dll+dsound.dll+AutoItX3.dll+dynwrapx.dll. Use Chinese to write the interface description. Looking for a good translator.
Download! (https://1drv.ms/f/s!AnFvs7Iqm0IrgdsqnuVrUBRi3tAZAQ)
Your code is ...uhm... to put it lightly ... it's bad. I don't even know where to start...
That's not at all surprising to hear haha. I'm a complete novice when it comes to jscript. Despite my attempts at dissecting marc's samples and reading through online documentation, I haven't had much luck in figuring out how to do a lot of things. If there's some resource, guide, or tutorial that might help me become more proficient I would love to know about it. I'm not sure how much, if at all, this component's implementation of jscript differs from more typical environments.
@ColdChemical, I've updated the code. You can change the images and remove the background colour I added - I just used them fr contrast.
Thank you for the help, though what I'm really after is a third button state in addition to normal and hover. Ideally I'd like to have this third button-state image appear whenever the context popup menu is open (similar to the way the Windows start menu button behaves). If there's no way for the jscript panel to "know" when the popup disappears, then I suppose this wouldn't be possible.
The WSH Cover Panel script is included in the Shutter configuration, it works fine with wsh_v1.5.6 in the original configuration.
I explained why it worked.
edit: changing my reason!! :))
It's because
on_metadb_changed function always get passed a handle list by JScript Panel. WSH panel mod and variants would do the same IF they had the preprocessors added that I mentioned. The function inside expects a handle, not a handle list and that's why it doesn't work. You can restore the function but modify it slightly...
function on_metadb_changed() {
MainController.Refresh(true); //this function still works if you omit it
}
@ColdChemical - not really possible. Button constructors with a down state typically only support a down image while you hold the mouse key down until you release it again. With a menu, you release the button immediately after pressing and the menu stays open until you click something again. There is no clever way of doing this other than the hack I already posted.
I could probably script something to do it but the track changes may not be entirely seamless. I'll test and report back.
edit: I tried it and it was fine for me but YMMV.
Requires WSH panel mod or JScript panel. You can find the latter via the link in my signature.
var t = tracks_to_skip();
function on_playback_new_track() {
var handle = fb.GetNowPlaying();
if (!handle)
return;
var p = handle.Path.toLowerCase();
for (var i = 0; i < t.length; i++) {
if (t[i] == p)
return fb.Next();
}
}
function tracks_to_skip() {
var a = [];
for (var i = 0; i < plman.PlaylistCount; i++) {
if (playlist_name_is_skip(i)) {
var items = plman.GetPlaylistItems(i);
for (var j = 0; j < items.Count; j++) {
a.push(items.Item(j).Path.toLowerCase());
}
}
}
return a;
}
function playlist_name_is_skip(idx) {
return plman.GetPlaylistName(idx).toLowerCase() == "skip";
}
function on_playlist_items_added(p) {
if (playlist_name_is_skip(p))
t = tracks_to_skip();
}
function on_playlist_items_removed(p) {
if (playlist_name_is_skip(p))
t = tracks_to_skip();
}
So this has worked great all this time but I've come across an issue with a track named similarly to another. I have an album where I've split the last track into two tracks since the second half is basically a spoken word segment. I'm wanting to skip the second split track but it continues to be played automatically.
The original title tag is named
Mortal Man. The title tags of the split are named
Mortal Man [part 1] and
Mortal Man [part 2], and the original, unedited track from which these were split from has been hidden in File Explorer so it doesn't appear in fb2k. Apart from that title tag change the only other differences between the tracks are the track numbers (I increased the track number counter by one for the second split), and the filenames (which have been updated with the track number and title tag changes). The Total Tracks tags of all tracks remain the same.
Any idea why the second split track is being played and not skipped, despite appearing in the Skip playlist?
Tags are irrelevant. The script only checks the full file path.
Tags are irrelevant. The script only checks the full file path.
Have any thoughts on why the second split track wouldn't be detected in that case, given it has a different filename?
The split tracks appear as the following (artist and album removed here for brevity, though there's no Unicode in the path fwiw):
16 - Mortal Man [part 1].flac17 - Mortal Man [part 2].flac <- track I'd like to skip
Tested and found the
[part 1] track
is correctly skipped, just not the second part of the split track.
Update: found that removing the track from the Skip playlist then re-adding it by dragging it into the playlist again fixed the issue. Strange but at least I know what to try next time.
You can restore the function but modify it slightly...
On play a new track, still can not automatically refresh the cover, need to manually refresh or about 20 seconds automatically display the cover of the new track. I might not understand what you say, just copy and paste, thanks for the Guide, I will continue to use the old version.
Strange but at least I know what to try next time.
Well I can't really explain that. I added timers and found it can parse 2000 tracks in 0.007 seconds so the chances of you manually doing something quicker than it can catch up seems unlikely. However, I did find removing the playlist named skip didn't update the list of items to skip so you should add this to the end of the script...
function on_playlists_changed() {
t = tracks_to_skip();
}
edit: I've updated it so it takes subsong in to account should you have any cuesheets or tracks with multiple chapters. The old script would skip all tracks sharing the same path. I guess all your tracks are single otherwise you would have complained but it's something I should have added originally. It also spams the console with how long it takes to parse the items..
var t = tracks_to_skip();
function on_playback_new_track() {
var handle = fb.GetNowPlaying();
if (!handle)
return;
var p = handle.Path.toLowerCase() + "|" + handle.Subsong;
for (var i = 0; i < t.length; i++) {
if (t[i] == p)
return fb.Next();
}
}
function tracks_to_skip() {
var a = [];
for (var i = 0; i < plman.PlaylistCount; i++) {
if (playlist_name_is_skip(i)) {
var b = new Date().getTime();
var items = plman.GetPlaylistItems(i);
for (var j = 0; j < items.Count; j++) {
a.push(items.Item(j).Path.toLowerCase() + "|" + items.Item(j).Subsong);
}
items.Dispose();
var c = new Date().getTime();
fb.trace("Found a playlist named skip - parsing " + a.length + " items took " + ((c - b) / 1000) + " seconds.");
}
}
return a;
}
function playlist_name_is_skip(idx) {
return plman.GetPlaylistName(idx).toLowerCase() == "skip";
}
function on_playlist_items_added(p) {
if (playlist_name_is_skip(p))
t = tracks_to_skip();
}
function on_playlist_items_removed(p) {
if (playlist_name_is_skip(p))
t = tracks_to_skip();
}
function on_playlists_changed() {
t = tracks_to_skip();
}
another edit: I suppose there is a possibility of a track being missed (not skipped) if you send a track to a new playlist and it begins playback immediately. I guess that could happen while the list is being updated. A workaround would be to be to update the list every time a new track begins but that seems a bit overkill for most cases.
On play a new track
The code inside both components is identical for on_playback_new_track.
.
Thanks for looking into it. Updated the script and bookmarked for future reference :)
The code inside both components is identical for on_playback_new_track.
Embarrassed, :-[ ,forgive my poor English. I mean, after modify the code as you said, when I play a new track, still can not automatically refresh the cover, need to manually refresh or about 20 seconds automatically display the cover of the new track.
My previous post wasn't any kind of explanation for why it doesn't work for you. It was a simple statement of fact saying that the component works in exactly the same way when a new track begins.
Also, it works fine for me.... this gif is quite large though (12MB)..
http://imgur.com/Ut0bYbt
Also, it works fine for me...
My cover panel still can't be displayed immediately. In jscript_panel, on_metadb_changed and on_selection_changed return metadb values are not normal.
https://1drv.ms/i/s!AnFvs7Iqm0IrgdwWZLaNe1H7bYrMnA
Another question, can you fix the JSSP to allow it to support the 'Prefences>Display>Selection viewers'?
I need a little help with a script problem I have. How can I modify the replay gain data for a track from within a script?
Thanks in advance for your time.
@always.beta, read...
https://github.com/19379/foo-jscript-panel/blob/master/CHANGELOG.md#v121
and
https://github.com/19379/foo-jscript-panel/blob/b2c6698b544958741abf9ea0cf5cac000c33ae4a/component/docs/Callbacks.txt#L146L147
@Black_Over_Bills_Mothers, you can't.
@marc2003. Thanks for your quick answer. At least I didn't waste too much time trying to find a way to modify the ReplayGain data!
I have another problem. I've recently downloaded some tracks with their Read-only flag set. This obviosly causes several file update functions to fail. Is there a way to, ideally remove the read-only flag, or at least detect it with utils.FileTest (possible additional mode)?
You can use the WshShell ActiveX object to run external commands.
edit: using fso as below is better
Thanks marc2003.
I've just this minute got a solution working with a file system object. Seems to work fine.
Ah yes, using fso is much better. 8)
Last.fm have updated their website to use https therefore the scripts need to be updated. Edit your text.js/thumbs.js files and replace http with https.
text.js
var url = "https://" + this.bio_lastfm_sites[this.bio_lastfm_site] + "/music/" + encodeURIComponent(this.artist) + "/+wiki";
thumbs.js
this.xmlhttp.open("GET", "https://www.last.fm/music/" + encodeURIComponent(this.artist) + "/+images", true);
latest version here. there are no such lines in these files. can't get biography to work anymore, due to „Last.fm Bio: HTTP error: 0”. any help?
reminderedit with solution for idiots like me:
these files are located at *user_name*\AppData\Roaming\foobar2000\js_marc2003\js if installed version is standalone (not portable)
I gave up WSH Cover Panel, switch to 'complete\album art.txt'.
Could you consider making these changes? change the (\complete\album art.txt)'s right menu Google image search to two level menu? Like:WSH Cover Panel, the search source is defined in a separate text. Easy to modify the search source and do not affect the search source when the main code updates. the right menu can be added to some attached pictures menu?
Help please. Is it possible to have two buttons on toolbar "set volume to -10db" and "set volume to -30db" with this component?
Thank you!
Well you can't add toolbars in default UI but here's a custom panel with 2 buttons...
// ==PREPROCESSOR==
// @name "SimpleThemedButton"
// @author "T.P Wang"
// @import "%fb2k_component_path%docs\flags.txt"
// @import "%fb2k_component_path%docs\helpers.txt"
// ==/PREPROCESSOR==
var cur_btn = null;
var g_down = false;
var g_theme = window.CreateThemeManager("Button");
var g_font = gdi.Font("Segoe UI", 12);
var ButtonStates = {
normal: 0,
hover: 1,
down: 2,
hide: 3
}
var buttons = {
v30: new SimpleButton(10, 10, 80, 26, "-30 dB", function () {
fb.Volume = -30;
}),
v10: new SimpleButton(100, 10, 80, 26, "-10 dB", function () {
fb.Volume = -10
})
}
function SimpleButton(x, y, w, h, text, fonClick, state) {
this.state = state ? state : ButtonStates.normal;
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.text = text;
this.fonClick = fonClick;
this.containXY = function (x, y) {
return (this.x <= x) && (x <= this.x + this.w) && (this.y <= y) && (y <= this.y + this.h);
}
this.changeState = function (state) {
var old = this.state;
this.state = state;
return old;
}
this.draw = function (gr) {
if (this.state == ButtonStates.hide) return;
switch (this.state)
{
case ButtonStates.normal:
g_theme.SetPartAndStateId(1, 1);
break;
case ButtonStates.hover:
g_theme.SetPartAndStateId(1, 2);
break;
case ButtonStates.down:
g_theme.SetPartAndStateId(1, 3);
break;
case ButtonStates.hide:
return;
}
g_theme.DrawThemeBackground(gr, this.x, this.y, this.w, this.h);
// RGB function is defined in docs\helpers.txt
// DT_* are defined in docs\flags.txt
gr.GdiDrawText(this.text, g_font, RGB(0,0,0), this.x, this.y, this.w, this.h, DT_CENTER| DT_VCENTER | DT_CALCRECT | DT_NOPREFIX);
}
this.onClick = function () {
this.fonClick && this.fonClick();
}
}
function drawAllButtons(gr) {
for (var i in buttons) {
buttons[i].draw(gr);
}
}
function chooseButton(x, y) {
for (var i in buttons) {
if (buttons[i].containXY(x, y) && buttons[i].state != ButtonStates.hide) return buttons[i];
}
return null;
}
function on_paint(gr) {
gr.FillSolidRect(0, 0, window.Width, window.Height, utils.GetSysColor(15));
drawAllButtons(gr);
}
function on_mouse_move(x, y) {
var old = cur_btn;
cur_btn = chooseButton(x, y);
if (old == cur_btn) {
if (g_down) return;
} else if (g_down && cur_btn && cur_btn.state != ButtonStates.down) {
cur_btn.changeState(ButtonStates.down);
window.Repaint();
return;
}
old && old.changeState(ButtonStates.normal);
cur_btn && cur_btn.changeState(ButtonStates.hover);
window.Repaint();
}
function on_mouse_leave() {
g_down = false;
if (cur_btn) {
cur_btn.changeState(ButtonStates.normal);
window.Repaint();
}
}
function on_mouse_lbtn_down(x, y) {
g_down = true;
if (cur_btn) {
cur_btn.changeState(ButtonStates.down);
window.Repaint();
}
}
function on_mouse_lbtn_up(x, y) {
g_down = false;
if (cur_btn) {
cur_btn.onClick();
cur_btn.changeState(ButtonStates.hover);
window.Repaint();
}
}
OMG! Huge props! I can't PM you :( Could you send me your Paypal? You should have donation button!
One more question, is it possible to assign a hotkeys to these custom buttons?
Not really. The component can accept keyboard input but only when the panel has focus. Click anywhere else on the foobar UI or any other program and the panel loses focus meaning keyboard shortcuts no longer work.
I have an idea of how to make it possible but it's highly convoluted and I'm not really sure if it's worth the effort.
Not really. The component can accept keyboard input but only when the panel has focus. Click anywhere else on the foobar UI or any other program and the panel loses focus meaning keyboard shortcuts no longer work.
I have an idea of how to make it possible but it's highly convoluted and I'm not really sure if it's worth the effort.
It's not worth, you're right. Thank you one more time for your answers and customized buttons!
It's now possible with the latest component version released just now. Here's the code snippet to go in your panel..
function on_main_menu(index) {
switch (index) {
case 1: // triggered when File>JScript Panel>1 is run
fb.Volume = -30;
break;
case 2: // triggered when File>JScript Panel>2 is run
fb.Volume = -10;
break;
}
}
You then have to bind commands 1 & 2 under File>JScript Panel to your keyboard shortcuts in the main preferences...
(https://i.imgur.com/c6XqsBp.png)
It's just a brilliant! Working absolutely fantastically!
jsplaylist-mod. Change requests:
I'm not sure who is now maintaining this script but I've just started using it as an alternative to ELPlaylist and it seems a lot quicker.
There are a few things I miss though:
1) Focus the display on a particular playlist
2) Don't show the extra line for each track if none of the columns are displaying anything in it ie all set to null
3) Don't collapse the list if the number of groups is less than a configurable number
Thanks to anyone prepared to implement these.
I don't understand the code well enough to make those sorts of changes. I can fix things I break with my component updates but that's about it.
@marc2003 Is it possible for the switcher script to use one single button to cycle through scripts or does it have to be one per script?
It's just this function that does the important bit...
window.NotifyOthers(name, info);
How you determine the name and info is entirely up to you.
Long time lurker, first time poster - I just wanted to thank marc2003 for developing and maintaining this incredibly useful plugin.
I was playing around with the album art jscript panel and I noticed the picture is cropped around the sides compared to the default UI album art panel. Is there anything I can do to adjust this setting?
I've tweaked it so the "Centre" and "Stretch" options no longer get trimmed. The "Crop" and "Crop Top" still get trimmed but by a lesser amount. Save this inside your foobar2000 profile\user-components\foo_jscript_panel\samples\complete\js (overwrite the existing helpers.js)
https://raw.githubusercontent.com/19379/foo-jscript-panel/master/component/samples/complete/js/helpers.js
You can use GetColorScheme like this...
var img = utils.GetAlbumArtV2(fb.GetFocusItem(), 0);
if (img) {
var arr = img.GetColorScheme(1).toArray();
var col = arr[0];
}
You can increase the number 1 to get more colours. The first is the most dominant and so on...
I'm trying to use this GetColorScheme function, but it gives me a 10-digit number. How do I convert it to RGB values?
You can use GetColorScheme like this...
var img = utils.GetAlbumArtV2(fb.GetFocusItem(), 0);
if (img) {
var arr = img.GetColorScheme(1).toArray();
var col = arr[0];
}
You can increase the number 1 to get more colours. The first is the most dominant and so on...
I'm trying to use this GetColorScheme function, but it gives me a 10-digit number. How do I convert it to RGB values?
Alright, I managed with Falstaff's GetColorSchemFromImage function.
Is it possible to get windows 10 accent color with jscript?
Is it possible to get windows 10 accent color with jscript?
Eventually I found out the custom windows accent color is stored in the ColorizationColor registry key in HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\DWM, therefore I managed to get it with the RegRead method.
I can't find a registry key for the taskbar color, though, so I guess it must be a darker shade of the accent color. Is there a formula to get the taskbar color from the accent color?
Is it possible to get windows 10 accent color with jscript?
Eventually I found out the custom windows accent color is stored in the ColorizationColor registry key in HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\DWM, therefore I managed to get it with the RegRead method.
I can't find a registry key for the taskbar color, though, so I guess it must be a darker shade of the accent color. Is there a formula to get the taskbar color from the accent color?
For those who are interested, I found out all shades and tints of the accent color are stored in the registry key
AccentPalette in HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Accent. The taskbar color is the 6th in the list when the transparency option is off and the 7th when it is on. Unfortunately the RegRead method does not seem to work with this registry key and I have no idea how to get its value. Any help would be appreciated.
If you look at the type of the value in regedit, it's REG_BINARY and if you look at the documentation for it here...
https://msdn.microsoft.com/en-gb/library/x05fawxd(v=vs.84).aspx
... it says it's a VBarray. Therefore you can try using toArray() on the result..
var something = WshShell.RegRead("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Accent\\AccentPalette").toArray();
edit: Since I'm feeling nice, I found out how...
function RGB(r, g, b) {
return 0xFF000000 | r << 16 | g << 8 | b;
}
var WshShell = new ActiveXObject("WScript.Shell");
var colours = WshShell.RegRead("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Accent\\AccentPalette").toArray();
var colour = RGB(colours[20], colours[21], colours[22]);
function on_paint(gr) {
gr.FillSolidRect(0, 0, window.Width, window.Height, colour);
}
edit: Since I'm feeling nice, I found out how...
Thanks, it worked! Glad you're feeling nice :)
What is the best way to get a list of all values in a specific field? For example, how can I get a list of all artists in my music library (or in a playlist)?
I've been looking in Falfstaff's and Wilb's library browser scripts, but they are far too complex for me to extrapolate the code I'm looking for.
I tried with some loops, but all I got was foobar2000 unresponsive.
// ==PREPROCESSOR==
// @import "%fb2k_component_path%samples\complete\js\lodash.min.js"
// @import "%fb2k_component_path%samples\complete\js\helpers.js"
// ==/PREPROCESSOR==
var tag = "artist"; //don't use %%
var tags = [];
var items = fb.GetQueryItems(fb.GetLibraryItems(), tag + " PRESENT");
for (var i = 0; i < items.Count; i++) {
var num = _.tf("$meta_num(" + tag + ")", items.Item(i));
for (var j = 0; j < num; j++) {
tags.push(_.tf("$meta(" + tag + "," + j + ")", items.Item(i)));
}
}
items.Dispose();
fb.ShowPopupMessage(_.uniq(tags.sort(), true).join("\n"));
// ==PREPROCESSOR==
// @import "%fb2k_component_path%samples\complete\js\lodash.min.js"
// @import "%fb2k_component_path%samples\complete\js\helpers.js"
// ==/PREPROCESSOR==
var tag = "artist"; //don't use %%
var tags = [];
var items = fb.GetQueryItems(fb.GetLibraryItems(), tag + " PRESENT");
for (var i = 0; i < items.Count; i++) {
var num = _.tf("$meta_num(" + tag + ")", items.Item(i));
for (var j = 0; j < num; j++) {
tags.push(_.tf("$meta(" + tag + "," + j + ")", items.Item(i)));
}
}
items.Dispose();
fb.ShowPopupMessage(_.uniq(tags.sort(), true).join("\n"));
Thanks for the script. What is the meaning of the underscore syntax? I often see it in your scripts, but couldn't find any reference.
On the 2nd line of the example above, you'll see I import a file name lodash.min.js - don't try and read it because it's minified (https://en.wikipedia.org/wiki/Minification_(programming)) but lodash is a javascript library containing lots of useful functions that I use throughout my scripts.
I have to use an older version (3.10.1) which is compatible with windows script host used by the component. All the functions are documented here....
https://lodash.com/docs/3.10.1
Just to confuse things, it also lets you add your own functions which can be called using _.functionName so there are plenty of those throughout my scripts as well. These are not documented anywhere but most are defined inside helpers.js starting here...
https://github.com/19379/foo-jscript-panel/blob/master/component/samples/complete/js/helpers.js#L103
In that previous snippet, _.tf is my own custom function defined here...
https://github.com/19379/foo-jscript-panel/blob/master/component/samples/complete/js/helpers.js#L571
whereas _.uniq is part of lodash itself which is documented here...
https://lodash.com/docs/3.10.1#uniq
Is there a way to identify a playlist regardless of the index or playlist name?
Feature request (forgive me if this has already been asked):
Is it possible to include support in a future version of JScript Panel for high-resolution monitors when viewing tooltip messages (the messages that appear when you hover over an object with a text caption)?
My new laptop has a 4k screen, which makes viewing these hover messages difficult.
The component supports custom fonts/sizes for tooltips but each script would need updating. If you were using my scripts, you need to open
samples\complete\js\helpers.js and edit line 51..
var tooltip = window.CreateTooltip();
so it becomes
var tooltip = window.CreateTooltip("Segoe UI", 20, 0);
The 20 is the font size in pixels and the 0 is style. You can change that to 1 if you want a bold font.
Using any other script, you need to edit window.CreateTooltip as above. It should appear only once in any script do don't just add it.
Is it DPI aware? That may be the issue they're experiencing.
No it isn't. It's entirely up to script authors if they want to cater for this sort of thing. I believe the registry can be queried to get the current DPI setting with WshShell..
var WshShell = new ActiveXObject("WScript.Shell");
var blah = WshShell.RegRead("HKCU\\....");
Here's a silly example with an extreme tooltip size made with the changes I mentioned in the previous post.
(https://i.imgur.com/nGhiGBq.jpg)
Well, it is true, most people still have 1080p or less screens. The rest can ask their favorite script authors to add HiDPI support to their scripts.
E: And for a second, I thought you posted a High DPI image, but the forum just shrank it with tags, until it was slightly larger than its physical resolution on my display.
That was my 2560x1440 desktop at 200%. As you can see, the rest of the destop and default UI elements are respecting it - the only things that aren't are my scripts. However, I'm working on adding DPI support for them to the next release so casual users won't have to edit scripts.
// ==PREPROCESSOR==
// @import "%fb2k_component_path%samples\complete\js\lodash.min.js"
// @import "%fb2k_component_path%samples\complete\js\helpers.js"
// ==/PREPROCESSOR==
var tag = "artist"; //don't use %%
var tags = [];
var items = fb.GetQueryItems(fb.GetLibraryItems(), tag + " PRESENT");
for (var i = 0; i < items.Count; i++) {
var num = _.tf("$meta_num(" + tag + ")", items.Item(i));
for (var j = 0; j < num; j++) {
tags.push(_.tf("$meta(" + tag + "," + j + ")", items.Item(i)));
}
}
items.Dispose();
fb.ShowPopupMessage(_.uniq(tags.sort(), true).join("\n"));
What does the Dispose method exactly do? Same question for all the dispose methods listed in the interfaces.txt document. I tried executing the script without that last-but-one line and nothing seems to change.
BTW are the methods mentioned in the interfaces.txt better defined in some other document?
docs\Notes & hints
https://github.com/19379/foo-jscript-panel/blob/master/foo_jscript_panel/docs/Notes%20%26%20Hints.txt#L8L9
and nope!
Can someone help me to adjust Br3tt's JS Smooth Browser script so that it works off of Album Artist instead of Artist? I don't want it splitting up all my compilation albums and split EPs.
Thanks!
@marc2003 Is there a quick way to change the font selection sizes for your sample scripts? Currently the options are 10, 12, 14, 16. Am looking to change to smaller intervals 10, 11, 12, 13 I tried looking into helpers.js and panels.js but couldn't find anything there.
Also, can type font and/or color font be changed?
Can someone help me to adjust Br3tt's JS Smooth Browser script so that it works off of Album Artist instead of Artist? I don't want it splitting up all my compilation albums and split EPs.
tf_groupkey_artist: fb.TitleFormat("$if2($meta(album artist,0),Unknow Artist)"),
works for me.
Hi marc2003
I use your panel with a script to process new music files . I've got a working version but with a few annoying issues. I wonder if you can help;
1) I use thr RunContextComandWithMetadb to replay/gain a playlist selection, remove all embedded images and to optimise file layout and minimise file size. But these commands do not wait for completion. I have to catch the generated event to ensure the command has completed. Can we have a version of this command that blocks until completed?
2) Some of the commands above, such as remove images and optimise files, generate user interface prompts. Can these be bypassed in any way?
Once again thanks for your efforts in giving us the capability to customise foobar so much. ANy help greatfully appreciated.
The component supports custom fonts/sizes for tooltips but each script would need updating.
Thanks, I'll give this a try!
Is it DPI aware? That may be the issue they're experiencing.
Yes, this is what I was asking about, actually. If there's no support for this, then I'm happy to use the directions that marc2003 suggested.
My own samples in the complete folder are now DPI aware for text/tooltips etc.
https://github.com/19379/foo-jscript-panel/releases
@marc2003 Typo at line 15 with foo-jscript-panel/foo_jscript_panel/samples/complete/musicbrainz.txt.
Argh, thanks for spotting.
If anyone has this problem, it should be...
var panel = new _.panel('Musicbrainz', ['metadb']);
Hi Guys,
New to this Foobar thing, but it appeals to me because of the seemingly endless skinning possibilities, thanks due in no small part to all those clever guys who made the components/dlls etc allowing mortals like me to hook into.
I have searched the forums over the last few days but have not been able to find any posts that could point me towards a solution to my problem.
What I would like to do is close the "Console" and "Preferences" dialogs through a button on my JScript panel. I can open these dialogs easily through,
fb.RunMainMenuCommand("View/Console"); and
fb.RunMainMenuCommand("File/Preferences");
but cannot find an equivalent to close them by toggling my buttons.
Have I missed something obvious or is going to be a matter of some serious scripting?
Any pointers would be gratefully received.
Apologies if this has been raised before and I have missed the solution in the my search of the forums!
Cheers
mph64
Calling @TheQwertiest - their modified component might be able to do this, mine can't.
It seems I've been a bit careless with the last few sample updates. Some silly bugs have crept in which I can only apologise for. I'll try and test a bit more thoroughly for next time. It looks like I broke tooltips in the album art script and my attempts at DPI support in the track info +seekbar+buttons script was half baked. :/
marc2003, where are the options regarding font size and font name stored in your scripts? What would be the easiest way to modify/override them if I only want a specific font and size for the panel below?
// ==PREPROCESSOR==
// @name "Last.fm Similar Artists / User Charts"
// @author "marc2003"
// @import "%fb2k_component_path%samples\complete\js\lodash.min.js"
// @import "%fb2k_component_path%samples\complete\js\helpers.js"
// @import "%fb2k_component_path%samples\complete\js\panel.js"
// @import "%fb2k_component_path%samples\complete\js\list.js"
// @import "%fb2k_component_path%samples\complete\js\lastfm.js"
// ==/PREPROCESSOR==
// Requires the "Guifx v2 Transports.ttf" font which can be downloaded from
// http://blog.guifx.com/2009/04/02/guifx-v2-transport-font/
var panel = new _.panel('Last.fm Similar Artists / User Charts', ['metadb']);
var lastfm = new _.lastfm();
var list = new _.list('lastfm_info', LM, TM-35, 0, 0);
panel.item_focus_change();
function on_notify_data(name, data) {
lastfm.notify_data(name, data);
}
function on_size() {
panel.size();
list.w = panel.w - (LM * 2);
list.h = panel.h - TM+50;
list.size();
}
function on_paint(gr) {
panel.paint(gr);
//gr.FillSolidRect(0, 0, panel.w, TM, panel.colours.header);
//gr.GdiDrawText(list.header_text(), panel.fonts.title, panel.colours.highlight, LM, 0, panel.w - (LM * 2), TM, LEFT);
list.paint(gr);
}
function on_metadb_changed() {
list.metadb_changed();
}
function on_mouse_wheel(s) {
list.wheel(s);
}
function on_mouse_move(x, y) {
list.move(x, y);
}
function on_mouse_lbtn_up(x, y) {
list.lbtn_up(x, y);
}
function on_key_down(k) {
list.key_down(k);
}
function on_mouse_rbtn_up(x, y) {
return panel.rbtn_up(x, y, list);
}
Also, I'd like to modify the script so it would cross reference my library and would only show similar artists which I don't have yet. Any ideas?
Directly after
var panel = new _.panel('Last.fm Similar Artists / User Charts', ['metadb']);
insert
panel.fonts.normal = _.gdiFont("font name", 12, 0); // 12 size, 0 style
panel.row_height = panel.fonts.normal.Height;
Note that changes to font settings made in the main UI preferences will override this so you'd need to reload the panel.
As for the library referencing thing, possible but could bog down running 100 queries at once??? It has no effect on me because my collection is so small but could be an issue for others. You'll need to edit
samples\complete\js\list.jsOn line 424, you should find this...
this.data = _(_.get(_.jsonParse(_.open(this.filename)), 'similarartists.artist', []))
.map(function (item) {
return {
name : item.name,
width : _.textWidth(item.name, panel.fonts.normal),
url : this.lastfm_link == 0 ? item.url : 'artist HAS ' + item.name
};
}, this)
.value();
try this instead...
this.data = _(_.get(_.jsonParse(_.open(this.filename)), 'similarartists.artist', []))
.filter(function (item) {
return fb.GetQueryItems(fb.GetLibraryItems(), 'artist IS ' + item.name).Count == 0;
})
.map(function (item) {
return {
name : item.name,
width : _.textWidth(item.name, panel.fonts.normal),
url : this.lastfm_link == 0 ? item.url : 'artist HAS ' + item.name
};
}, this)
.value();
If editing while foobar is open, make sure to reload panel to pick up changes. Also, future component updates will overwrite this file so make notes or move the edited file elsewhere and edit the preprocessor import path for list.js in the Configuration window.
Thanks for the help.
Indeed the query freezes foobar for 1-3 seconds, not too severe, but not optimal either, Probably could be improved by some sort of caching or limiting the last.fm query to a smaller number (and maybe occasionally firing it twice if there aren't enough artist left after the cross reference). But for what I wanted should be good enough.
Changing the font also works. Just for reference in case someone else tries using it too, theres a typo at your second line in your second codebox, 'pane.row_height' should be 'panel.row_height'.
Also one more question, is JScript capable of writing tags? Seems like multiple people are using a convoluted method to retrieve similar artists from last.fm and then later copy its values to a multivalue tag. So I was wondering if one could automatize this with JScript alone. foo_uie_biography can do something similar (makes said data available as a tag for the currently playing song), but stuff like $meta(tag,0) don't work on the provided tag so it's not that useful. I don't really expect a code for this, I'm just curious if it's doable at all.
Edit
.take(20) on line 2...
this.data = _(_.get(_.jsonParse(_.open(this.filename)), 'similarartists.artist', []))
.take(20)
.filter(function (item) {
return fb.GetQueryItems(fb.GetLibraryItems(), 'artist IS ' + item.name).Count == 0;
})
.map(function (item) {
return {
name : item.name,
width : _.textWidth(item.name, panel.fonts.normal),
url : this.lastfm_link == 0 ? item.url : 'artist HAS ' + item.name
};
}, this)
.value();
And yes, you can edit tags with JScript Panel. If you wanted to, you could even update every single file in the library that has the same artist as the current track because obviously the similar artists would be the same. Also, it writes multi-value tags properly.
I'll post a quick and dirty example later.
This will update all library files with the same artist (determined using
$meta(artist,0) ) as the current track with the first 5 similar artists when you double click the panel. A blank area would be better than clicking on the text! Check the
tag_name variable if you want to edit it...
function on_mouse_lbtn_dblclk() {
if (list.lastfm_mode != 0 || list.items == 0)
return;
var tags = _(list.data)
.take(5)
.map('name')
.value()
.join(';');
var tag_name = 'similar artists';
var items_to_tag = fb.GetQueryItems(fb.GetLibraryItems(), 'NOT "$ext(%path%)" IS cue AND "$meta(artist,0)" IS ' + list.artist);
if (WshShell.popup('About to update tags in ' + items_to_tag.Count + ' file(s). Continue?', 0, panel.name, popup.question + popup.yes_no) == popup.yes)
items_to_tag.UpdateFileInfoSimple(tag_name, tags, tag_name);
}
It will count the files and prompt you first. If you want it to happen automatically without the prompt, remove this line...
if (WshShell.popup('About to update tags in ' + items_to_tag.Count + ' file(s). Continue?', 0, panel.name, popup.question + popup.yes_no) == popup.yes)
If you really want to do one track at a time...
function on_mouse_lbtn_dblclk() {
if (list.lastfm_mode != 0 || list.items == 0)
return;
var tags = _(list.data)
.take(5)
.map('name')
.value()
.join(';');
var tag_name = 'similar artists';
panel.metadb.UpdateFileInfoSimple(tag_name, tags, tag_name);
}
Seems to be working well.
I took the liberty to also hook up on_playback_new_track() or on_playback_starting() with your last script. However both seems to only trigger the tag writing process after you switch away from the track in question (so it basically always updates the previous track when playback has started on a new one). Is there one that triggers right away or am I doing something fundamentally wrong?
(The goal with this one is to update the currently playing track automatically, similarly how foo_uie_biography works. With the modified list.js that only shows similar artists not yet in library I feel this might better in terms of always showing up to date info. Compared to one batch operation of every file, which would probably work better with the regular lists.js getting all similar artists that should be fairly consistent over time. It's possible there will also be a conflict between the component waveform seekbar which seems to "lock" the files while it's scanning them the first time, we'll see. That can probably be solved by delaying the writing process a couple seconds.)
function on_playback_new_track() {
if (list.lastfm_mode != 0 || list.items == 0)
return;
var tags = _(list.data)
.take(5)
.map('name')
.value()
.join(';');
var tag_name = 'similar artists';
panel.metadb.UpdateFileInfoSimple(tag_name, tags, tag_name);
}
Can someone please help be with a button to launch the VMDGB webpage for an album based on the tag %vmgdb%
http://vgmdb.net/album/%vmgdb%
I would like the button to use a PNG graphic. It would be awesome if the graphic could change if the %vmgdb% tag is empty (I would use a grayed-out version of the button image so it looks disabled).
If anyone has code for a similar button (for loading a URL using a tag value), I can adapt it to fit my needs. I just didn't find anything in the Samples folder.
Thanks :)
or am I doing something fundamentally wrong?
Yes. you've overwritten an already existing
on_playback_new_track function in panel.js and completely broken the script's ability to update when a new track starts. If any duplicate functions exist in javascript, the last always takes precedence so you need to include code from the old function. Also, a timer is required to make it work properly because it can take a second or 2 for the web request to complete on new tracks or updating when the cached data is over a day old. I've allowed 5 seconds. You can place this inside the Configuration window...
function on_playback_new_track() {
panel.item_focus_change(); //required code from old function
if (list.timer)
window.ClearTimeout(list.timer);
list.timer = window.SetTimeout(function () {
if (list.lastfm_mode != 0 || list.items == 0)
return;
var tags = _(list.data)
.take(5)
.map('name')
.value()
.join(';');
var tag_name = 'similar artists';
try {
panel.metadb.UpdateFileInfoSimple(tag_name, tags, tag_name);
} catch (e) {}
}, 5000);
}
Mr Bean...
// ==PREPROCESSOR==
// @import "%fb2k_component_path%samples\complete\js\lodash.min.js"
// @import "%fb2k_component_path%samples\complete\js\helpers.js"
// @import "%fb2k_component_path%samples\complete\js\panel.js"
// ==/PREPROCESSOR==
var panel = new _.panel('Button', ['metadb', 'custom_background']);
var buttons = new _.buttons();
var off = fb.ProfilePath + "my_images\\off.png"; // edit the folder/image names as needed
var on = fb.ProfilePath + "my_images\\on.ong";
function on_size() {
panel.size();
}
function on_metadb_changed() {
if (panel.metadb) {
var vmgdb = panel.tf("[%vmgdb%]");
//firt 4 values are x,y,w,h
buttons.buttons.vmgdb = new _.button(0, 0, 20, 20, { normal : vmgdb.length ? on : off }, function () {
if (!vmgdb.length)
return; // do nothing if tag is empty
_.run('http://vgmdb.net/album/' + vmgdb);
}, 'VMGDB');
} else {
buttons.buttons = {}
}
window.Repaint();
}
function on_paint(gr) {
panel.paint(gr);
buttons.paint(gr);
}
function on_mouse_move(x, y) {
buttons.move(x, y);
}
function on_mouse_leave() {
buttons.leave();
}
function on_mouse_lbtn_up(x, y) {
buttons.lbtn_up(x, y);
}
function on_mouse_rbtn_up(x, y) {
return panel.rbtn_up(x, y);
}
Woot! Thanks mark2003.
Sadly, I get an error:
JScript Panel ({FA8128A9-B8F6-4599-AD1F-C6E6D5BBEF0C})
JavaScript runtime error:
'panel' is undefined
File: <main>
Line: 17, Col: 2
<source text only available at compile time>
It looks like you installed the dll only without the required files contained within the archive. I do give this link on the installation page for a reason...
http://wiki.hydrogenaud.io/index.php?title=Foobar2000:How_to_install_a_component
edit: or you could be using a pretty old version that didn't come with samples. Use the Help menu>Check for updated components.
Hmm, I didn't use the install, but I did copy all the files from the archive, not just the dll.
I deleted it and used the install, it's working now. Thanks again :)
@marc2003 , quick question about Musicbrainz script. Is is possible for it to check the currently selected artist, and compare album names in our library with musicbrainz info, for releases we already have in our library. And use different font colour, or style, or basically any kind of formatting, for those releases? Extra text, like "in library", next to it, or simple check mark, would work too.
Guessing, but tagging our library with musicbrainz album ID would help there?
Also, left click now gets us to release-group of the album, could it be edited (or small search button added next to releases) that it uses outside pages like google, itunes, spotify, whatever site really, for album search? Links option via right click gives us artist related pages.
I see marc2003, thanks for the help.
It appears that this edit (https://hydrogenaud.io/index.php/topic,110516.msg944334.html#msg944334) results in a crash in the similar artist panel if %artist% is Hidekuni Horita. As long as a letter is changed everything is fine and other metadata doesn't seem to contribute. It also works fine with the unedited list.js. Not really sure why.
JScript Panel (Last.fm Similar Artists / User Charts by marc2003)
JavaScript runtime error:
File: foobar2000\user-components\foo_jscript_panel\samples\complete\js\list.js
Line: 427, Col: 9
<source text only available at compile time>
// ==PREPROCESSOR==
// @name "Last.fm Similar Artists / User Charts"
// @author "marc2003"
// @import "%fb2k_component_path%samples\complete\js\lodash.min.js"
// @import "%fb2k_component_path%samples\complete\js\helpers.js"
// @import "%fb2k_component_path%samples\complete\js\panel.js"
// @import "%fb2k_component_path%samples\complete\js\list.js"
// @import "%fb2k_component_path%samples\complete\js\lastfm.js"
// ==/PREPROCESSOR==
// Requires the "Guifx v2 Transports.ttf" font which can be downloaded from
// http://blog.guifx.com/2009/04/02/guifx-v2-transport-font/
var panel = new _.panel('Last.fm Similar Artists / User Charts', ['metadb']);
panel.fonts.normal = _.gdiFont("Segoe UI", 8, 0); // 12 size, 0 style
panel.row_height = panel.fonts.normal.Height;
var lastfm = new _.lastfm();
var list = new _.list('lastfm_info', LM, TM-36, 0, 0);
panel.item_focus_change();
function on_notify_data(name, data) {
lastfm.notify_data(name, data);
}
function on_size() {
panel.size();
list.w = panel.w - (LM * 2);
list.h = panel.h - TM+60;
list.size();
}
function on_paint(gr) {
panel.paint(gr);
//gr.FillSolidRect(0, 0, panel.w, TM, panel.colours.header);
//gr.GdiDrawText(list.header_text(), panel.fonts.title, panel.colours.highlight, LM, 0, panel.w - (LM * 2), TM, LEFT);
list.paint(gr);
}
function on_metadb_changed() {
list.metadb_changed();
}
function on_mouse_wheel(s) {
list.wheel(s);
}
function on_mouse_move(x, y) {
list.move(x, y);
}
function on_mouse_lbtn_up(x, y) {
list.lbtn_up(x, y);
}
function on_key_down(k) {
list.key_down(k);
}
function on_mouse_rbtn_up(x, y) {
return panel.rbtn_up(x, y, list);
}
function on_mouse_lbtn_dblclk() {
if (list.lastfm_mode != 0 || list.items == 0)
return;
var tags = _(list.data)
.take(5)
.map('name')
.value()
.join(';');
var tag_name = 'similar artists';
panel.metadb.UpdateFileInfoSimple(tag_name, tags, tag_name);
}
What I would like to do is close the "Console" and "Preferences" dialogs through a button on my JScript panel. I can open these dialogs easily through,
fb.RunMainMenuCommand("View/Console"); and
fb.RunMainMenuCommand("File/Preferences");
Calling @TheQwertiest - their modified component might be able to do this, mine can't.
TLDR: Regretfully, there is no easy way to do that, even with WSH methods. There is a messy solution though:
// foobar2000
var FbWnd = wsh_utils.GetWndByHandle(window.ID).GetAncestor(2);
// dekstop
var DesktopWnd = FbWnd.GetAncestor(1);
function ToggleConsole()
{
// "Console" is the caption of the console window, might be localized by foobar2000
var consoleWnd = DesktopWnd.GetChild("Console", "{483DF8E3-09E3-40d2-BEB8-67284CE3559F}",0);
if (consoleWnd)
{
wsh_utils.CloseWnd(consoleWnd);
}
else
{
fb.RunMainMenuCommand("View/Console");
}
}
function TogglePreferences()
{
// "Preferences: Components (foobar2000.exe)" is the caption of the pref window, might be localized by foobar2000
var prefWnd = DesktopWnd.GetChild("Preferences: Components (foobar2000.exe)","#32770",0);
if (prefWnd)
{
wsh_utils.CloseWnd(prefWnd);
}
else
{
fb.RunMainMenuCommand("File/Preferences");
}
}
Full story: it seems, that foobar2000 creates Console and Preferences windows as separate entities, i.e. they do not have parent-child relationship with foobar2000. Thus, the only way to get those windows is via searching all top level windows, with specific caption and class, since there might be a collision in Caption with other windows.
If there was a proper parent-child relationship, we could get away with Caption only, since there is not a lot of windows in foobar2000 itself.
@marc2003 : Can I post a link to my version of jscript here? Or should I share it only privately (i.e. PM, e-mail, etc)?
@OoNebsoO, right click panel>links should give itunes/spotify links for most established artists. You could always contribute to musicbrainz if you find they are missing. I'm not querying the library for releases for performance reasons and I'm not really inclined to add any other options at the moment.
@Daeron , shame I didn't read my own docs when implementing that edit. I know that function can throw errors with invalid queries and I forgot to handle it properly.
.filter(function (item) {
try {
return fb.GetQueryItems(fb.GetLibraryItems(), 'artist IS "' + item.name + '"').Count == 0;
} catch (e) {
return true;
}
})
@TheQwertiest, you can post a link to your component, no problem.
However, I don't think it will work for preferences because the caption changes every time you select a different item in the tree. Also
(foobar2000.exe) is only provided by that banned component we can't really name. And that changes to what ever component provides the option you have selected.
Thanks for the fix marc2003.
Is it possible to write more than one proper multivalue tag in one go & if so what's the syntax?
The following didn't seem to work:
handle.UpdateFileInfoSimple("GENRE1", "Downtempo;Ambient", "GENRE1","GENRE2", "Rock;Classic Rock", "GENRE2");
Other variances I tried either only wrote one tag else only one was correctly written as a multivalue tag.
I actually want to write 5 multivalue tags at a time. UpdateFileInfoSimple can be run separately for each, but that then seems to rewrite the file 5 times, and so isn't ideal for many files.
Any help would be appreciated.
I thought the existing docs were clear enough... ?? :P
UpdateFileInfoSimple(field1, value1 [, field2, value2 [,...] ] [, multivalue_fields]);
if value is an empty string, field will be removed
multivalue_fields is a semicolon-separated list containing field names which need to be treated as multivalue.
So you want something like...
handle.UpdateFileInfoSimple("GENRE1", "Downtempo;Ambient", "GENRE2", "Rock;Classic Rock", "GENRE1;GENRE2");
Remember you can use UpdateFileInfoSimple on a handle list as well.
What I would like to do is close the "Console" and "Preferences" dialogs through a button on my JScript panel. I can open these dialogs easily through,
fb.RunMainMenuCommand("View/Console"); and
fb.RunMainMenuCommand("File/Preferences");
Here is updated code and the modded component foo_jscript_panel-v1.2.3.3[modded] (https://www.mediafire.com/file/5ygpu775n5sjp72/foo_jscript_panel.dll) (make a backup of existing one, before replacing though)
// foobar2000
var FbWnd = wsh_utils.GetWndByHandle(window.ID).GetAncestor(2);
// dekstop
var DesktopWnd = FbWnd.GetAncestor(1);
function ToggleConsole()
{
// "Console" is the caption of the console window, might be localized by foobar2000
var consoleWnd = DesktopWnd.GetChildWithSameProcess(FbWnd,"Console", "{483DF8E3-09E3-40d2-BEB8-67284CE3559F}");
if (consoleWnd)
{
wsh_utils.CloseWnd(consoleWnd);
}
else
{
fb.RunMainMenuCommand("View/Console");
}
}
function TogglePreferences()
{
// Might have collision with other windows within fb2k that have "#32770" as the base class.
var prefWnd = DesktopWnd.GetChildWithSameProcess(FbWnd,"", "#32770");
if (prefWnd)
{
wsh_utils.CloseWnd(prefWnd);
}
else
{
fb.RunMainMenuCommand("File/Preferences");
}
}
Also (foobar2000.exe) is only provided by that banned component we can't really name. And that changes to what ever component provides the option you have selected.
Heh, never knew that, since I was using
that component with fb2k from the day one =)
Quite a shame, that it was banned, since it adds so many useful features to fb2k...
Does the new method UpdateFileInfoFromJSON handle threading in a different manner as to bypass the limit the number of entries we can update in one run as discussed in the WSH panel Mod discussion ?
https://hydrogenaud.io/index.php/topic,77883.msg902143.html#msg902143
Yep. You now get a progress dialog like this when working with enough files...
(https://i.imgur.com/g9KlV0U.png)
I've only managed to test with 2000 files as that's all I have. :-[
edit: funny how fbuser was able to tag 500 files at once with the old function. I found my own system crashed after tagging 75.
Yep. You now get a progress dialog like this when working with enough files...
(https://i.imgur.com/g9KlV0U.png)
I've only managed to test with 2000 files as that's all I have. :-[
edit: funny how fbuser was able to tag 500 files at once with the old function. I found my own system crashed after tagging 75.
Awesome. Thanks :)
Great improvement.
My max was 100 entries...
@marc2003-
Is there an easy way to change the included jsspm double click selection behavior into single click? At one point Falstaff had this in his original version but changed it for reasons unknown.
I'd like to ask for a 'feature' request as well. I see file properties (from samples) still creates an autoplaylist from any item clicked in that panel. Is there any possibility to change that so it is off by default instead of the way it is now? I personally do not find it useful to have an autoplaylist created from say one files MD5 hash tag. Generally I edit list.js by commenting out those lines but feel that should be optional. Right click option maybe? Don't know and just a suggestion.
If anyone has found the included allmusic script has stopped working, you can edit line 253 of user-components\foo_jscript_panel\samples\complete\js\text.js by replacing the http with https like this...
https://github.com/19379/foo-jscript-panel/commit/d216052e4e4863ac6187af9aa1cf968a11953943
edit: just noticed some previous posts have been nuked. I apologise to the mods and the previous poster is on the ignore list. :P
Thanks
Setting 'Mood' in the jsplaylist-mod causes an instant crash. Error message below. (https://youtu.be/SilHMPTy6Oc) Version 1.3.0.
JScript Panel (jsplaylist-mod by Br3tt aka Falstaff >> modded by marc2003)
JavaScript runtime error:
Object doesn't support property or method 'UpdateFileInfoSimple'
File: C:\Users\*\Desktop\foo_test\user-components\foo_jscript_panel\samples\jsplaylist-mod\js\WSHplaylist.js
Line: 1077, Col: 10
<source text only available at compile time>
If someone else runs into this you may wish to inform marc2003 since I apparently tripped his trigger one too many times.
I use Line(2860-2866、2891-2892、2942-2970) and utils.MapString to translate the music tags from traditional Chinese into Simplified Chinese. When the music tags has a null value, it fails while running on JScript Panel, and no error occurs on WSH PLUS (with utils.LCMapString). I don't know if there is a problem with my code or the utils.MapString interface. Can you help me see where the problem is?
Can you add the word wrap function at the JScript Panel Configuration ?
You know I copied the function from WSH panel mod plus. The only difference is that I made it throw an error if you don't supply a
flag.
I tested these examples and they perform the same in both components.
JScript Panel
var test = utils.MapString("", 0x0804, 0x04000000); //returns empty string
var test = utils.MapString(null, 0x0804, 0x04000000); //script error
var test = utils.MapString(undefined, 0x0804, 0x04000000); //returns empty string
WSH Panel Mod Plus
var test = utils.LCMapString("", 0x0804, 0x04000000); //returns empty string
var test = utils.LCMapString(null, 0x0804, 0x04000000); //script error
var test = utils.LCMapString(undefined, 0x0804, 0x04000000); //returns empty string
Just use something like this instead...
arr[k] = utils.MapString(fileinfo.MetaValue(idx,0) || "", 0x0804, ret - 3000 ? 0x04000000 : 0x02000000);
And no, I'm not adding word wrap to the configuration window. I'll be honest and say I wouldn't know how even if wanted to!
Thanks. It works. Now ttsping focuses on SUI. It's a new user interface that combines sciter and WSH interfaces...
(track info + seekbar + buttons) background color can be changed to automatically get the title bar or taskbar color? Like Groove.
I'm not changing it but you can get windows 10 colours from the registry...
https://hydrogenaud.io/index.php/topic,110516.msg941430.html#msg941430
If anyone is interested I've got a working jscript that switches PSS splitters with buttons from the latest JScript panel. You need to have Columns UI, PSS, and JScript panel installed (portable for testing recommended). I used images out of the mono folder from the jscript component folder for generic buttons images. Once those components are installed you can import this FCL file (https://1drv.ms/u/s!ApfYRpO7XcpKmkZPwnz1NQKfl7Bw) from within Columns UI.
Right clicking the Parent Splitter (https://imgur.com/Txn9hwe) and selecting Splitter Settings (upper one) will show child splitter names in PanelList tab. The Script tab shows the PSS code that must be used in the parent splitter. Note names in Script tab (1-4) and their placement here. They need to match the names in the PanelList tab.
This type of switcher does not need to be in the same parent splitter as is the case for PSS buttons. You can even use this in the CUI toolbar to change the panels. Right click the toolbar > Panels > JScript panel > copy code from orange jscript panel.
I'm unsure if it could be cleaned up or optimized further, but it works quite well.
If anyone is interested I've got a working jscript that switches PSS splitters with buttons from the latest JScript panel. You need to have Columns UI, PSS, and JScript panel installed (portable for testing recommended). I used images out of the mono folder from the jscript component folder for generic buttons images. Once those components are installed you can import this FCL file (https://1drv.ms/u/s!ApfYRpO7XcpKmkZPwnz1NQKfl7Bw) from within Columns UI.
Right clicking the Parent Splitter (https://imgur.com/Txn9hwe) and selecting Splitter Settings (upper one) will show child splitter names in PanelList tab. The Script tab shows the PSS code that must be used in the parent splitter. Note names in Script tab (1-4) and their placement here. They need to match the names in the PanelList tab.
This type of switcher does not need to be in the same parent splitter as is the case for PSS buttons. You can even use this in the CUI toolbar to change the panels. Right click the toolbar > Panels > JScript panel > copy code from orange jscript panel.
I'm unsure if it could be cleaned up or optimized further, but it works quite well.
I just want to mention that the reqiured "hack" to refresh the PSS panel
if (fb.IsPlaying || fb.IsPaused) {
fb.RunMainMenuCommand("Playback/Play or Pause");
fb.RunMainMenuCommand("Playback/Play or Pause");
} else {
fb.RunMainMenuCommand("Playback/Play");
fb.RunMainMenuCommand("Playback/Stop");
}
works well with local media files, but not with internet radio streams where there is a noticable pause in the playback.
Replace Wsh panel mod with jscript panel on catrox. There are some undefined definitions. Who can help me? Like: line: 989 in Control_Scrollbar.js line: 584 in Panel_Cover.js
Catrox was written for WSH panel mod... so use WSH panel mod. The main reason I created JScript Panel was because of my breaking changes so people can now run both components side by side if they don't know how to update the scripts.
edit: and of course you even have access to WSH panel mod PLUS which seems to contain most functions from both components.
@always.beta: Well, actually, original CaTRoX is pretty much compatible with JScript, you just need to follow this guide (https://github.com/19379/foo-jscript-panel/wiki/Updating-WSH-Panel-Mod-scripts-for-JScript-Panel) to make it work.
Well that link is in the first post of this thread.... it's really for script authors who might want to update their scripts and then take advantage of newer features in this component. I figure for the casual user, it's just easier to use the old component - that is you can afford the 1MB or so of disk space it takes. :P
@always.beta: Well, actually, original CaTRoX is pretty much compatible with JScript, you just need to follow this guide (https://github.com/19379/foo-jscript-panel/wiki/Updating-WSH-Panel-Mod-scripts-for-JScript-Panel) to make it work.
The interface has been updated as instructed. Now the error: createScrollbarImages(line: 989 in Control_Scrollbar.js) is undefined. However, it is defined in line: 165. I don't know how to fix the definition.
Just an act of compulsion. A new components appears, why not upgrade. :)
Possibly related to this... https://hydrogenaud.io/index.php/topic,110499.msg933234.html#msg933234
I just want to mention that the reqiured "hack" to refresh the PSS panel works well with local media files, but not with internet radio streams where there is a noticable pause in the playback.
That's a well known limitation of PSS and not exactly what the focus of this experiment was. Until there's another component that allows the same flexibility as PSS without it's warts we're sort of stuck with what we have at hand. If a user can live with the drawbacks then this simple script permits PSS switching from anywhere in the UI as long as the jscript panel doing the switching is visible. I even rolled this into my heavily modified 'track info + seekbar + buttons' control bar.
I just want to mention that the reqiured "hack" to refresh the PSS panel works well with local media files, but not with internet radio streams where there is a noticable pause in the playback.
That's a well known limitation of PSS and not exactly what the focus of this experiment was. Until there's another component that allows the same flexibility as PSS without it's warts we're sort of stuck with what we have at hand. If a user can live with the drawbacks then this simple script permits PSS switching from anywhere in the UI as long as the jscript panel doing the switching is visible. I even rolled this into my heavily modified 'track info + seekbar + buttons' control bar.
I just wanted to mention a limitation of your experiment.
There exists a component that can switch & move panels with desired sizes and its called mega_panel_splitter.
http://1drv.ms/1EbzBou (http://1drv.ms/1EbzBou)
It is based on wsh and old version [1.1.10].
https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/foo-wsh-panel-mod/Source-1.1.10.7z
Proof of concept demo: https://www.dropbox.com/s/nvqh5d5y40ae74p/bandicam%202017-10-22%2018-58-27-047.avi?dl=0 (https://www.dropbox.com/s/nvqh5d5y40ae74p/bandicam%202017-10-22%2018-58-27-047.avi?dl=0)
If you need to control a jscript panel from PSS you can use marc2003 new callback, on_main_menu.
https://github.com/19379/foo-jscript-panel/blob/master/foo_jscript_panel/docs/Callbacks.txt#L61
The opposite is not possible though. (Use jscript panel to notify PSS)
PSS only evaluates scripts on playback start or when track info is modified.
I just wanted to mention a limitation of your experiment.
It does exactly what it was supposed to do; control PSS splitters with the only means available to do so at this time. Recommending undocumented components that a handful of people on the planet use (and probably even fewer understand) is going off-topic here.
When does the on_mouse_move event actually take place?
I understand if I move the pointer from A to B an on_mouse_event takes place when the pointer stops on B, thus passing the B coordinates as arguments to the on_mouse_move function, but what happens during the path from A to B? Does the event take place only when the pointer stops, or also while it is still moving? In this latter case, is the motion detected on a time interval or a space interval basis?
Start with a blank panel...
var tooltip = window.CreateTooltip("Segoe UI", 32, 1);
function on_mouse_move(x, y) {
tt(x + "-" + y);
}
function tt(message) {
if (tooltip.Text != message) { //must check values have changed otherwise tooltip will flicker
tooltip.Text = message;
tooltip.Activate();
}
}
Now move your mouse and see how often the numbers update.
Start with a blank panel...
var tooltip = window.CreateTooltip("Segoe UI", 32, 1);
function on_mouse_move(x, y) {
tt(x + "-" + y);
}
function tt(message) {
if (tooltip.Text != message) { //must check values have changed otherwise tooltip will flicker
tooltip.Text = message;
tooltip.Activate();
}
}
Now move your mouse and see how often the numbers update.
Well, I can't really see in real time what happens if the mouse is moving too fast, however I traced the
y value with the console and beyond a certain speed the increments can be greater than 1, therefore I'd say a minimum time interval is required before the event takes place.
I also tried removing the if statement to check if there is a minimum space interval, too, and when moving slow enough, some values were repeated. That means, if I'm correct, that no minimum space interval is required to trigger the event, and since the coordinates are rounded to an integer, an on_mouse_event does not necessarily mean the
x and
y values have changed. I guess this is something that must be handled with an if statement, like you did, in order to prevent flickering if the on_mouse_event triggers a repaint .
I'm looking for a little help with falstaff's scripts. As an example I installed JS Smooth Playlist Manager and I get this error when applying it:
JScript Panel (JS Smooth Playlist Manager v20151115-1000-151 by Br3tt aka Falstaff >> http://br3tt.deviantart.com)
JavaScript compilation error:
Syntax error
File: C:\Users\Daniel\AppData\Roaming\foobar2000\js_br3tt\jsspm\js\JScommon.js
Line: 540, Col: 8
}; else {
What am I doing wrong?
Looks like you have the original version from deviantart - they're not compatible with the latest versions of the component.
However, updated versions of the scripts are bundled inside the component folder so right click in a panel>Open component folder and browse to samples\js-mooth
edit: if you don't have a js-smooth folder, you'll need to update the component (https://github.com/19379/foo-jscript-panel/releases).
JS Smooth Playlist: when the music is played to 1/3, the selection box will automatically switch to the next one, and the current music loses the focus of the playback. How do I close it, please?
I don't even understand the "question/problem" above! I know my component changes did break the originals some time ago and I did my best to change the code style to make them load. They all do that now and I don't understand the code well enough to make changes to the deeper features/functionality.
Simply put, I don't have the answers. If they don't work as expected, don't use them.
JS Smooth Playlist: when the music is played to 1/3, the selection box will automatically switch to the next one, and the current music loses the focus of the playback. How do I close it, please?
It is a conflict that occurs when you select in ESLyrics , Lyrics save scheme "Save when 60s or 1/3 of length have played".
It is a conflict that occurs when you select in ESLyrics , Lyrics save scheme "Save when 60s or 1/3 of length have played".
I always thought the track title artist information has not changed, and will not affect it. :-[ I've changed the Lyrics save scheme. Thank you.
Can I compare two objects?
For example.
I have two massive of embedded covers
I need if (embedded_1[0] == embedded_2[0] ) {.........}
or
var img1 = gdi.Image(img_path + "1.png"),
var img2 = gdi.Image(img_path + "2.png"),
if ( img1 == img2 ) {.........}
Nope.
Nope.
there was hope
Thanks, marc2003
Is there a way to detect if the windows theme, or the screen settings were changed?
Is there a way to detect if the windows theme, or the screen settings were changed?
Can you elaborate your question a bit? =)
Are you talking about Windows (e.g. Windows 10) theme? Or fb2k theme?
And there a lot of various screen settings as well both in fb2k and Windows...
Is there a way to detect if the windows theme, or the screen settings were changed?
Can you elaborate your question a bit? =)
Are you talking about Windows (e.g. Windows 10) theme? Or fb2k theme?
And there a lot of various screen settings as well both in fb2k and Windows...
I'm talking about the windows 10 theme. I have a script that reads the registry key value of the accent color and other related settings such as transparency mode and whether the accent color is applied to the window titlebar. The script than refreshes panel stack splitter in order to apply the new accent color, if changed. At the moment it is triggered by the
on_size and by the
on_playback_new_track events, but I would like to execute the script when one of those screen settings is changed, or when a new theme is applied.
Well, there are no such functions in JScript. But you could probably make something with window.setInterval, i.e. get, compare and update theme values from registry every N seconds .
Well, there are no such functions in JScript. But you could probably make something with window.setInterval, i.e. get, compare and update theme values from registry every N seconds .
I'll give it a look, thanks.
Does anybody have or know of a fairly simple script for an input box?
Does anybody have or know of a fairly simple script for an input box?
I'm trying to replace the quicksearch toolbar with a jscript panel, but I'm not looking for a ready made script, which would probably have the same layout issues that the quicksearch toolbar has. I've seen some configurations with a jscript searchbox, but they are far too complex to extrapolate the relevant code.
I thought I could build what I needed with the on_key_down and on_key_up events, but perhaps I've been a little too optimistic. What are the basic guidelines? Which callbacks should I use and, by the way, how do I get the proper character codes from key events?
I'm trying to replace the quicksearch toolbar with a jscript panel, but I'm not looking for a ready made script, which would probably have the same layout issues that the quicksearch toolbar has. I've seen some configurations with a jscript searchbox, but they are far too complex to extrapolate the relevant code.
I thought I could build what I needed with the on_key_down and on_key_up events, but perhaps I've been a little too optimistic. What are the basic guidelines? Which callbacks should I use and, by the way, how do I get the proper character codes from key events?
The issue is that JScript is not a web browser (which is my fucking dream... can you imagine how easy this stuff would be if we could use css/html for displaying panels and stuff -- I digress) so you can't really do an input box without completely faking EVERYTHING. i.e. you'd have to draw a rectangle on the screen. When the user clicks on it you have to draw a carat. When the user presses a key you have to draw a character to the screen and move the carat, you have to redraw on backspaces,.... etc.
I assume it *could* be done and maybe someone has done it, but it sounds awful to me.
There is some good news though. Doing something on keypresses is the easy part! The delete and ctrl-A keys call functions specific to my theme, but ctrl-F and Shift-F will run different foobar searches which might be good enough for you.
function on_key_down(vkey) {
var CtrlKeyPressed = utils.IsKeyPressed(VK_CONTROL);
var ShiftKeyPressed = utils.IsKeyPressed(VK_SHIFT);
switch (vkey) {
case VK_DELETE:
RemovePlaylistSelection(activeList, crop = false);
break;
case VK_KEY_A:
CtrlKeyPressed && selectAll();
break;
case VK_KEY_F:
CtrlKeyPressed && fb.RunMainMenuCommand("Edit/Search");
ShiftKeyPressed && !CtrlKeyPressed && fb.RunMainMenuCommand("Library/Search");
break;
}
There is some good news though. Doing something on keypresses is the easy part! The delete and ctrl-A keys call functions specific to my theme, but ctrl-F and Shift-F will run different foobar searches which might be good enough for you.
function on_key_down(vkey) {
var CtrlKeyPressed = utils.IsKeyPressed(VK_CONTROL);
var ShiftKeyPressed = utils.IsKeyPressed(VK_SHIFT);
switch (vkey) {
case VK_DELETE:
RemovePlaylistSelection(activeList, crop = false);
break;
case VK_KEY_A:
CtrlKeyPressed && selectAll();
break;
case VK_KEY_F:
CtrlKeyPressed && fb.RunMainMenuCommand("Edit/Search");
ShiftKeyPressed && !CtrlKeyPressed && fb.RunMainMenuCommand("Library/Search");
break;
}
Thanks a lot! This is the kind of starting point I'm looking for, and thanks for pointing me to the utils interface which for some reason I always fail to take into account. I still can't figure out a reasonable way to determine the character code, though. The combination of keycode and utils.IsKeyPressed is actually enough, but do I really have to go through all possible combinations one by one with a switch statement? Isn't there something like a keyboard mapping? Perhaps some array of values in the registry key?
The issue is that JScript is not a web browser (which is my fucking dream... can you imagine how easy this stuff would be if we could use css/html for displaying panels and stuff -- I digress)
Indeed! I'm still waiting for the sciter ui plug-in.
so you can't really do an input box without completely faking EVERYTHING. i.e. you'd have to draw a rectangle on the screen. When the user clicks on it you have to draw a carat. When the user presses a key you have to draw a character to the screen and move the carat, you have to redraw on backspaces,.... etc.
I assume it *could* be done and maybe someone has done it, but it sounds awful to me.
Yes, someone has. There is one in colagen's eole skin, even though I think the script is taken from the DUItunes skin by Falstaff. The code that implements the searchbox - at least where I'm able to recognize it - is within my reach, but it is hidden in longer multipurpose scripts, specific for that particular configuration or layout and with a maze of crossfererence to other js documents that make reading it a real pain in the neck, unless you are the author, I guess.
[Thanks a lot! This is the kind of starting point I'm looking for, and thanks for pointing me to the utils interface which for some reason I always fail to take into account. I still can't figure out a reasonable way to determine the character code, though. The combination of keycode and utils.IsKeyPressed is actually enough, but do I really have to go through all possible combinations one by one with a switch statement? Isn't there something like a keyboard mapping? Perhaps some array of values in the registry key?
on_key_down returns standard ascii character codes. So values 65-90 correspond to A-Z (you need to check if VK_SHIFT is down for upper/lower though). If you want to output the key pressed to the screen you can do something like:
var str = String.fromCharCode(65); // str now contains 'A'
on_key_down returns standard ascii character codes. So values 65-90 correspond to A-Z (you need to check if VK_SHIFT is down for upper/lower though). If you want to output the key pressed to the screen you can do something like:
var str = String.fromCharCode(65); // str now contains 'A'
Yes, the A-Z character codes, as well as the blank space and 0-9 characters, are the same as the key code, but all other symbols are messed up and I believe they change with the keyboard settings.
I would assume punctuation and other printable characters are the same, but the other things probably require a select statement based off the VK_ defines.
on_key_down returns standard ascii character codes. So values 65-90 correspond to A-Z (you need to check if VK_SHIFT is down for upper/lower though). If you want to output the key pressed to the screen you can do something like:
var str = String.fromCharCode(65); // str now contains 'A'
Yes, the A-Z character codes, as well as the blank space and 0-9 characters, are the same as the key code, but all other symbols are messed up and I believe they change with the keyboard settings.
We were on the wrong track! The
on_char(code) callback is the one to look at: it takes the character code which is actually mapped to the key, rather than the key code.
Nice, I'd never actually used that callback before. Thanks for the info.
How do you escape the ampersand? The backslash doesn't seem to work as with other characters.
Basically: how can I write "Tom & Jerry" with a GdiDrawText method?
Try "Tom && Jerry"
How do you escape the ampersand? The backslash doesn't seem to work as with other characters.
Basically: how can I write "Tom & Jerry" with a GdiDrawText method?
You need to add the flag DT_NOPREFIX
https://github.com/marc2k3/foo_jscript_panel/blob/master/foo_jscript_panel/docs/Flags.txt#L16
https://github.com/marc2k3/foo_jscript_panel/blob/8ee7c4d084b535946922c05cadc3eba1b0e5c7e4/foo_jscript_panel/docs/Interfaces.txt#L1268
Thanks, both solutions work.
Hello. I use
// @name "Text Reader"
// @author "marc2003"
1. I want to use it for viewing сue located of course in the playing folder, how to set the path? Default $directory_path(%path%) ... $directory_path(%path%)\*.CUE ... dont work
2. where to change the font type?
3. I want to display a text file with the name "discography.txt" in the root artist folder, the problem is that sometimes the depth of nesting, for example "artist \ album \" ... "artist \ album \ CD1"
EDIT
2. where to change the font type?
The panel object uses the DUI or CUI font settings.
3. I want to display a text file with the name "discography.txt" in the root artist folder, the problem is that sometimes the depth of nesting, for example "artist \ album \" ... "artist \ album \ CD1"
It depends on your folder naming standards. For example, if all your multiple discs were in folders named CD%discnumber% this could be your custom path:
$if($strcmp($directory(%path%),CD%discnumber%),$replace($directory_path(%path%),$directory(%path%),),$directory_path(%path%))
2. where to change the font type?
The panel object uses the DUI or CUI font settings.
3. I want to display a text file with the name "discography.txt" in the root artist folder, the problem is that sometimes the depth of nesting, for example "artist \ album \" ... "artist \ album \ CD1"
It depends on your folder naming standards. For example, if all your multiple discs were in folders named CD%discnumber% this could be your custom path:$if($strcmp($directory(%path%),CD%discnumber%),$replace($directory_path(%path%),$directory(%path%),),$directory_path(%path%))
2. I use when changing columns UI the font of a custom, only the headings change but not the actual display of the text file in the panel
3. CD%discnumber% - use of this code requires the insertion of tags% discnumber% ??? How to be if there are no tags (in CUE), and the folders are called CD1, CD2? And how to complete the code to take only the file with the name "discography.txt"?
2. I use when changing columns UI the font of a custom, only the headings change but not the actual display of the text file in the panel
You are right, in text_reader mode the panel always uses the lucida console character for the text. This is not my script, so I'm just groping around, but you can try editing the script and replace on line 11 the word "text_reader" with the word "allmusic", that should apply the CUI font.
3. CD%discnumber% - use of this code requires the insertion of tags% discnumber% ??? How to be if there are no tags (in CUE), and the folders are called CD1, CD2? And how to complete the code to take only the file with the name "discography.txt"?
Something like this?
$ifequal($strstr($directory(%path%),CD),1,$replace($directory_path(%path%),\$directory(%path%),),$directory_path(%path%))\discography.txt
2. I use when changing columns UI the font of a custom, only the headings change but not the actual display of the text file in the panel
You are right, in text_reader mode the panel always uses the lucida console character for the text. This is not my script, so I'm just groping around, but you can try editing the script and replace on line 11 the word "text_reader" with the word "allmusic", that should apply the CUI font.
3. CD%discnumber% - use of this code requires the insertion of tags% discnumber% ??? How to be if there are no tags (in CUE), and the folders are called CD1, CD2? And how to complete the code to take only the file with the name "discography.txt"?
Something like this?$ifequal($strstr($directory(%path%),CD),1,$replace($directory_path(%path%),\$directory(%path%),),$directory_path(%path%))\discography.txt
1. with allmusic stopped working as text reader((
2. the code does not see the file in the artist folder, you need to make the code for universal viewing from any sub-folder with any recursion up to the folder artist
var 1: artist\album\CD1\playable file
var 2: artist\album\playable file
in both variants "discography.txt" is located in "artist" folder
Hello. I use
// @name "Text Reader"
// @author "marc2003"
1. I want to use it for viewing сue located of course in the playing folder, how to set the path? Default $directory_path(%path%) ... $directory_path(%path%)\*.CUE ... dont work
2. where to change the font type?
3. I want to display a text file with the name "discography.txt" in the root artist folder, the problem is that sometimes the depth of nesting, for example "artist \ album \" ... "artist \ album \ CD1"
1. The text reader looks for *.txt *.log in default custom path $directory_path(%path%) or a specific file when defined $directory_path(%path%)\thecuefilename.cue
1a. Either specify the same name to all your cue files eg. tracklist.cue and define the custom path $directory_path(%path%)\tracklist.cue
OR
1b. Modify text.js in user-components\foo_jscript_panel\samples\complete\js to include *.cue by changing line #370
this.exts = 'txt|log';
TO
this.exts = 'cue|txt|log';
Remember that any future update to the component will overwrite text.js
2. The text panel follows the defined common (list items) CUI font in the preferences page.
Uncheck "Fixed width font" from the text panel submenu for it not to use fixed font Lucida Console.
3. This should work
$left(%path%,$strstr(%path%,\%artist%))%artist%)\discography.txt
EDIT: actually just follow zeremy's instructions
zeremy, Thank you so much! "Fixed width font" was in the most prominent place))))))))
I added this.exts = 'cue|txt|log'; ... but still does not read the only cue in the folder, only when assigning a relative path, how to make it work on any cue ... $directory_path(%path%)\*.cue ???
zeremy, Thank you so much! "Fixed width font" was in the most prominent place))))))))
I added this.exts = 'cue|txt|log'; ... but still does not read the only cue in the folder, only when assigning a relative path, how to make it work on any cue ... $directory_path(%path%)\*.cue ???
Don't use $directory_path(%path%)\*.cue in the custom path
Use $directory_path(%path%)
The script will load the first file found out of the three extensions cue,txt,log ( you cant define a single one ) in the directory,
zeremy, Thank you, we created Cue Viewer!
zeremy, Thank you, we created Cue Viewer!
Glad I helped you sort it out.
To be honest, I just gave you a few pointers.
You should thank @marc2003 who is the author.
var items = plman.GetPlaylistItems(plman.ActivePlaylist);
for (var i = 0; i < items.Count; i++) {
items.Item(i).SetRating(5);
}
items.RefreshStats();
items.Dispose();
What to do with this script? Thanks.
I've been doing a LOT of work with color handling in my script as I'm using image.GetColorScheme() to pull the colors to generate a dynamic theme. It works great, and I can't wait to show it to everyone, but I figured I ought to share some of the helper code I wrote as I'm sure it'd be useful to more than just me.
This code makes extensive use out of the getRed, getGreen, getBlue, rgb, rgba helper functions and I won't bother repeating them unless somebody can't find them in helpers.txt. Also, I renamed RGB and RGBA to lowercase versions.
prettyPrint a color. Useful for logging:
function colToRgb(c, showPrefix) {
if (typeof showPrefix === 'undefined') showPrefix = true;
var alpha = getAlpha(c);
var prefix = '';
if (alpha < 255) {
if (showPrefix) prefix = 'rgba'
return prefix + '('+ getRed(c) + ', ' + getGreen(c) + ', ' + getBlue(c) + ', ' + alpha + ')';
} else {
if (showPrefix) prefix = 'rgb'
return prefix + '(' + getRed(c) + ', ' + getGreen(c) + ', ' + getBlue(c) + ')';
}
}
Calculate Brightness of a color:
function calcBrightness(c) {
var r = getRed(c);
var g = getGreen(c);
var b = getBlue(c);
return Math.round(Math.sqrt( 0.299*r*r + 0.587*g*g + 0.114*b*b ));
}
Create Shades (darker) or Tints (lighter) of a color. These two functions take a percent number, i.e. pass 20 instead of .2. Passing 100 to shade will result in solid black, 100 to tint is solid white.
color = rgb(81, 89, 72); // gray-ish green
darker = shadeColor(color, 30); // darker = rgb(57, 62, 50)
lighter = tintColor(color, 20); // lighter = rgb(116, 122, 109)
function shadeColor(color, percent) {
var red = getRed(color);
var green = getGreen(color);
var blue = getBlue(color);
return rgba(darkenColorVal(red, percent), darkenColorVal(green, percent), darkenColorVal(blue, percent), getAlpha(color));
}
function tintColor(color, percent) {
var red = getRed(color);
var green = getGreen(color);
var blue = getBlue(color);
return rgba(lightenColorVal(red, percent), lightenColorVal(green, percent), lightenColorVal(blue, percent), getAlpha(color));
}
// helpers, don't call directly
function darkenColorVal(color, percent) {
var shift = Math.max(color * percent / 100, percent / 2);
val = Math.round(color - shift);
return Math.max(val, 0);
}
function lightenColorVal(color, percent) {
val = Math.round(color + ((255-color) * (percent / 100)));
return Math.min(val, 255);
}
HI,
Does somebody know what is the
fromhook parameter in this callback function ?
function on_metadb_changed(handle_list, fromhook) {}
It seems to be boolean, and it seems to be true when the callback is from a change by foobar, and false otherwise. Is that true ? Is there a documentation somewhere ? There is nothing in the "official" documentation
Thanks!
HI,
Does somebody know what is the fromhook parameter in this callback function ?
function on_metadb_changed(handle_list, fromhook) {}
It seems to be boolean, and it seems to be true when the callback is from a change by foobar, and false otherwise. Is that true ? Is there a documentation somewhere ? There is nothing in the "official" documentation
Thanks!
From fb2k SDK documentation:
//! @param
p_fromhook Set to true when actual file contents haven't changed but one of metadb_display_field_provider implementations requested an update so output of metadb_handle::format_title() etc has changed.
E.g. it will be true when
%play_count% field provided by foo_playcount component has changed.
Okey, thanks, clear enough
To anyone using
IntelliJ WebStorm or
IDEA to create/edit scripts:
I've updated JSDoc'd version of JScript's interface.txt (https://github.com/marc2k3/foo_jscript_panel/blob/master/foo_jscript_panel/docs/Interfaces.txt), which can be used as a plugin/library in IDEA/WebStorm.
This will remove most of 'undefined symbol' warnings and will also provide some type checks when using JScript interface.
Instructions:- Download all the files from >>git<< (https://github.com/TheQwertiest/CaTRoX_QWR/tree/master/jscript_api) and put them in some folder.
- File > Settings > Languages > JavaScript > Libraries > Add... > + > Attach Directories... > Choose folder from the previous step
Is there a way distinguish two different playlists with the same name, without knowing their index?
When I need to perform some action on a specific playlist, I usually retrieve the playlist index by looping through all playlists until I find the one with the matching name, but since nothing in foobar2000 prevents me from accidentally duplicating a playlist name and the index changes when moving the playlist, how can I make sure I identify the right playlist?
Is there a way distinguish two different playlists with the same name, without knowing their index?
When I need to perform some action on a specific playlist, I usually retrieve the playlist index by looping through all playlists until I find the one with the matching name, but since nothing in foobar2000 prevents me from accidentally duplicating a playlist name and the index changes when moving the playlist, how can I make sure I identify the right playlist?
Well, if two playlists have the same name and content, then the only way to differentiate them is by their index. If you are working on the currently active playlist you can retrieve it's index via plman.ActivePlaylist. May be you could elaborate your scenario a bit more?
PS: reply #666 > : )
Well, if two playlists have the same name and content, then the only way to differentiate them is by their index.
No, I mean two different playlists by all means, different content, but accidentally named alike.
I have some sort of "service" playlists. For example a "Recently Added" autoplaylist with all tracks added in the past 6 weeks. I use a script to create said playlist if it is not present (in case I accidentally delete it, for example). Now, let's say I run the menu command Library-> Playback Statistics -> Show recently added. This will create a second "Recently Added" autoplaylist, but with a different format and content. If I accidentally delete my "Recently Added" playlist, the script will fail to recreate it, because it will find another playlist with the same name and mistake it for the deleted one.
PS: reply #666 > : )
8)
I'm pretty sure there must be some sort of playlist identifier, other than the name and the index, because components such as playlist attributes can keep trace of a single playlist settings even if its name is not univocal and even after it is moved around, hence changing its index, but I don't know if and how this identifier is accessible with jscript.
I'm pretty sure there must be some sort of playlist identifier, other than the name and the index, because components such as playlist attributes can keep trace of a single playlist settings even if its name is not univocal and even after it is moved around, hence changing its index, but I don't know if and how this identifier is accessible with jscript.
foo_playlist_attributes probably uses this API (https://github.com/marc2k3/foo_jscript_panel/blob/master/foobar2000/SDK/playlist.h#L386), which is not exposed in JScript. Nevertheless, this API only allows to set some property to playlists (i.e. playlists are differentiated by index in fb2k itself), so foo_playlist_attributes most likely sets unique properties to each playlist on startup, which allows it to track all the changes on those playlists.
To anyone using IntelliJ WebStorm or IDEA to create/edit scripts:
I've updated JSDoc'd version of JScript's interface.txt (https://github.com/marc2k3/foo_jscript_panel/blob/master/foo_jscript_panel/docs/Interfaces.txt), which can be used as a plugin/library in IDEA/WebStorm.
This will remove most of 'undefined symbol' warnings and will also provide some type checks when using JScript interface.
Damnit, I could really use this for VSCode :)
Damnit, I could really use this for VSCode :)
Google is your friend =)
E.g.: https://stackoverflow.com/questions/45332052/how-to-add-an-api-to-visual-studio-code
Touché!
Alright, so I added your Interfaces.js to my VS Code, and it works perfectly, almost. fb, gdi, utils, etc. all work out of the box.... except for gr which is the one I most care about :D
Dig a little digging and your code generator was missing the new on the gr constructor. Change 2110 to:
var gr = new IGdiGraphics();
And everything works beautifully. Also, I think I owe you a beer now.
I just updated to 2.0.x this week and today I just realized I can't add items to the playbackQueue. Here's my call:
plman.AddPlaylistItemToPlaybackQueue(activeList, focusItemIndex);
where activeList is the index of the playlist and focusItemIndex is the index into that playlist of the song. Both those numbers are correct. Nothing appears to happen though. Am I missing something? There was some stuff in the breaking changes about this playlist stuff, but it doesn't look like AddPlaylistItemToPlaybackQueue was affected.
Touché!
Alright, so I added your Interfaces.js to my VS Code, and it works perfectly, almost. fb, gdi, utils, etc. all work out of the box.... except for gr which is the one I most care about :D
Dig a little digging and your code generator was missing the new on the gr constructor. Change 2110 to:
var gr = new IGdiGraphics();
And everything works beautifully. Also, I think I owe you a beer now.
Heh, will be fixed soon =)
And you are welcome! Glad that it was useful for someone other than me :P
I just updated to 2.0.x this week and today I just realized I can't add items to the playbackQueue. Here's my call:
plman.AddPlaylistItemToPlaybackQueue(activeList, focusItemIndex);
where activeList is the index of the playlist and focusItemIndex is the index into that playlist of the song. Both those numbers are correct. Nothing appears to happen though. Am I missing something? There was some stuff in the breaking changes about this playlist stuff, but it doesn't look like AddPlaylistItemToPlaybackQueue was affected.
Not sure about this - AddPlaylistItemToPlaybackQueue works fine for me... Queue is updated and the added item is played next as well :\
The function usage seems the same as well:
https://github.com/TheQwertiest/CaTRoX_QWR/blob/master/theme/Scripts/Panel_Playlist.js#L4013
What do you mean by "Nothing appears to happen"? Is it that the added track is ignored, or on_queue_changed callbacks are not called?
PS: Didn't have a chance to visit Austin (or Texas for that matter) yet, but now I'll have one more excuse to rectify that =)
What do you mean by "Nothing appears to happen"? Is it that the added track is ignored, or on_queue_changed callbacks are not called?
Exactly what I said. Nothing "appears" to happen. ;) Turns out everything actually was happening, my playlist just isn't showing the queued status of items. Got to be related to the breaking changes. I fixed the errors, but something still isn't right I guess.
PS: Didn't have a chance to visit Austin (or Texas for that matter) yet, but now I'll have one more excuse to rectify that =)
Do it! The music is great, the beer is cheap, and the women are gorgeous. You basically can't go wrong.
help.
I have LastFm HTML code
<li class="metadata-item metadata-item--limit-width other-releases">
h2 class="metadata-title">Also featured on</h2>
<a href="/music/John+Lennon/The+John+Lennon+Collection" title="The John Lennon Collection"><img src="https://lastfm-img2.akamaized.net/i/u/avatar42s/59ecaa8fd6474c48b04cc537a0d9e508.jpg" alt="The John Lennon Collection" /></a>
<a href="/music/John+Lennon/Lennon" title="Lennon"><img src="https://lastfm-img2.akamaized.net/i/u/avatar42s/937195d43be848959662ad9b615ef1c1.jpg" alt="Lennon" /></a>
<a href="/music/John+Lennon/Lennon+Legend+-+The+Very+Best+Of+John+Lennon" title="Lennon Legend - The Very Best Of John Lennon"><img src="https://lastfm-img2.akamaized.net/i/u/avatar42s/686afc08c3a94049a235314603e62fe6.jpg" alt="Lennon Legend - The Very Best Of John Lennon" /></a>
<div class="additional-release-count">
<a href="/music/John+Lennon/_/Instant+Karma!/+albums"><span class="release-count">+5</span> other releases</a>
</div>
</li>
if i I want to get "Also featured on" , I do
var h2 = div.getElementsByTagName("h2");
for (i = 0; i < h2.length; i++) {
if (h2[i].className == "metadata-title") {
t = h2[i].innerHTML;
break;
}
}
How I can get (title or alt):
"The John Lennon Collection"
"Lennon"
and
"Lennon Legend - The Very Best Of John Lennon"
@kgena_ua https://jsfiddle.net/p76j7Lb4/
OMG, I'm lost. What are you guys talking about? Is this code for the JScript panel?
if i I want to get "Also featured on" , I do
var h2 = div.getElementsByTagName("h2");
for (i = 0; i < h2.length; i++) {
if (h2[i].className == "metadata-title") {
t = h2[i].innerHTML;
break;
}
}
https://jsfiddle.net/p76j7Lb4/
It is an extract from his script where he is asking how to parse the html to get the values he wants to use.
My fiddle is just pointing out how to get the values.
I see the logic of the script, but how do you reference an HTML element in JScript panel? At least I'm guessing the div object is one. I'm still pretty alien to HTML, as I thought it was useless for JScript panel,
I see the logic of the script, but how do you reference an HTML element in JScript panel? At least I'm guessing the div object is one. I'm still pretty alien to HTML, as I thought it was useless for JScript panel,
His script is making an AJAX call to a webpage and then attempting to parse the HTML object he gets back to display the text in his theme somewhere. He's (sadly) not manipulating or displaying the HTML directly.
Have mercy for a non-developer, simple foobar2000 user. Learning to work with the interfaces and callbacks provided in the component documentation I was able to do wonderful things that were science fiction to me, only one year ago, but you guys are from another planet. What is an AJAX call, now?
Alright, I googled it: it's a jQuey method. So, not only HTML, but jQuery is also available in a non-browser environment such as JScript panel?
I really thought all I needed, besides the basics of jscript, was in the component docs. I'm clearly missing some big part of it.
Please enlighten me.
zeremy, thank for the fact that you always help.
OMG, I'm lost. What are you guys talking about? Is this code for the JScript panel?
var h2 = div.getElementsByTagName("h2");
for (i = 0; i < h2.length; i++) {
if (h2[i].className == "metadata-title") {
t = h2[i].innerHTML;
break;
}
}
davideleo,
this code for foo_jscript_panel or foo_uie_wsh_panel_mod.
See my topic: Biography Text, Album Info, Picture. www.last.fm
davideleo,
this code for foo_jscript_panel or foo_uie_wsh_panel_mod.
See my topic: Biography Text, Album Info, Picture. www.last.fm
Ok, thanks. I must admit I never checked your script. If this is an excerpt from it, I'd better download it and have a look at the whole code. Be prepared for more questions ;)
for example, we got a review of the track
I've been modifying an old marc2003 code I had in order for it to fit my setup, and my problem is the elapsed playback time (%playback_time% /") only updates when I refresh the panel (so for example play/pause the song). It drives me nuts, if anyone has any idea on how to fix it, please:
// ==PREPROCESSOR==
// @name "track info + seekbar + buttons"
// @author "marc2003"
// @import "%fb2k_profile_path%js_marc2003\js\lodash.min.js"
// @import "%fb2k_profile_path%js_marc2003\js\helpers.js"
// @import "%fb2k_profile_path%js_marc2003\js\panel.js"
// @import "%fb2k_profile_path%js_marc2003\js\seekbar.js"
// ==/PREPROCESSOR==
//note the buttons are white and you'd have to edit the images to change them...
var colours = {
background : _.RGB(255, 255, 255),
title : _.RGB(60, 60, 60),
artist : _.RGB(80, 80, 80),
time : _.RGB(80, 80, 80),
};
//////////////////////////////////////////////////////////////
var panel = new _.panel("track info + seekbar + buttons");
var seekbar = new _.seekbar(60, 5, 0, 20);
var buttons = new _.buttons();
var img = null;
on_playback_new_track();
buttons.update = function () {
var y = _.round((panel.h - 36) / 2);
}
function on_size() {
panel.size();
seekbar.x = panel.h + 310
seekbar.w = panel.w - panel.h - 710;
seekbar.y = (panel.h - 20) / 2;
buttons.update();
}
function on_paint(gr) {
if (fb.IsPlaying) {
img && _.drawImage(gr, img, 0, 0, panel.h, panel.h, image.centre);
gr.GdiDrawText(_.tfe("%title%"), gdi.Font("Helvetica Bold", 16), colours.title, 82, -1, 500, 40, LEFT);
gr.GdiDrawText(_.tfe("%artist%"), gdi.Font("Helvetica Light", 16), colours.artist, 82, 20, 500, 30, LEFT);
gr.GdiDrawText(_.tfe("%playback_time% /"), gdi.Font("Helvetica Light", 16), colours.time, 82, 43, 110, LEFT);
gr.GdiDrawText(_.tfe("%length%"), gdi.Font("Helvetica Light", 16), colours.time, 125, 0, 60, 107, LEFT);
;
}
}
function on_playback_new_track() {
var metadb = fb.GetNowPlaying();
if (!metadb)
return;
_.dispose(img);
img = utils.GetAlbumArtV2(metadb, 0);
window.Repaint();
}
function on_playback_edited() {
window.Repaint();
}
function on_playback_seek() {
seekbar.playback_seek();
}
function on_playback_stop() {
buttons.update();
window.Repaint();
}
function on_playback_pause() {
buttons.update();
window.Repaint();
}
function on_playback_starting() {
buttons.update();
window.Repaint();
}
function on_mouse_wheel(s) {
buttons.leave();
}
function on_mouse_move(x, y) {
if (buttons.move(x, y))
return;
seekbar.move(x, y);
}
function on_mouse_leave() {
buttons.leave();
}
function on_mouse_lbtn_down(x, y) {
seekbar.lbtn_down(x, y);
}
function on_mouse_lbtn_up(x, y) {
if (buttons.lbtn_up(x, y))
return;
if (seekbar.lbtn_up(x, y))
return;
fb.RunMainMenuCommand("View/Show now playing in playlist");
}
function on_mouse_rbtn_up(x, y) {
return panel.rbtn_up(x, y);
}
Have mercy for a non-developer, simple foobar2000 user. Learning to work with the interfaces and callbacks provided in the component documentation I was able to do wonderful things that were science fiction to me, only one year ago, but you guys are from another planet. What is an AJAX call, now?
Alright, I googled it: it's a jQuey method. So, not only HTML, but jQuery is also available in a non-browser environment such as JScript panel?
I really thought all I needed, besides the basics of jscript, was in the component docs. I'm clearly missing some big part of it.
Please enlighten me.
JScript panel is not a browser and you can't import jQuery, but it is possible to import (via ==PREPROCESSOR==) some JavaScript utility libraries like :
https://lodash.com/ (https://lodash.com/)
http://underscorejs.org/ (http://underscorejs.org/)
As for AJAX , MordredKLB was referring to AJAX = Asynchronous JavaScript And XML (https://www.w3schools.com/xml/ajax_intro.asp) that is possible by using ActiveX object. (Microsoft.XMLHTTP)https://www.w3schools.com/xml/ajax_xmlhttprequest_create.asp (https://www.w3schools.com/xml/ajax_xmlhttprequest_create.asp)
The possibility to use ActiveX objects is documented in the wiki.
https://github.com/marc2k3/foo_jscript_panel/wiki (https://github.com/marc2k3/foo_jscript_panel/wiki)
A few other ActiveX objects (not limited to) that you may find in other jScript panel scripts are :
Scripting.FileSystemObject
WScript.Shell
Shell.Application
They are loaded in the script (e.g for WScript.Shell)
var WshShell = new ActiveXObject("WScript.Shell");
Study the scripts from the major contributors and you will discover them and find out how to use them.
my problem is the elapsed playback time (%playback_time% /") only updates when I refresh the panel
may be add
function on_playback_time(time){}
I've been modifying an old marc2003 code I had in order for it to fit my setup, and my problem is the elapsed playback time (%playback_time% /") only updates when I refresh the panel (so for example play/pause the song).
Try:
if (fb.PlaybackLength > 0) {
gr.GdiDrawText(_.tfe("%playback_time% /"), gdi.Font("Helvetica Light", 16), colours.time, 82, 43, 110, LEFT);
}
may be add
function on_playback_time(time){}
Yeah, you should be able add that callback and throw a window.Repaint() in there and it should solve your problem. Like so:
function on_playback_time(time){
window.Repaint();
}
JScript panel is not a browser and you can't import jQuery, but it is possible to import (via ==PREPROCESSOR==) some JavaScript utility libraries like :
https://lodash.com/ (https://lodash.com/)
http://underscorejs.org/ (http://underscorejs.org/)
As for AJAX , MordredKLB was referring to AJAX = Asynchronous JavaScript And XML (https://www.w3schools.com/xml/ajax_intro.asp) that is possible by using ActiveX object. (Microsoft.XMLHTTP)https://www.w3schools.com/xml/ajax_xmlhttprequest_create.asp (https://www.w3schools.com/xml/ajax_xmlhttprequest_create.asp)
The possibility to use ActiveX objects is documented in the wiki.
https://github.com/marc2k3/foo_jscript_panel/wiki (https://github.com/marc2k3/foo_jscript_panel/wiki)
Thanks zeremy, now it is a bit clearer. I'm aware of the possibility to use ActiveXObjects and I've been using it myself in some scripts. Nevertheless, it's a very wide topic and I don't really know where to look for references. I've learned to use some properties and methods of the Scripting.FileSystemObject and of the WScript.Shell, only because I've seen it done in other people's scripts, but the Microsoft.XMLHTTP is totally new to me (I guess I will find an example in kgena_ua's script). Is there some online resource with a guide to ActiveXObjects? I usually end up on some microsoft doc page when I google, but they're nothing like a guide, they're basically a brief reference for the initiate.
Same thing for the libraries: I've been using the lodash library because I've seen examples in marc2000's scripts (and because it comes bundled with the sample docs of the component), but where do you learn about libraries such as the underscorjs? If I were to look for it myself, I'd be lost (thanks for the link BTW).
As for AJAX , MordredKLB was referring to AJAX = Asynchronous JavaScript And XML (https://www.w3schools.com/xml/ajax_intro.asp) that is possible by using ActiveX object. (Microsoft.XMLHTTP)https://www.w3schools.com/xml/ajax_xmlhttprequest_create.asp (https://www.w3schools.com/xml/ajax_xmlhttprequest_create.asp)
So, let me get this straight: are all the methods of the XMLHttpRequest object listed in the w3schools AJAX chapter, available in JScript panel as methods of the Microsoft.XMLHTTP object?
davideleo: I won't speak to ActiveX, but there's a whole world of libraries that Javascript developers are typically familiar with which the average person will never need to know about. Libraries like lodash and underscore are pretty common utility libraries that add extra functionality which make working with certain objects/data easier. The thing you need to be aware of is that EVERY javascript library (whether for the browser or JScript, etc.) isn't adding any new building blocks, just arranging them in ways that make things more convenient to use. This is fundamentally different than plugins for foobar or .DLLs for a c++ project.
For clarification, lodash/_ have a _.first(array, n) method which allow you to get the first n values of an array. There's no new functionality here, you could write it yourself in javascript just as easily as:
function first(array, n) {
return array.slice(0, n);
}
That's why in my estimation js libraries are almost always overkill for JScript panels. In that lodash example there are 100+ other new methods, 99% of which you aren't going to use. Figure out what you want to do, see if somebody is doing it in a library already, and then rip off their code. :)
My theme is a massive 8k line beast. There is some functionality I wanted to implement that requires methods available in ES6 (a newer version of javascript than JScript provides). Specifically, I wanted to find keys matching a certain value in an array of JSON objects. ES6 has an array.find, but it doesn't work in JScript. Because I knew the method existed, I looked it up on MDN (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find) and if you scroll down you'll see a Polyfill. That's a piece of code that allows older browsers to implement the new functionality. I just copied that polyfill to my code, and voilá! array.find now works for me.
The JS ecosystem is vast, and ever changing. Unfortunately most of it has moved on from the IE9 browser that JScript implements. Rather than trying to learn it all (and particularly a version 7 years old), your best bet is to google around and ask in here.
Additionally, looking for a way to have a different image on hover for these buttons:
// ==PREPROCESSOR==
// @name "Playback Buttons"
// @author "marc2003"
// @import "%fb2k_profile_path%js_marc2003\js\lodash.min.js"
// @import "%fb2k_profile_path%js_marc2003\js\helpers.js"
// @import "%fb2k_profile_path%js_marc2003\js\panel.js"
// ==/PREPROCESSOR==
var panel = new _.panel("Playback Buttons", ["custom_background"]);
var buttons = new _.buttons();
var bs = 27;
buttons.update = function () {
this.buttons.previous = new _.button(0, 0, bs, bs, {normal : "buttons\\track_previous.png"}, function () { fb.Prev(); }, "");
this.buttons.play = new _.button(30, 0, bs, bs, {normal : !fb.IsPlaying || fb.IsPaused ? "buttons\\play.png" : "buttons\\pause.png"}, function () { fb.PlayOrPause(); }, !fb.IsPlaying || fb.IsPaused ? "" : "");
this.buttons.next = new _.button(60, 0, bs, bs, {normal : "buttons\\track_next.png"}, function () { fb.Next(); }, "");
}
function on_size() {
panel.size();
buttons.update();
}
function on_paint(gr) {
panel.paint(gr);
buttons.paint(gr);
}
function on_playback_stop() {
buttons.update();
window.Repaint();
}
function on_playback_pause() {
buttons.update();
window.Repaint();
}
function on_playback_starting() {
buttons.update();
window.Repaint();
}
function on_mouse_move(x, y) {
buttons.move(x, y);
}
function on_mouse_leave() {
buttons.leave();
}
function on_mouse_lbtn_up(x, y) {
buttons.lbtn_up(x, y);
}
function on_mouse_rbtn_up(x, y) {
return panel.rbtn_up(x, y);
}
I've been modifying an old marc2003 code I had in order for it to fit my setup, and my problem is the elapsed playback time (%playback_time% /") only updates when I refresh the panel (so for example play/pause the song).
Try:
if (fb.PlaybackLength > 0) {
gr.GdiDrawText(_.tfe("%playback_time% /"), gdi.Font("Helvetica Light", 16), colours.time, 82, 43, 110, LEFT);
}
Thanks but it doesn't work. It displays it, but still doesn't refresh.
I've been modifying an old marc2003 code I had in order for it to fit my setup, and my problem is the elapsed playback time (%playback_time% /") only updates when I refresh the panel (so for example play/pause the song). It drives me nuts, if anyone has any idea on how to fix it, please:
gr.GdiDrawText(_.tfe("%playback_time% /"), gdi.Font("Helvetica Light", 16), colours.time, 82, 43, 110, LEFT);
You're missing a coordinate in that line. Unsure if that would break stuff, but it's possible.
Thanks but it doesn't work. It displays it, but still doesn't refresh.
Did you see my post with the on_playback_time code? Without that callback it's never going to update unless you manually draw in a loop (which would be REALLY dumb).
As for AJAX , MordredKLB was referring to AJAX = Asynchronous JavaScript And XML (https://www.w3schools.com/xml/ajax_intro.asp) that is possible by using ActiveX object. (Microsoft.XMLHTTP)https://www.w3schools.com/xml/ajax_xmlhttprequest_create.asp (https://www.w3schools.com/xml/ajax_xmlhttprequest_create.asp)
So, let me get this straight: are all the methods of the XMLHttpRequest object listed in the w3schools AJAX chapter, available in JScript panel as methods of the Microsoft.XMLHTTP object?
Here is a link for the basics.
https://developer.mozilla.org/en-US/docs/Web/Guide/AJAX/Getting_Started (https://developer.mozilla.org/en-US/docs/Web/Guide/AJAX/Getting_Started)
Thanks but it doesn't work. It displays it, but still doesn't refresh.
Did you see my post with the on_playback_time code? Without that callback it's never going to update unless you manually draw in a loop (which would be REALLY dumb).
I'm also using a script based on marc2003's samples, but it doesn't call on_playback_time anywhere. (!)
My elapsed time code is in an on_paint function which came from the Seekbar sample. It turns out that Seekbar.js continually checks fb.IsPlaying and calls for a refresh if it is, obviating the use of on_playback_time. I wondered what I was doing right....
@firewater Sorry for wasting your time.
My elapsed time code is in an on_paint function which came from the Seekbar sample. It turns out that Seekbar.js continually checks fb.IsPlaying and calls for a refresh if it is, obviating the use of on_playback_time. I wondered what I was doing right....
I haven't looked at that code, but I assume it was doing something similar to:
setInterval(function () {
if (fb.IsPlaying) window.Repaint();
},1000);
That's fine and will obviously work, but the callback is a much cleaner and more accurate way to do it and will have less wasted repaints (which are probably trivial in most cases/themes, but a full repaint for me can take 30-40ms).
I haven't looked at that code, but I assume it was doing something similar to:
setInterval(function () {
if (fb.IsPlaying) window.Repaint();
},1000);
That's fine and will obviously work, but the callback is a much cleaner and more accurate way to do it and will have less wasted repaints (which are probably trivial in most cases/themes, but a full repaint for me can take 30-40ms).
It does that, save for more tests in the "if" and "150" instead of the "1000" in your example. I assume that's milliseconds, and that the smaller interval is needed for smoothly animating the moving seek button.
I'll keep the callback in mind for when I rewrite my scripts. Thanks for the lesson!
Well you do bring up an interesting point. If you've just got a time counter (which appeared to be what
@firewater was doing) then on_playback_time is what you want to use. If you're trying to animate a progress bar, you very well might want to update it more frequently.
I actually do just this in my script, and I figured it would be cool to smoothly fill the progress bar 1 pixel at a time (if possible). In on_playback_new_track() I call a function I wrote called SetProgressBarRefresh():
function SetProgressBarRefresh()
{
if (fb.PlaybackLength > 0) {
t_interval = Math.abs(Math.ceil(1000/(progressBarWidth/fb.PlaybackLength))); // we want to update the progress bar for every pixel so divide total time by number of pixels in progress bar
if (t_interval < 25) {
t_interval = 25; // if interval is too low your refreshes can stack up. Refreshing 40x a second max seems reasonable
}
if (showDebugTiming)
console.log("Progress bar will update every " + t_interval + "ms or " + 1000/t_interval + " times per second.");
timer && window.ClearInterval(timer);
timer = null;
if (!fb.IsPaused) { // only create timer if actually playing
timer = window.SetInterval(function() {
refresh_seekbar();
}, t_interval);
}
}
}
refreshProgressBar() {
window.RepaintRect(<<exact dimensions of my progressBar so I don't redraw more stuff>>)
}
timer and t_interval are global variables. progressBarWidth is the width of the progress bar I want to fill. I only redraw the progressBar itself because there's a lot of other crap in my jscript panel. If the only thing in your script is a progress bar then who cares... just to windowRepaint().
This isn't complete because you'll need to clear the timer when the playback stops, and also when paused. You'd also need to call SetProgressBarRefresh in on_size() and when unpausing. There's probably some more stuff too, but that's how I do it. Obviously the draw code is up to you, but Math.floor(progressBarLength * fb.PlaybackTime / fb.PlaybackLength) is the way to calculate the number of pixels of your progressbar to fill.
Math.floor(progressBarLength * fb.PlaybackTime / fb.PlaybackLength) is the way to calculate the number of pixels of your progressbar to fill.
It's Math.ceil in the posted code. Is that what you meant?
I've added your post to my samples/notes library for future use. Thanks for another lesson.
Well when calculating the interval between refreshes I probably wanted the number to be bigger rather than smaller so that when the interval elapsed you could be sure it was always adding at least one to the fill.
Math.floor rounds down, Math.ceil rounds up, and Math.round roundest to the nearest. When actually drawing a progress bar you probably want to always round one direction or the other, but it doesn't really matter which.
Does a Coverflow script for newest JScript Panel exist? The only script I found is: https://br3tt.deviantart.com/art/WSH-CoverFlow-290788027 by Br3tt on Deviantart, but this is only for the old WSH panel mod.
Does a Coverflow script for newest JScript Panel exist? The only script I found is: https://br3tt.deviantart.com/art/WSH-CoverFlow-290788027 by Br3tt on Deviantart, but this is only for the old WSH panel mod.
it is necessary to replace
window.GetColor by
window.GetColour if(g_instancetype == 0) { // CUI
g_textcolor = window.GetColourCUI(ColorTypeCUI.text);
g_textcolor_sel = window.GetColourCUI(ColorTypeCUI.selection_text);
g_textcolor_hl = window.GetColourCUI(ColorTypeCUI.active_item_frame);
g_backcolor = window.GetColourCUI(ColorTypeCUI.background);
g_backcolor_sel = window.GetColourCUI(ColorTypeCUI.selection_background);
} else if(g_instancetype == 1) { // DUI
g_textcolor = window.GetColourDUI(ColorTypeDUI.text);
g_textcolor_sel = window.GetColourDUI(ColorTypeDUI.selection);
g_textcolor_hl = window.GetColourDUI(ColorTypeDUI.highlight);
g_backcolor = window.GetColourDUI(ColorTypeDUI.background);
g_backcolor_sel = g_textcolor_sel;
};
and replace
fb.IsAutoPlaylist by
plman.IsAutoPlaylist _child01.AppendMenuItem((plman.IsAutoPlaylist(panel.active_playlist))?MF_DISABLED|MF_GRAYED:MF_STRING, 1000, "Remove");
_child02.AppendTo(_child01, MF_STRING, "Add to...");
_child02.AppendMenuItem(MF_STRING, 2000, "a New playlist...");
_child02.AppendMenuItem(MF_SEPARATOR, 0, "");
var pl_count = fb.PlaylistCount;
for(var i=0;i<pl_count;i++) {
if(i!=panel.active_playlist && !plman.IsAutoPlaylist(i)) {
_child02.AppendMenuItem(MF_STRING, 2001+i, plman.GetPlaylistName(i));
};
};
Works, thanks!
what about "EnableMenuItem(id_or_pos, enable, bypos = false)" in jscript panel. Can not find.
See https://github.com/marc2k3/foo_jscript_panel/wiki/Breaking-Changes#v203
why ....
TheQwertiest, thanks
marc2k3, is it possible to return EnableMenuItem
marc2k3, is it possible to return EnableMenuItem
There's no need for EnableMenuItem, and it was rightly removed.
Replace your EnableMenuItem calls with something like this:
_menu.AppendMenuItem(pref.displayArt ? MF_STRING : MF_DISABLED, 5, 'Display Album Art');
marc2k3, is it possible to return EnableMenuItem
There's no need for EnableMenuItem, and it was rightly removed.
Replace your EnableMenuItem calls with something like this:
_menu.AppendMenuItem(pref.displayArt ? MF_STRING : MF_DISABLED, 5, 'Display Album Art');
I know that.
I understand if new functions are added that give new opportunities.
but why remove the old convenient features.
I do not understand
I know that.
I understand if new functions are added that give new opportunities.
but why remove the old convenient features.
I do not understand
Because it is not really 'convenient', but rather useless. EnableMenuItem would be only useful if the menu could be kept open after clicking on it (i.e. dynamically update a currently open menu), which is not possible in JScript anyway. It would be a different case, if there was some unique functionality that is only available through EnableMenuItem, but all of it's functionality is available through AppendMenuItem flags.
In the old wsh_panel component there were quite a few methods with duplicated functionality, which made scripting interface unnecessary bloated. Removing them allows for easier component development and maintenance.
PS: And I abhor the 'Microsoft' way - indefinite support of the deprecated functionality, which causes a lot of their API to be over-complicated because of the compatibility reasons.
Hi,
With the latest jscript panel release, there is a new dodragDrop functionality, which is great, now we can do drag and drop between jscript panels (for the moment, you can't do drag and drop within the same panel and outside the panel at the same time, you have to choose between both actions, but it's the only flaw)
My issue is that an empty semi-transparent rectangle is drawn while dragging tracks next to the mouse pointer, it look a little bit buggy (on windows, this rectangle contain a preview of the dragged content, for ex file icons, but here the rectangle is just empty), is there a way to remove this rectangle ?
(https://thumb.ibb.co/iKSX5S/Untitled_1.png) (https://ibb.co/iKSX5S)
for the moment, you can't do drag and drop within the same panel and outside the panel at the same time, you have to choose between both actions, but it's the only flaw
Well, that is not really true, since in my playlist script I'm using drag-n-drop API for both actions =)
I.e. you just have to implement it correctly :P
My issue is that an empty semi-transparent rectangle is drawn while dragging tracks next to the mouse pointer, it look a little bit buggy (on windows, this rectangle contain a preview of the dragged content, for ex file icons, but here the rectangle is just empty), is there a way to remove this rectangle ?
Currently, image for dragging is generated by fb2k interface itself, so this is the intended behaviour of JScript (the square does not look as ugly on my system though (Win7/Win10), it is also quite weird that you don't have a cursor displayed in that drag). I will try to investigate if it's possible to make it prettier (e.g. like CUI playlist) and in case of success will present the results to @marc2003 for approval.
[EDIT] Darn, if we want to change the drag image, the whole image must be generated manually (aero/glass effects and all)...
[EDIT2] Hm, I think it's possible to add the text to that rectangle without much hassle...
Well, that is not really true, since in my playlist script I'm using drag-n-drop API for both actions =)
I.e. you just have to implement it correctly :P
Do you have a link to this playlist script, so i can look to the code ? I tried to download and install CaTRoX_QWR from the link in your signature, but i didn't find any external drag and drop.
Currently, the best i'm able to do is to do an internal drag and drop by default, and switch to an external drag and drop when the cursor goes out of the panel limits. But i can't switch back to a internal drag and drop if i move the cursor back into the panel
Currently, image for dragging is generated by fb2k interface itself, so this is the intended behaviour of JScript (the square does not look as ugly on my system though (Win7/Win10), it is also quite weird that you don't have a cursor displayed in that drag). I will try to investigate if it's possible to make it prettier (e.g. like CUI playlist) and in case of success will present the results to @marc2003 for approval.
Thanks for taking a look! About the cursor, it's just because my screen capture tool doesn't show the cursor. The cursor is there
Do you have a link to this playlist script, so i can look to the code ? I tried to download and install CaTRoX_QWR from the link in your signature, but i didn't find any external drag and drop.
Currently, the best i'm able to do is to do an internal drag and drop by default, and switch to an external drag and drop when the cursor goes out of the panel limits. But i can't switch back to a internal drag and drop if i move the cursor back into the panel
I have yet to release the updated theme (since I'm waiting for
@WilB :P), but you can get it manually from git:
- Download repo as zip.
- Extract themes folder content to ...\foobar2000\themes\CaTRoX\ (e.g. CaTRoX_QWR\theme\Scripts > ...\foobar2000\themes\CaTRoX\Scripts)
- Import .fcl.
All the relevant drag-n-drop code is in Playlist script (https://github.com/TheQwertiest/CaTRoX_QWR/blob/master/theme/Scripts/Panel_Playlist.js):
https://github.com/TheQwertiest/CaTRoX_QWR/blob/a1be1e922542193ba7ca0cf9cbf17535f9adfe63/theme/Scripts/Panel_Playlist.js#L938
https://github.com/TheQwertiest/CaTRoX_QWR/blob/a1be1e922542193ba7ca0cf9cbf17535f9adfe63/theme/Scripts/Panel_Playlist.js#L961
https://github.com/TheQwertiest/CaTRoX_QWR/blob/a1be1e922542193ba7ca0cf9cbf17535f9adfe63/theme/Scripts/Panel_Playlist.js#L973
https://github.com/TheQwertiest/CaTRoX_QWR/blob/a1be1e922542193ba7ca0cf9cbf17535f9adfe63/theme/Scripts/Panel_Playlist.js#L1017
To anyone using
IntelliJ WebStorm,
IDEA or
Visual Studio Code to create/edit scripts:
I've updated JSDoc'd version of JScript's interface.txt (https://github.com/marc2k3/foo_jscript_panel/blob/master/foo_jscript_panel/docs/Interfaces.txt), which can be used as a plugin/library in WebStorm/IDEA/VisualCode.
This will remove most of 'undefined symbol' warnings and will also provide some type checks when using JScript interface.
Instructions:- Download all files from >>git<< (https://github.com/TheQwertiest/CaTRoX_QWR/tree/master/jscript_api) and put them in some folder.
- IntelliJ: File > Settings > Languages > JavaScript > Libraries > Add... > + > Attach Directories... > Choose folder from the previous step
- Visual Studio Code: instructions (https://stackoverflow.com/questions/45332052/how-to-add-an-api-to-visual-studio-code)
[EDIT] Darn, if we want to change the drag image, the whole image must be generated manually (aero/glass effects and all)...
[EDIT2] Hm, I think it's possible to add the text to that rectangle without much hassle...
Hi again,
So in the end, you didn't manage to find a way to remove this rectangle, or replace it with something which would make more sense ? Generating a gdi.Image for each drag and drop is completely fine, then it's up to the coder to do something which look nice/is useful in term of UI.
(About the drag and drop inside a panel / outside a panel, i managed to install your catrox theme, and yes, your code do what i'm trying to achieve in term of behavior, so i'm convinced now : ) i need to clean up my drag and drop code to make it work like yours.)
I am newbie to Jscript Panel so I have some questions:
1. I want to create a panel that will run external program (Spek) in that panel, and spek will show the spectrogram of file which is playing? Can I do it?
2. I am searching spectrogram seekbar and after lurking around I find that JScript Panel can create that. Can anyone help me to do that...
Thank you. Sorry for my bad English, it's not my native language
Apparently I was on a very old version 1.3.0 and decided to update just now. Unfortunately a ton of scripts in my skin broke. I fixed some errors regarding fb.trace and getcolorcui replacements but this one I can't beat:
Error: JScript Panel v2.1.0.2 (track info + seekbar + buttons by marc2003)
Microsoft JScript runtime error:
Object doesn't support this property or method
File: C:\Users\3\AppData\Roaming\foobar2000\js_marc2003\js\panel.js
Line: 65, Col: 5
<source text only available at compile time>
which is if (font) {
Please help :(
Apparently I was on a very old version 1.3.0 and decided to update just now. Unfortunately a ton of scripts in my skin broke. I fixed some errors regarding fb.trace and getcolorcui replacements but this one I can't beat:
Those scripts have been updated by marc. The one you want is located in: %appdata%\foobar2000\user-components\foo_jscript_panel\samples\complete\js\panel.js
Use that instead of the one you have installed to that location.
To anyone using IntelliJ WebStorm, IDEA or Visual Studio Code to create/edit scripts:
I've updated JSDoc'd version of JScript's interface.txt (https://github.com/marc2k3/foo_jscript_panel/blob/master/foo_jscript_panel/docs/Interfaces.txt), which can be used as a plugin/library in WebStorm/IDEA/VisualCode.
This will remove most of 'undefined symbol' warnings and will also provide some type checks when using JScript interface.
Instructions:
- Download all files from >>git<< (https://github.com/TheQwertiest/CaTRoX_QWR/tree/master/jscript_api) and put them in some folder.
- IntelliJ: File > Settings > Languages > JavaScript > Libraries > Add... > + > Attach Directories... > Choose folder from the previous step
- Visual Studio Code: instructions (https://stackoverflow.com/questions/45332052/how-to-add-an-api-to-visual-studio-code)
You are doing god's work, my friend. Thank you so much.
Apparently I was on a very old version 1.3.0 and decided to update just now. Unfortunately a ton of scripts in my skin broke. I fixed some errors regarding fb.trace and getcolorcui replacements but this one I can't beat:
Those scripts have been updated by marc. The one you want is located in: %appdata%\foobar2000\user-components\foo_jscript_panel\samples\complete\js\panel.js
Use that instead of the one you have installed to that location.
Thanks, I had an old path. Managed to salvage all but one panel.
I also moved to a JS version of smooth playlist (was using WSH), does anyone know how to alight text to the middle of the row vertically?
You'll need to find the DrawString call for those texts, and set the last parameter to be: StringFormat(0, 1)
I've found it's easier to set up objects to make handling those StringFormat calls easier, so I have this in my code:
var StringAlignment = {Near: 0, Center: 1, Far: 2};
// then you can use it like
gr.DrawString("blah", font, color, x, y, w, h, StringFormat(StringAlignment.Near, StringAlignment.Center));
// or
var leftCenter = StringFormat(StringAlignment.Near, StringAlignment.Center);
gr.DrawString("blah", font, color, x, y, w, h, leftCenter);
You'll also need to make sure the height for the text is the entire height of the row, and not just tall enough for the text.
You'll need to find the DrawString call for those texts, and set the last parameter to be: StringFormat(0, 1)
I've found it's easier to set up objects to make handling those StringFormat calls easier, so I have this in my code:
var StringAlignment = {Near: 0, Center: 1, Far: 2};
// then you can use it like
gr.DrawString("blah", font, color, x, y, w, h, StringFormat(StringAlignment.Near, StringAlignment.Center));
// or
var leftCenter = StringFormat(StringAlignment.Near, StringAlignment.Center);
gr.DrawString("blah", font, color, x, y, w, h, leftCenter);
You'll also need to make sure the height for the text is the entire height of the row, and not just tall enough for the text.
Thanks but I couldn't get it to work :P All I managed was to move heart icon via WSHplaylist.js :D
Another question, is there another option apart from fb.GetFocusItem() and fb.GetNowPlaying()?
I want to add tracks to queue with a single MMB click, fb.RunContextCommandWithMetadb("Add to playback queue",fb.GetFocusItem()) needs 2 clicks, first one to select the track with LMB and only then MMB to add to queue.
Hi,
I hope one of you kind folk can help. I'm a complete coding novice, but have been making small changes to the fantastic work done by others. Thing is, there's something i want to add but have hit a brick wall.
I'd like to add different images to the left of time elapsed on the seekbar depending on the codec of the track playing. So an image for MP3, a different one for FLAC etc etc, you get the picture. Along with that, another image that appears to the left of
that only if the track is greater than 16-bit. I've found scripts that do similar, but i can't get my head around what is required from them to achieve this. I've even attempted merging them into my existing edits, but have had nothing but inevitable errors ::) A lot of Googling and some headaches later, i've decided to admit defeat and ask those that know best!
So if anyone wouldn't mind a bit of hand-holding with a complete newb it'd be very very much appreciated...just assume you're talking to a child :)) I'm here to learn and improve my knowledge.
Code below and screenshot attached and again, thanks for any assistance guys.
// ==PREPROCESSOR==
// @name "Track Info + Seekbar + Buttons"
// @author "marc2003"
// @import "%fb2k_component_path%samples\complete\js\lodash.min.js"
// @import "%fb2k_component_path%samples\complete\js\helpers.js"
// @import "%fb2k_component_path%samples\complete\js\panel.js"
// @import "%fb2k_component_path%samples\complete\js\seekbar.js"
// ==/PREPROCESSOR==
var colours = {
background : _.RGB(30, 30, 30),
title : _.RGB(255, 255, 255),
artist : _.RGB(240, 240, 240),
codec : _.RGB(180, 180, 180),
album : _.RGB(180, 180, 180),
time : _.RGB(240, 240, 240),
seekbar_background : _.RGB(160, 160, 160),
seekbar_progress : _.RGB(255, 255, 255),
seekbar_knob : _.RGB(0, 120, 215)
};
var tfo = {
artist : fb.TitleFormat('%artist%'),
title : fb.TitleFormat('%title%'),
codec : fb.TitleFormat('%codec%'),
album : fb.TitleFormat('%album%'),
playback_time : fb.TitleFormat('%playback_time% '),
length : fb.TitleFormat(' %length%')
};
//////////////////////////////////////////////////////////////
var panel = new _.panel();
var seekbar = new _.seekbar(0, 0, 0, 0);
var buttons = new _.buttons();
var img = null;
var bs = _.scale(30);
on_playback_new_track(fb.GetNowPlaying());
buttons.update = function () {
var y = Math.round((panel.h - bs) / 1.7);
this.buttons.stop = new _.button(panel.w - LM - (bs * 13.0), y, bs, bs, {normal : 'buttons\\stop_grey_min.png'}, function () { fb.Stop(); }, 'Stop');
this.buttons.previous = new _.button(panel.w - LM - (bs * 11.7), y, bs, bs, {normal : 'buttons\\back_grey_min.png'}, function () { fb.Prev(); }, 'Previous');
this.buttons.play = new _.button(panel.w - LM - (bs * 10.4), y, bs, bs, {normal : !fb.IsPlaying || fb.IsPaused ? 'buttons\\play_grey_min.png' : 'buttons\\pause_grey_min.png'}, function () { fb.PlayOrPause(); }, !fb.IsPlaying || fb.IsPaused ? 'Play' : 'Pause');
this.buttons.next = new _.button(panel.w - LM - (bs * 9.1), y, bs, bs, {normal : 'buttons\\next_grey_min.png'}, function () { fb.Next(); }, 'Next');
this.buttons.random = new _.button(panel.w - LM - (bs * 4.9), y, bs, bs, {normal : 'buttons\\shuffle_grey_min.png'}, function () { fb.Random(); }, 'Random');
this.buttons.console = new _.button(panel.w - LM - (bs * 3.6), y, bs, bs, {normal : 'buttons\\console_grey_min.png'}, function () { fb.ShowConsole(); }, 'Console');
this.buttons.search = new _.button(panel.w - LM - (bs * 2.3), y, bs, bs, {normal : 'buttons\\search_grey_min.png'}, function () { fb.RunMainMenuCommand('Library/Search'); }, 'Library Search');
this.buttons.preferences = new _.button(panel.w - LM - bs, y, bs, bs, {normal : 'buttons\\settings_grey_min.png'}, function () { fb.ShowPreferences(); }, 'Preferences');
}
function on_size() {
panel.size();
seekbar.x = Math.round(panel.w * 0.32);
seekbar.w = panel.w - seekbar.x - _.scale(500);
seekbar.h = _.scale(12);
seekbar.y = (panel.h - seekbar.h) / 2;
buttons.update();
}
function on_paint(gr) {
gr.FillSolidRect(0, 0, panel.w, panel.h, colours.background);
buttons.paint(gr);
gr.FillSolidRect(seekbar.x, seekbar.y, seekbar.w + _.scale(6), seekbar.h, colours.seekbar_background);
if (fb.IsPlaying) {
if (img) {
_.drawImage(gr, img, 0, 0, panel.h, panel.h, image.centre);
}
gr.GdiDrawText(tfo.title.Eval(), panel.fonts.title, colours.title, panel.h + 10, 0, seekbar.x - panel.h - _.scale(60), panel.h * 0.4, LEFT);
gr.GdiDrawText(tfo.artist.Eval(), panel.fonts.normal, colours.artist, panel.h + 10, panel.h * 0.3, seekbar.x - panel.h - _.scale(60), panel.h * 0.4, LEFT);
gr.GdiDrawText(tfo.album.Eval(), panel.fonts.normal, colours.album, panel.h + 10, panel.h * 0.3, seekbar.x - panel.h - _.scale(60), panel.h * 1.0, LEFT);
gr.GdiDrawText(tfo.codec.Eval(), panel.fonts.normal, colours.codec, panel.h + 500, panel.h * 0.3, seekbar.x - panel.h - _.scale(60), panel.h * 0.4, LEFT);
gr.SetSmoothingMode(2);
if (fb.PlaybackLength > 0) {
var pos = seekbar.pos();
gr.FillSolidRect(seekbar.x, seekbar.y, pos, seekbar.h, colours.seekbar_progress);
gr.FillSolidRect(seekbar.x + pos, seekbar.y, _.scale(6), seekbar.h, colours.seekbar_knob);
gr.GdiDrawText(tfo.playback_time.Eval(), panel.fonts.normal, colours.time, seekbar.x - _.scale(45), 0, _.scale(45), panel.h, RIGHT);
gr.GdiDrawText(tfo.length.Eval(), panel.fonts.normal, colours.time, seekbar.x + seekbar.w + _.scale(6), 0, _.scale(45), panel.h, LEFT);
}
}
gr.DrawRect(seekbar.x, seekbar.y, seekbar.w + _.scale(6), seekbar.h, 1, colours.seekbar_progress);
}
function on_playback_new_track(metadb) {
if (!metadb) {
return;
}
_.dispose(img);
img = utils.GetAlbumArtV2(metadb, 0);
window.Repaint();
}
function on_playback_edited() {
window.Repaint();
}
function on_playback_seek() {
seekbar.playback_seek();
}
function on_playback_stop() {
buttons.update();
window.Repaint();
}
function on_playback_pause() {
buttons.update();
window.Repaint();
}
function on_playback_starting() {
buttons.update();
window.Repaint();
}
function on_mouse_wheel(s) {
if (seekbar.wheel(s)) {
return;
}
if (s == 1) {
fb.VolumeUp();
} else {
fb.VolumeDown();
}
}
function on_mouse_move(x, y) {
if (buttons.move(x, y)) {
return;
}
seekbar.move(x, y);
}
function on_mouse_leave() {
buttons.leave();
}
function on_mouse_lbtn_down(x, y) {
seekbar.lbtn_down(x, y);
}
function on_mouse_lbtn_up(x, y) {
if (buttons.lbtn_up(x, y)) {
return;
}
if (seekbar.lbtn_up(x, y)) {
return;
}
fb.RunMainMenuCommand('View/Show now playing in playlist');
}
function on_mouse_rbtn_up(x, y) {
return panel.rbtn_up(x, y);
}
Hi again,
So in the end, you didn't manage to find a way to remove this rectangle, or replace it with something which would make more sense ? Generating a gdi.Image for each drag and drop is completely fine, then it's up to the coder to do something which look nice/is useful in term of UI.
I kinda forgot about it =)
I will work on it a bit later, when I catch up with some IRL stuff...
(About the drag and drop inside a panel / outside a panel, i managed to install your catrox theme, and yes, your code do what i'm trying to achieve in term of behavior, so i'm convinced now : ) i need to clean up my drag and drop code to make it work like yours.)
Glad that it worked out ;)
You are doing god's work, my friend. Thank you so much.
You are welcome ;)
Another question, is there another option apart from fb.GetFocusItem() and fb.GetNowPlaying()?
I want to add tracks to queue with a single MMB click, fb.RunContextCommandWithMetadb("Add to playback queue",fb.GetFocusItem()) needs 2 clicks, first one to select the track with LMB and only then MMB to add to queue.
Not entirely sure what's the problem, you can do all of this in one call. Smth like this:
function on_mouse_mbtn_down(x,y,m) {
var item_idx;
...
// Calculate item index
...
plman.SetPlaylistFocusItem(plman.ActivePlaylist, item_idx);
plman.AddPlaylistItemToPlaybackQueue(plman.ActivePlaylist, item_idx);
}
I'd like to add different images to the left of time elapsed on the seekbar depending on the codec of the track playing. So an image for MP3, a different one for FLAC etc etc, you get the picture. Along with that, another image that appears to the left of that only if the track is greater than 16-bit. I've found scripts that do similar, but i can't get my head around what is required from them to achieve this. I've even attempted merging them into my existing edits, but have had nothing but inevitable errors ::) A lot of Googling and some headaches later, i've decided to admit defeat and ask those that know best!
I'm not going to do all the heavy lifting for you, but I'll show you what I've done to accomplish something similar. Some of this code was written years ago, and the style may not be great, so change it as needed.
First off I'm assuming you have the images you want to display already in a folder somewhere. Let's call it /images/codecs
At the top of your file where you setup your globals:
var mediaTypeImg = null;
var pref = {};
pref.codec_base = fb.ProfilePath + 'images/codecs';
// gets the correct image
function LoadMediaTypeImage() {
_.dispose(mediaTypeImg);
if (pref.show_codec_img) {
codec = fb.TitleFormat("[%codec%]").Eval();
switch (codec) {
case "DTS":
mediaTypeImg = gdi.Image(pref.codec_base+"DTS.png");
break;
case "ATSC A/52":
mediaTypeImg = gdi.Image(pref.codec_base+"Dolby Digital.png");
break;
case "FLAC":
mediaTypeImg = gdi.Image(pref.codec_base+"FLAC.png");
break;
case "Vorbis":
mediaTypeImg = gdi.Image(pref.codec_base+"Ogg.png");
break;
case "MP3":
mediaTypeImg = gdi.Image(pref.codec_base+"mp3.png");
break;
case "default":
console.log("Unknown codec: "+codec);
break;
}
}
return;
}
Then in your on_playback_new_track before window.Repaint(); call LoadMediaTypeImage(), and dispose the mediaTypeImg in on_playback_stop()
Now all you need to do is add the code to display the image in your on_paint callback which should be fairly trivial. Just do an:
// you'll need to figure out what the x, y, w, and h should be
if (mediaTypeImg) {
gr.DrawImage(mediaTypeImg, x, y, w, h, 0, 0, mediaTypeImg.Width, mediaTypeImg.Height, 0);
}
If you want to check for 24-bit or whatever you can also do that in the LoadMediaTypeImg function and only set that image if bit-depth > 16.
Hope that helps.
Another question, is there another option apart from fb.GetFocusItem() and fb.GetNowPlaying()?
I want to add tracks to queue with a single MMB click, fb.RunContextCommandWithMetadb("Add to playback queue",fb.GetFocusItem()) needs 2 clicks, first one to select the track with LMB and only then MMB to add to queue.
Not entirely sure what's the problem, you can do all of this in one call. Smth like this:
function on_mouse_mbtn_down(x,y,m) {
var item_idx;
...
// Calculate item index
...
plman.SetPlaylistFocusItem(plman.ActivePlaylist, item_idx);
plman.AddPlaylistItemToPlaybackQueue(plman.ActivePlaylist, item_idx);
}
Thanks for your reply! It adds track #1 of current playlist to the queue no matter which track I click on though.
Thanks for your reply! It adds track #1 of current playlist to the queue no matter which track I click on though.
Welp, that's because you have to implement "// Calculate item index" part yourself :P
I'd like to add different images to the left of time elapsed on the seekbar depending on the codec of the track playing. So an image for MP3, a different one for FLAC etc etc, you get the picture. Along with that, another image that appears to the left of that only if the track is greater than 16-bit. I've found scripts that do similar, but i can't get my head around what is required from them to achieve this. I've even attempted merging them into my existing edits, but have had nothing but inevitable errors ::) A lot of Googling and some headaches later, i've decided to admit defeat and ask those that know best!
I'm not going to do all the heavy lifting for you, but I'll show you what I've done to accomplish something similar. Some of this code was written years ago, and the style may not be great, so change it as needed.
First off I'm assuming you have the images you want to display already in a folder somewhere. Let's call it /images/codecs
At the top of your file where you setup your globals:
var mediaTypeImg = null;
var pref = {};
pref.codec_base = fb.ProfilePath + 'images/codecs';
// gets the correct image
function LoadMediaTypeImage() {
_.dispose(mediaTypeImg);
if (pref.show_codec_img) {
codec = fb.TitleFormat("[%codec%]").Eval();
switch (codec) {
case "DTS":
mediaTypeImg = gdi.Image(pref.codec_base+"DTS.png");
break;
case "ATSC A/52":
mediaTypeImg = gdi.Image(pref.codec_base+"Dolby Digital.png");
break;
case "FLAC":
mediaTypeImg = gdi.Image(pref.codec_base+"FLAC.png");
break;
case "Vorbis":
mediaTypeImg = gdi.Image(pref.codec_base+"Ogg.png");
break;
case "MP3":
mediaTypeImg = gdi.Image(pref.codec_base+"mp3.png");
break;
case "default":
console.log("Unknown codec: "+codec);
break;
}
}
return;
}
Then in your on_playback_new_track before window.Repaint(); call LoadMediaTypeImage(), and dispose the mediaTypeImg in on_playback_stop()
Now all you need to do is add the code to display the image in your on_paint callback which should be fairly trivial. Just do an:
// you'll need to figure out what the x, y, w, and h should be
if (mediaTypeImg) {
gr.DrawImage(mediaTypeImg, x, y, w, h, 0, 0, mediaTypeImg.Width, mediaTypeImg.Height, 0);
}
If you want to check for 24-bit or whatever you can also do that in the LoadMediaTypeImg function and only set that image if bit-depth > 16.
Hope that helps.
Thanks so much for taking the time to give some advice and reply Mordred, and yes I'd certainly rather do the bulk of it myself. How else will I learn!? I will have a proper go at getting it to work at the weekend once I have the time (can see it taking a while!)
I may ask some seemingly stupid questions though...I hope that's ok? (total novice remember).
So the variables can be added below the existing ones in my code? (i.e. before the buttons.update) The code layout is split into sections yes?
Then in your on_playback_new_track before window.Repaint(); call LoadMediaTypeImage(), and dispose the mediaTypeImg in on_playback_stop() I'm sure this probably is easy, but it has thrown me a bit!
Thanks, and again sorry for the probably ridiculously obvious questions. Its very difficult to find much online about how these work though.
Appreciate it Mordred
Jamie
Thanks so much for taking the time to give some advice and reply Mordred, and yes I'd certainly rather do the bulk of it myself. How else will I learn!? I will have a proper go at getting it to work at the weekend once I have the time (can see it taking a while!)
I may ask some seemingly stupid questions though...I hope that's ok? (total novice remember).
So the variables can be added below the existing ones in my code? (i.e. before the buttons.update) The code layout is split into sections yes?
There are other variables declared in you script, you can just add them there. I'm confused what you mean by code being split into sections. It's split into functions. I know you said you're new to all of this, so it might be worthwhile checking out a super basic javascript tutorial just so you understand a little bit more about how all this works.
Then in your on_playback_new_track before window.Repaint(); call LoadMediaTypeImage(), and dispose the mediaTypeImg in on_playback_stop() I'm sure this probably is easy, but it has thrown me a bit!
i.e. just do:
function on_playback_new_track(metadb) {
if (!metadb) {
return;
}
_.dispose(img);
img = utils.GetAlbumArtV2(metadb, 0);
LoadMediaTypeImage();
window.Repaint();
}
And just toss a
_.dispose(mediaTypeImg); into your on_playback_stop() function.
I've got a playlist in my theme (based on CatRox) and I had a crazy idea that I'm not sure is possible. What I'd like is to turn certain strings in the playlist into buttons (I know how to do this part), which when clicked on will populate a playlist. I.e. Where I list the Artist in the playlist if you clicked on the artist name, it would populate a playlist with all songs from that artist, and set it to active. It'd be like playlist hyperlinks.
Is it possible to create/populate a playlist based on strings from jscript? I confess I haven't really looked into this, just hoping someone can save me some time and trial/error here.
You could create an autoplaylist
plman.CreateAutoPlaylist , using the string in the query and then switch to that playlist.
You can find a sample in marc2003 samples, autoplaylist.txt and the code in list.js
One thing though: autoplaylists are read-only, so you'll have to copy it, if you want to have ability to edit it afterwords.
One thing though: autoplaylists are read-only, so you'll have to copy it, if you want to have ability to edit it afterwords.
I'm assuming you mean I can't edit it from jscript. Can I at least delete the auto-playlist? I'd hate to have dozens of these things clogging up my playlists dropdown.
I'm assuming you mean I can't edit it from jscript. Can I at least delete the auto-playlist? I'd hate to have dozens of these things clogging up my playlists dropdown.
Autoplaylists are not editable in fb2k in general, not just in JScript =)
You can modify playlist itself (move\delete\rename etc), but you can't modify it's contents.
fb.GetQueryItems(handle_list, query); (IFbMetadbHandleList) is another possibility
Gives handle list that can add to playlist etc, e.g.
var b = fb.GetQueryItems(fb.GetLibraryItems(), "artist IS Madonna");
Results are unsorted.
NOTE: Use try/catch to handle invalid queries. An empty handle list will be returned if the query is valid but there are no results.
Autoplaylists are not editable in fb2k in general, not just in JScript =)
You can modify playlist itself (move\delete\rename etc), but you can't modify it's contents.
Haha, I thought you were trying to say you couldn't modify the query. Yes I realize you can't delete the contents.
var b = fb.GetQueryItems(fb.GetLibraryItems(), "artist IS Madonna");
Results are unsorted.
NOTE: Use try/catch to handle invalid queries. An empty handle list will be returned if the query is valid but there are no results.
Yeah, I was going through interfaces.txt and literally just saw that.
But then with that it looks like I can do:
plman.FindOrCreatePlaylist <- get my special "selected object" playlist
plman.ClearPlaylist
plman.InsertPlaylistItems <- insert that handle_list into the playlist
plman.SortByFormatV2
Boom, done. Thanks guys! This will be a fun project tonight.
foo_jscript_panel\samples\complete\last.fm bio.txt
Some characters cannot be displayed properly.
e.g. "Lou Reed & Metallica" will show "Lou Reed _Metallica".
Hi!
@marc2003
Please make dialogs window (do not full screen) like this :
http://jpegshare.net/a6/5f/a65f641edb1185583910ba040405d896.png.html
http://jpegshare.net/20/d1/20d148ada69b02b63cd236aed5ed6c14.png.html
I have this script by marc2003, which I've edited a little. I'm wondering how can I make the album cover image have a 1px grey border?
// ==PREPROCESSOR==
// @name "track info + seekbar + buttons"
// @author "marc2003"
// @import "%fb2k_profile_path%js_marc2003\js\lodash.min.js"
// @import "%fb2k_profile_path%js_marc2003\js\helpers.js"
// @import "%fb2k_profile_path%js_marc2003\js\panel.js"
// @import "%fb2k_profile_path%js_marc2003\js\seekbar.js"
// ==/PREPROCESSOR==
//note the buttons are white and you'd have to edit the images to change them...
var colours = {
background : _.RGB(255, 255, 255),
title : _.RGB(55, 49, 53),
artist : _.RGB(95, 95, 95),
};
//////////////////////////////////////////////////////////////
var panel = new _.panel("track info + seekbar + buttons");
var seekbar = new _.seekbar(60, 5, 0, 20);
var buttons = new _.buttons();
var img = null;
on_playback_new_track();
buttons.update = function () {
var y = _.round((panel.h - 36) / 1);
}
function on_size() {
panel.size();
seekbar.x = panel.h + 310
seekbar.w = panel.w - panel.h - 710;
seekbar.y = (panel.h - 20) / 2;
buttons.update();
}
function on_paint(gr) {
if (fb.PlaybackLength > 0) {
img && _.drawImage(gr, img, 12, 12, 50, 50, image.centre);
gr.GdiDrawText(_.tfe("%title%"), gdi.Font("Helvetica", 16), colours.title, 75, 10, 400, 40, LEFT);
gr.GdiDrawText(_.tfe("%artist% l %album%"), gdi.Font("Helvetica Light", 16), colours.artist, 75, 32, 400, 30, LEFT);
}
}
function on_playback_new_track() {
var metadb = fb.GetNowPlaying();
if (!metadb)
return;
_.dispose(img);
img = utils.GetAlbumArtV2(metadb, 0);
window.Repaint();
}
function on_playback_edited() {
window.Repaint();
}
function on_playback_seek() {
seekbar.playback_seek();
}
function on_playback_stop() {
buttons.update();
window.Repaint();
}
function on_playback_pause() {
buttons.update();
window.Repaint();
}
function on_playback_starting() {
buttons.update();
window.Repaint();
}
function on_mouse_wheel(s) {
buttons.leave();
}
function on_mouse_move(x, y) {
if (buttons.move(x, y))
return;
seekbar.move(x, y);
}
function on_mouse_leave() {
buttons.leave();
}
function on_mouse_lbtn_down(x, y) {
seekbar.lbtn_down(x, y);
}
function on_mouse_lbtn_up(x, y) {
if (buttons.lbtn_up(x, y))
return;
if (seekbar.lbtn_up(x, y))
return;
fb.RunMainMenuCommand("View/Show now playing in playlist");
}
function on_mouse_rbtn_up(x, y) {
return panel.rbtn_up(x, y);
}
Change on_paint(gr) to be:
function on_paint(gr) {
if (fb.PlaybackLength > 0) {
if (img) {
_.drawImage(gr, img, 12, 12, 50, 50, image.centre);
gr.DrawRect(11, 11, 51, 51, 1, _.RGB(96,96,96);
}
gr.GdiDrawText(_.tfe("%title%"), gdi.Font("Helvetica", 16), colours.title, 75, 10, 400, 40, LEFT);
gr.GdiDrawText(_.tfe("%artist% l %album%"), gdi.Font("Helvetica Light", 16), colours.artist, 75, 32, 400, 30, LEFT);
}
}
You might need to play with the coordinates and color in the DrawRect call to get things to your liking, but that should be a good start.
Thanks, worked perfectly.
What is the meaning of the fromhook parameter in the on_metadb_changed callback?
What is the meaning of the fromhook parameter in the on_metadb_changed callback?
I found this explanation in an old WSH panel mod document, but I hardly understand a word of this definition, probably because I have no idea of what the "metadb_display_field_provider" is:
fromhook: boolean, set to true when actual file contents haven't changed but one of metadb_display_field_provider implementations requested an update so output of metadb_handle::format_title() etc has changed.
Any clue?
I don't think it's anything you have to worry about typically.
When fromhook is true, it means that information in a metadb changed, but not the tags in the file itself. For example, if you're using foo_playcount and you rate a song 5 *s, on_metadb_changed will be called with fromhook = true. If you open up the properties dialog and change a song title and then OK out of the dialog, on_metadb_changed will be called with fromhook = false. I can't think of a single good reason you'd want to ignore one or the other type of metadb change, so it's possible it's mainly for informational purposes.
Thanks a lot for the explanation, Mordred.
I just upgraded from v1.3.2.2 to v2.1.4. I updated every script according to marc2003 instructions and everything works fine, but one panel, which crashes, warning me that "Object doesn't support this property or method". The referenced line, which as far as I can see shouldn't be affected by the breaking changes, is the following:
var filtered_list = _.uniq(autocomplete, true).filter(filterAutocomplete);
If it helps, the filter function is the following:
function filterAutocomplete(value){
return value.indexOf(text) == 0;
}
It's a search-box script, where
text is what is typed in the search-box and
autocomplete is an array of previous entries.
I just upgraded from v1.3.2.2 to v2.1.4. I updated every script according to marc2003 instructions and everything works fine, but one panel, which crashes, warning me that "Object doesn't support this property or method". The referenced line, which as far as I can see shouldn't be affected by the breaking changes, is the following:
var filtered_list = _.uniq(autocomplete, true).filter(filterAutocomplete);
One more clue: the problem seems to be gone after switching fom jscript to chakra engine.
One more clue: the problem seems to be gone after switching fom jscript to chakra engine.
The problem is caused by using different JS engines:
Chakra engine provides ECMA-5 support, while JScript provides ECMA-3 (with some extensions).
`Array.indexOf` is a ECMA-262 5th edition feature, so it is not available under JScript engine, which is used by default when migrating from v1.3.2.2 to v2.* (v1.3.2.2 used Chakra if it was available though).
The problem is caused by using different JS engines:
Chakra engine provides ECMA-5 support, while JScript provides ECMA-3 (with some extensions).
`Array.indexOf` is a ECMA-262 5th edition feature, so it is not available under JScript engine, which is used by default when migrating from v1.3.2.2 to v2.* (v1.3.2.2 used Chakra if it was available though).
Thanks, I was not aware of using the Chakra engine, with the previous version. I was actually not even aware that different jscript engines exist.
The plug-in uses system provided jscript engines, or else it would probably be significant in size, if it were, say, providing a complete copy of V8, like nodejs does.
@marc2003
I paid attention to the unexpected value of the variable time:undefined in the function on_playback_time(time) at the beginning of playback.
So it should be, or can it be fixed?
In script:
function on_playback_time(time) {
fb.trace(' --------- on_playback_time --- time: ' +time+ ' ---- fb.PlaybackTime: ' +fb.PlaybackTime);
In console:
Opening track for playback: .....
--------- on_playback_time --- time: undefined ---- fb.PlaybackTime: 0.14017006802721077
--------- on_playback_time --- time: 1 ---- fb.PlaybackTime: 1.1074625850340127
...
... or else it would probably be significant in size, if it were, say, providing a complete copy of V8, like nodejs does.
Dunno about V8, but SpiderMonkey (Firefox JS engine) takes only ~18Mb, so it's not really that bad =)
... or else it would probably be significant in size, if it were, say, providing a complete copy of V8, like nodejs does.
Dunno about V8, but SpiderMonkey (Firefox JS engine) takes only ~18Mb, so it's not really that bad =)
I'm hearing you say you're going to do a fork with spidermonkey and full ES6 support.... ;)
I'm hearing you say you're going to do a fork with spidermonkey and full ES6 support.... ;)
Yeah, but it is a pretty big undertaking, so it won't be ready any time soon... It will probably take months to reimplement all the features.
I am using GetColourSchemeJSON to create themed colors layouts based on album art.
I would appreciate any help on how to determine the best text color ( with JScript ) for the background color, as to achieve comfortable contrast.
Ignore my previous post, found a solution.
http://www.nbdtech.com/Blog/archive/2008/04/27/Calculating-the-Perceived-Brightness-of-a-Color.aspx
That algorithm uses different numbers than I've seen. My theme currently uses the w3c brightness recommendation for calculating these values (I have a color helper class which makes these things much easier https://github.com/kbuffington/Georgia/blob/master/js/color.js):
// brightness from 0-255 divide by 2.55 if you want 0-100%
Math.round(Math.sqrt( 0.299*this.r*this.r + 0.587*this.g*this.g + 0.114*this.b*this.b ));
I can share my color picking code if you're interested. I've spent months on it and finally pretty happy with it.
Thank you for your feedback and link.
I will use the algorithm you recommended.
I will have to study more to understand how to use the helper class, but you provided me a start point.
If you don't mind please share your colour picking code, you seem to have spent a long time implementing it.
As for JScript Panel, I wish interfaces also had
window.SetColourDUI / window.SetColourCUI
Then it would be possible to also change the colours of native panels via JScript script.
You use the Color class by just instantiating it with new and passing a color value. Like var col = new Color(rgb(255,0,0)); Then you can just do col.r or col.brightness or col.isCloseToGreyscale. col.val will spit the foobar color back out (pull the latest version of color.js from github because I just changed this 5 minutes ago).
Here's my color picker code which shows this in action:
function getThemeColor(image, maxColorsToPull, maxColors) {
var selectedColor;
var minFrequency = 0.015;
var colorsWeighted = [];
try {
colorsWeighted = JSON.parse(image.GetColourSchemeJson(maxColorsToPull));
colorsWeighted.forEach(function (c, i) {
colorsWeighted[i].col = new Color(c.col);
});
console.log('idx color bright freq weight');
maxWeight = 0;
selectedColor = colorsWeighted[0].col; // choose first color in case no color selected below
colorsWeighted.forEach(function (c, i) {
var col = c.col;
var midBrightness = 127 - Math.abs(127 - col.brightness); // favors colors with a brightness around 127
c.weight = c.freq * midBrightness * 10; // multiply by 10 so numbers are easier to compare
if (c.freq >= minFrequency && !col.isCloseToGreyscale && col.brightness < 212) {
console.log(leftPad(i, 2), col.getRGB(true,true), leftPad(col.brightness, 4), ' ', leftPad(parseFloat(c.freq*100).toFixed(2),5) + '%', leftPad(parseFloat(c.weight).toFixed(2), 7));
if (c.weight > maxWeight) {
maxWeight = c.weight;
selectedColor = col;
}
} else if (col.isCloseToGreyscale) {
console.log(' -', col.getRGB(true,true), leftPad(col.brightness, 4), ' ', leftPad(parseFloat(c.freq*100).toFixed(2),5) + '%', ' grey');
} else {
console.log(' -', col.getRGB(true,true), leftPad(col.brightness, 4), ' ', leftPad(parseFloat(c.freq*100).toFixed(2),5) + '%', leftPad(parseFloat(c.weight).toFixed(2), 7));
}
});
if (selectedColor.brightness < 39) {
console.log(selectedColor.getRGB(true), 'brightness:', selectedColor.brightness, 'too dark -- searching for highlight color');
brightest = selectedColor;
maxWeight = 0;
colorsWeighted.forEach(function (c, i) {
if (c.col.brightness > selectedColor.brightness &&
c.col.brightness < 200 &&
!c.col.isCloseToGreyscale &&
c.weight > maxWeight &&
c.freq > .01) {
maxWeight = c.weight;
brightest = c.col;
}
});
selectedColor = brightest;
}
console.log('Selected Color:', selectedColor.getRGB(true));
return selectedColor.val;
} catch (e) {
return undefined;
}
}
Here's the explanation. My theme requires that the theme color (which I use for some backgrounds) has white text and white logos on it. So I want to choose a color that looks good but isn't too bright. I also try and avoid colors that are greyscale or close to it (GetColourSchemeJson will often return colors like rgb(100,101,97) which are essentially greyscale) because those are pretty boring. On my first pass I only want to choose a color that appears at least 1.5% of the time. I also weight colors more with a brightness around 127 (this portion of the weighting is linear but I'd like it to be more of a gaussian weight but it works well enough).
If after the first pass I didn't find a suitable color, I do a second pass looking for basically the brightest non-greyscale color which appears at least 1% of the time. If that still doesn't find anything suitable I just return the very first color because the image is obviously completely greyscale or very close to it.
When running this I have a lot of logging to the console to see what's going on. Change your font to Consolas if you want it to be readable :)
Have a BIG request (question):
How to achieve the normal operation of timers after exit Sleep or Hibernate.
All timers of various JScript Panel scripts try to "catch up" with the system time.
Help, how to solve this?
@MordredKLB Thanks for sharing, your reply was very useful :)
foo_jscript_panel\samples\jsplaylist-mod\
Previously, JS common.js is enough for the playlist (JS Smooth Playlist) to work.
Why now import everything else ?? :
// @import "%fb2k_component_path%samples\jsplaylist-mod\js\WSHcommon.js"
// @import "%fb2k_component_path%samples\jsplaylist-mod\js\WSHinputbox.js"
// @import "%fb2k_component_path%samples\jsplaylist-mod\js\WSHtopbar.js"
// @import "%fb2k_component_path%samples\jsplaylist-mod\js\WSHscrollbar.js"
// @import "%fb2k_component_path%samples\jsplaylist-mod\js\WSHheaderbar.js"
// @import "%fb2k_component_path%samples\jsplaylist-mod\js\WSHplaylist.js"
// @import "%fb2k_component_path%samples\jsplaylist-mod\js\WSHplaylistmanager.js"
// @import "%fb2k_component_path%samples\jsplaylist-mod\js\WSHsettings.js"
// @import "%fb2k_component_path%samples\jsplaylist-mod\js\main.js
:(
..
I have one question. It seems that framestyle (none, gray , sunken) doesn't work for some old plugins in foobar v 1.4 , and also doesn't work for Jscript. 'Edge Style' is grayed out in Jscript and cant be selected. Would that be fixed? Thanks.
Can someone help me. How to get toolbar panel color? Which color is that?
I tried:
var CLR = 20;
g_syscolor = utils.GetSysColour(CLR);
This works. But i dont know which color is for toolbar?
I have been using the following definitions:
COLOR_SCROLLBAR 0
COLOR_BACKGROUND 1
COLOR_ACTIVECAPTION 2
COLOR_INACTIVECAPTION 3
COLOR_MENU 4
COLOR_WINDOW 5
COLOR_WINDOWFRAME 6
COLOR_MENUTEXT 7
COLOR_WINDOWTEXT 8
COLOR_CAPTIONTEXT 9
COLOR_ACTIVEBORDER 10
COLOR_INACTIVEBORDER 11
COLOR_APPWORKSPACE 12
COLOR_HIGHLIGHT 13
CLOR_HIGHLIGHTTEXT 14
COLOR_BTNFACE 15
COLOR_BTNSHADOW 16
COLOR_GRAYTEXT 17
COLOR_BTNTEXT 18
COLOR_INACTIVECAPTIONTEXT 19
COLOR_BTNHIGHLIGHT 20
I believe the toolbars use the COLOR_BTNFACE value.
I have been using the following definitions:
COLOR_SCROLLBAR 0
COLOR_BACKGROUND 1
COLOR_ACTIVECAPTION 2
COLOR_INACTIVECAPTION 3
COLOR_MENU 4
COLOR_WINDOW 5
COLOR_WINDOWFRAME 6
COLOR_MENUTEXT 7
COLOR_WINDOWTEXT 8
COLOR_CAPTIONTEXT 9
COLOR_ACTIVEBORDER 10
COLOR_INACTIVEBORDER 11
COLOR_APPWORKSPACE 12
COLOR_HIGHLIGHT 13
CLOR_HIGHLIGHTTEXT 14
COLOR_BTNFACE 15
COLOR_BTNSHADOW 16
COLOR_GRAYTEXT 17
COLOR_BTNTEXT 18
COLOR_INACTIVECAPTIONTEXT 19
COLOR_BTNHIGHLIGHT 20
I believe the toolbars use the COLOR_BTNFACE value.
No, i tried all that colors and even more, i cant get color for toolbar background.
I need this background color (so it should match OS, if its win 7 then it's blue if win 10 white) :
(https://s15.postimg.cc/gddqh1s6z/20180815_102801.png)
It appears that you are using Aero themes. In that case GetSysColour is not going to help you, as it only returns a single colour value.
If you look closely, the menu background is not a solid colour but a gradient, or maybe even a combination of two gradients depending on the theme.
I'm not aware of any documented ways of getting that info from the system. One thing you could try is extracting a sample of that pattern graphically from a screen shot and stretching it to the desired width.
That may cover your personal setups (until you make any changes in Windows themes), but a generic solution would be much more difficult to build.
It appears that you are using Aero themes. In that case GetSysColour is not going to help you, as it only returns a single colour value.
If you look closely, the menu background is not a solid colour but a gradient, or maybe even a combination of two gradients depending on the theme.
I'm not aware of any documented ways of getting that info from the system. One thing you could try is extracting a sample of that pattern graphically from a screen shot and stretching it to the desired width.
That may cover your personal setups (until you make any changes in Windows themes), but a generic solution would be much more difficult to build.
Yes, another way is to use:
function on_main_menu(index) {
Then i can put buttons on standard toolbar. I tried that and works fine. But problem is that popup menu which buttons open, cant folow button position on toolbar, it folows jscript panel position. So if i move button, menu wont folow.
And i must then somehow hide jscript panel.
Maybe Marc can help?
I have problem with adding "PLAY_COUNT" Tag.
var PLAY_COUNT = fb.TitleFormat("%PLAY_COUNT%").EvalWithMetadb(metadb);
//Play Count
if(PLAY_COUNT>=0) {
new_playcounter = Math.floor(PLAY_COUNT) + 1;
} else if(PLAY_COUNT=="?") {
new_playcounter = 1;
} else {
new_playcounter = Math.floor(p_counter) + 1;
}
Everything works fine, but if i have big number in TAG like: "965198981958199645645646456456456" , then when script adds "+1" ,then number converts to scientific "9.651989819582e+32".
How to avoid this?
I also ask you to help, you know how - I took the @text reader@, I registered the path:
$left(%path%,$strstr(%path%,\%artist%))%artist%)\Discography.txt
displays all the same FIRST text file alphabetically, Discography.txt only if it is alone in the folder
+
how to make "album art" that looked in folder Covers located at the root of the album?
del
I also ask you to help, you know how - I took the @text reader@, I registered the path:
$left(%path%,$strstr(%path%,\%artist%))%artist%)\Discography.txt
displays all the same FIRST text file alphabetically, Discography.txt only if it is alone in the folder
ctrl/rt-click for panel properties.
place your custom path\filename in "2K3.TEXT.FILENAME.TF"
not sure if I understand your 2nd question but if you want to set the location of album art:
prefs>display>album art>front cover (search patterns):
Covers\*.*
or might be
$directory_path(%path%)\Covers\*.*
place your custom path\filename in "2K3.TEXT.FILENAME.TF"
Please provide a complete code example, where to insert?
// ==PREPROCESSOR==
// @name "Text Reader"
// @author "marc2003"
// @import "%fb2k_component_path%samples\complete\js\lodash.min.js"
// @import "%fb2k_component_path%samples\complete\js\helpers.js"
// @import "%fb2k_component_path%samples\complete\js\panel.js"
// @import "%fb2k_component_path%samples\complete\js\text.js"
// ==/PREPROCESSOR==
var panel = new _.panel('Text Reader');
var text = new _.text('text_reader', LM, TM, 0, 0);
panel.item_focus_change();
function on_size() {
panel.size();
text.w = panel.w - (LM * 2);
text.h = panel.h - TM;
text.size();
}
function on_paint(gr) {
panel.paint(gr);
gr.GdiDrawText(text.header_text(), panel.fonts.title, panel.colours.highlight, LM, 0, panel.w - (LM * 2), TM, LEFT);
gr.DrawLine(text.x, text.y + 1, text.x + text.w, text.y + 1, 1, panel.colours.highlight);
text.paint(gr);
}
function on_metadb_changed() {
text.metadb_changed();
}
function on_mouse_wheel(s) {
text.wheel(s);
}
function on_mouse_move(x, y) {
text.move(x, y);
}
function on_mouse_lbtn_up(x, y) {
text.lbtn_up(x, y);
}
function on_key_down(k) {
text.key_down(k);
}
function on_mouse_rbtn_up(x, y) {
return panel.rbtn_up(x, y, text);
}
prefs>display>album art>front cover (search patterns):
Covers\*.*
or might be
$directory_path(%path%)\Covers\*.*
Where???
(https://i108.fastpic.ru/big/2018/1125/1e/97bed1343b04f09226584737505d071e.png) (https://i107.fastpic.ru/big/2018/1125/87/741aeb9bbb2b33f814d0dc52ada22887.png)
@text reader@
#1 You have a text reader js panel?
right-click on the panel. Select "Custom path..." and insert your path\filename
(https://i.imgur.com/q5G6YFH.jpg)
cover images
#2 The jspanel uses
Foobar preferences cover image location.
FBprefs > Display > Album Art > Front cover (search patterns):
(https://i.imgur.com/bQNzwTF.jpg)
I am use foo_jscript_panel by marc2k3 https://github.com/marc2k3 "Album Art" not "text reader" there is no such menu((((
there were 2 questions I confused you (covers + Discography)
added lines to settings still not visible
front.jpg
cover.jpg
%filename%.jpg
%album%.jpg
folder.jpg
folder.png
Covers\*.*
$directory_path(%path%)\Covers\*.*
I tried Album Art in a panel and it loads the artwork from the album folder, which I believe is the default location from Foobar prefs.
In preferences, try only the path you want?
Otherwise, I recommend trying a different panel : thumbs.txt
located here [foobar]\user-components\foo_jscript_panel\samples\complete\thumbs.txt
You can specify a custom path and it has other options.
I don't understand your discography question.
thumbs.txt works !!! deleted *.*
$directory_path(%path%)\Covers\ - such an option, mjm 716 Thanks!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
discography question - There are several text files in the root directory in the executor folder, one of them is diskography.txt. This music is played from subfolders, the script
$left(%path%,$strstr(%path%,\%artist%))%artist%)\Discography.txt
goes to the root but does not read the specified file and displays the first one in alphabetical order
(https://i108.fastpic.ru/big/2018/1125/83/e968f84ec13c2c79d0b340659f126b83.png) (https://i108.fastpic.ru/big/2018/1125/39/d0fe7e7828bb1c312b3943d0c0e9a939.png)
maybe this thread is useful for reversing your directory path:
https://hydrogenaud.io/index.php/topic,47627.msg423140.html#msg423140
maybe this thread is useful for reversing your directory path:
https://hydrogenaud.io/index.php/topic,47627.msg423140.html#msg423140
No, the required script rises to the folder, but does not open the specified file, but displays the first one alphabetically, in my case it is a biography
how to fix the path to the folder "Covers" if it is not in the current but one level higher?
Artist > Covers - $directory_path(%path%)\Covers\
CD1 > Artist > Covers - ???
(https://i108.fastpic.ru/big/2018/1203/2f/c34cb58ef69954eca60add9c14661e2f.png) (https://i107.fastpic.ru/big/2018/1203/69/84c4618fff605af6ce7e234fad15e969.png)
Question : I'm using JS Panel as a replacement for the standard album art component. It works well.
However, I have noticed this behaviour :
- If I double-click on a cover and the cover is an image file, the component opens the cover (so I get an enlarged version)
- If I double-click on a cover and the cover is embedded in an audio file, the component opens the audio file directory instead
Is there a way to open/enlarge the cover even if it's embedded ? Thank you.
@Mrakobes what you want was in the thread I posted for you previously.
http://www.hydrogenaudio.org/forums/index.php?s=&showtopic=43251&view=findpost&p=410071
@wcs13 any chance you give us a hint about what script you are using?
Sure. "Album Art" by marc2003.
// ==PREPROCESSOR==
// @name "Album Art"
// @author "marc2003"
// @import "%fb2k_component_path%samples\complete\js\lodash.min.js"
// @import "%fb2k_component_path%samples\complete\js\helpers.js"
// @import "%fb2k_component_path%samples\complete\js\panel.js"
// @import "%fb2k_component_path%samples\complete\js\albumart.js"
// ==/PREPROCESSOR==
var panel = new _.panel('custom_background');
var albumart = new _.albumart(0, 0, 0, 0);
panel.item_focus_change();
function on_size() {
panel.size();
albumart.w = panel.w;
albumart.h = panel.h;
}
function on_paint(gr) {
panel.paint(gr);
albumart.paint(gr);
}
function on_metadb_changed() {
albumart.metadb_changed();
}
function on_get_album_art_done(m, id, im, p) {
albumart.get_album_art_done(p);
}
function on_mouse_wheel(s) {
albumart.wheel(s);
}
function on_mouse_move(x, y) {
albumart.move(x, y);
}
function on_mouse_lbtn_dblclk(x, y) {
albumart.lbtn_dblclk(x, y);
}
function on_mouse_rbtn_up(x, y) {
return panel.rbtn_up(x, y, albumart);
}
function on_key_down(k) {
albumart.key_down(k);
}
You may want to try out the thumbs.txt sample in the same folder as album_art.txt
It has core functions of albumart but more options, incl. right-click to view image which may also work for embedded.
I don't use embedded art so can't test.
I've tried thumbs.txt. It doesn't seem to work.
It only displays the folder.jpg if it's present in the audio files directory, but it doesn't display any embedded artwork.
At least album art.txt displays the embedded artwork, even if it doesn't enlarge it.
$directory(%path%,$sub($sub($len(%path%),$len($replace(%path%,\,))),1))
@Mrakobes what you want was in the thread I posted for you previously.
http://www.hydrogenaudio.org/forums/index.php?s=&showtopic=43251&view=findpost&p=410071
@wcs13 any chance you give us a hint about what script you are using?
custom folder - $directory(%path%,$sub($sub($len(%path%),$len($replace(%path%,\,))),1))
dont work with // @name "Thumbs" (((
Hi everybody, still looking for a solution for my problem below :
Question : I'm using JS Panel as a replacement for the standard album art component [with marc2003's albumart script). It works well. However, I have noticed this behaviour :
- If I double-click on a cover and the cover is an image file, the component opens the cover (so I get an enlarged version)
- If I double-click on a cover and the cover is embedded in an audio file, the component opens the audio file directory instead
Is there a way to open/enlarge the cover even if it's embedded ? Thank you.
I think I may have found the small part of marc2003's "albumart.js" file that handles the left double-click on the album art :
this.lbtn_dblclk = function (x, y) {
if (this.trace(x, y)) {
if (panel.metadb && panel.metadb.Path == this.path) {
_.explorer(this.path);
} else if (_.isFile(this.path)) {
_.run(this.path);
}
return true;
} else {
return false;
}
}
Could somebody help me modify it, so that when we double-click it always displays the album art enlarged, whether it's external or embedded ?
Currently it only displays it enlarged if it's an external file. Otherwise it just opens a Windows explorer window to show the audio file folder.
I hope I'm clear enough. Thanks in advance !
Found a strange behaviour of Br3tts JS Smooth Browser (jssb) on marc2k3s JScript Panel (JScript Panel 2.2.0, PSS 0.3.8.3(alpha), Columns UI 1.0.0, Foobar 1.4.2):
Using the Chakra Engine, in the Album Art Grid Display Mode the Background Wallpaper Options do not work, background always black or white. All other Display Modes work well, changing to JScript Engine also solves the topic.
Cool, the JScript equivalent of coding web pages for IE6.
Found a strange behaviour of Br3tts JS Smooth Browser (jssb) on marc2k3s JScript Panel (JScript Panel 2.2.0, PSS 0.3.8.3(alpha), Columns UI 1.0.0, Foobar 1.4.2):
Using the Chakra Engine, in the Album Art Grid Display Mode the Background Wallpaper Options do not work, background always black or white. All other Display Modes work well, changing to JScript Engine also solves the topic.
Solved with marc2k3s update of the JScript Panel v2.2.0.1, see here (https://github.com/marc2k3/foo_jscript_panel/releases/tag/v2.2.0.1). Background of jssb with Chakra Engine works now as intended for all Display Modes! See as well commit here (https://github.com/marc2k3/foo_jscript_panel/commits/master).
Thanks Marc for that incredible responsiveness!
I actually moved to spider monkey panel, but this looks like a legacy from jscript panel: why are some lines in the flags document commented out? Namely line 37-39. Others are uncommented, but nevertheless followed by a "do not use" remark.
I often use those variables in my scripts and what I actually did is preprocess the flags document after uncommenting those lines. This leads me to a more general question: are we supposed to use the flags and helpers documents this way, in the preprocessor? Or is it a better practice to copy the flags and helpers we need, in our own scripts?
Will somebody explain me the meaning of the numeric arguments in the BuildMenu methods?
The JScript "Coverflow View" by Br3tt doesn't work with JScript Panel 2.2.1 anymore.
Problem is line 1535:
window.DlgCode = DLGC_WANTALLKEYS;
I tried
// window.DlgCode = DLGC_WANTALLKEYS;
but the error still remains.
marc2003I found bug!
When Foobar started a window POPs up with a message:
JScript Panel v2.2.1 (JS Smooth Playlist Manager v2018-mod by Br3tt aka Falstaff)
JavaScript execution failed:
Overflow
File: G:\Foobar2000\user-components\foo_jscript_panel\samples\js-smooth\js\jsspm.js
Line: 432, Col: 3
Then I go to the window with this script and click on the right mouse button to restart the script. Now it works1
FYI marc2003 hasn't been active on the forum since 2017.
If you have a bug report for JScript Panel, please contact marc2k3 at Github (https://github.com/marc2k3/foo_jscript_panel) and open an issue.
Hi, marc.
I am currently using SMP, and looking for a method to implement box-shadow effect like in CSS.
Is there any way to do it in albumart.js without using an external shadow image?
(I'll reply there, but maybe you should consider moving to SMP (https://hydrogenaud.io/index.php/topic,116669.0.html), which is faster and offer more possibilites.)
You need to create an image with this shadow, and then you draw the shadow image below/before the final image. Here is a function which create such image:
function createShadow(width, height, color){
var shadow = gdi.CreateImage(width, height);
var gb = shadow.GetGraphics();
gb.FillSolidRect(10, 10, width-20, height-20, color);
shadow.ReleaseGraphics(gb);
shadow = shadow.Resize(width*1/10, height*1/10,2);
shadow = shadow.Resize(width, height, 2);
return shadow;
};
And then using this function, it's quite easy:
cover_shadow = createShadow(image_width, image_height, RGB(0,0,0));
gr.DrawImage(cover_shadow, 0, 0, image_width+20, image_height+20, 0, 0, cover_shadow.Width, cover_shadow.Height);
To achieve the desired effect (shadow blur radius/position), you need to play mostly with the values in DrawImage
(I'll reply there, but maybe you should consider moving to SMP (https://hydrogenaud.io/index.php/topic,116669.0.html), which is faster and offer more possibilites.)
You need to create an image with this shadow, and then you draw the shadow image below/before the final image. Here is a function which create such image:
function createShadow(width, height, color){
var shadow = gdi.CreateImage(width, height);
var gb = shadow.GetGraphics();
gb.FillSolidRect(10, 10, width-20, height-20, color);
shadow.ReleaseGraphics(gb);
shadow = shadow.Resize(width*1/10, height*1/10,2);
shadow = shadow.Resize(width, height, 2);
return shadow;
};
And then using this function, it's quite easy:
cover_shadow = createShadow(image_width, image_height, RGB(0,0,0));
gr.DrawImage(cover_shadow, 0, 0, image_width+20, image_height+20, 0, 0, cover_shadow.Width, cover_shadow.Height);
To achieve the desired effect (shadow blur radius/position), you need to play mostly with the values in DrawImage
function createShadow(width, height, color){
let shadow = gdi.CreateImage(width, height);
let gb = shadow.GetGraphics();
gb.FillSolidRect(0, 0, width, height, color);
shadow.ReleaseGraphics(gb);
shadow = shadow.Resize(width / 128, height / 128, 2);
shadow = shadow.Resize(width, height, 2);
return shadow;
}
if (this.img) {
let cover_shadow = createShadow(this.img.Width, this.img.Height, _RGBA(0, 0, 0, 128));
_drawImage(gr, cover_shadow, this.x, this.y, this.w, this.h, this.properties.aspect.value);
_drawImage(gr, this.img, this.x + 10, this.y + 10, this.w - 20, this.h - 20, this.properties.aspect.value);
}
Thanks for the tip.
So, what the script is doing is that resize the image to a smaller size and then resize it back to original dimension so that it can be generated with blurred border? If so, what I don't get is the resized shadow image has blurred edge only on right and bottom, but no blurred effect on left and top. Is this a rendering bug from resize()?
Yes, you understood correctly. I didn't try myself your code, but i guess the issue is with the rectangle drawn inside the createShadow function. In my function, I intentionly left 10px of padding, in order to leave space for the blur effect:
gb.FillSolidRect(10, 10, width-20, height-20, color);
You removed this padding:
gb.FillSolidRect(0, 0, width, height, color);
Otherwise, you can probably use the function StackBlur instead of this resize trick which create a blur effect, look into SMP doc.
Yes, you understood correctly. I didn't try myself your code, but i guess the issue is with the rectangle drawn inside the createShadow function. In my function, I intentionly left 10px of padding, in order to leave space for the blur effect:
gb.FillSolidRect(10, 10, width-20, height-20, color);
You removed this padding:
gb.FillSolidRect(0, 0, width, height, color);
Otherwise, you can probably use the function StackBlur instead of this resize trick which create a blur effect, look into SMP doc.
I found a ref in one of Br3tt's skins https://www.deviantart.com/br3tt/art/DUiTunes-beta3-412700925
I tried different ways to achieve it in SMP, the only function missing for this is BoxBlur() which has been removed since Jscript(?).
Eventually, I am using a png shadow file instead, overall it works fine. Thanks anyway.
https://imgur.com/94NqVBy
i gave you the name of the function, StackBlur.
For example:
function createCoverShadowStack(cover_width, cover_height, color, radius){
var shadow = gdi.CreateImage(cover_width, cover_height);
var gb = shadow.GetGraphics();
var radius = Math.floor(Math.min(cover_width/2,cover_height/2,radius));
gb.FillSolidRect(radius, radius, cover_width-radius*2, cover_height-radius*2, color);
shadow.ReleaseGraphics(gb);
shadow.StackBlur(radius);
return shadow;
};
i gave you the name of the function, StackBlur.
For example:
function createCoverShadowStack(cover_width, cover_height, color, radius){
var shadow = gdi.CreateImage(cover_width, cover_height);
var gb = shadow.GetGraphics();
var radius = Math.floor(Math.min(cover_width/2,cover_height/2,radius));
gb.FillSolidRect(radius, radius, cover_width-radius*2, cover_height-radius*2, color);
shadow.ReleaseGraphics(gb);
shadow.StackBlur(radius);
return shadow;
};
Many THNAKS! It works perfectly.
(Strange that there's no activity in this thread for the last 120 days... are you all moved over to SMP? ::) )
Hi at all,
i try to calculate the days between %first_played% and today and used this code (example):
var a = fb.TitleFormat("$date(%first_played%)").Eval()
var b = new Date();
var c = new Date(a);
var d = Math.floor((b.getTime() - c.getTime()) / 86400000);
I have no idea if i use it correctly because i have no clue about this Date() stuff...
The code snippet works with Chakra engine but not with Jscript engine.
So my question is: do i use it wrong?
Or is there any other (maybe inbuilt?) method for calculate date differences?
The code snippet works with Chakra engine but not with Jscript engine.
So my question is: do i use it wrong?
Or is there any other (maybe inbuilt?) method for calculate date differences?
I wonder if Date(a) is failing in Jscript. You should be using Chakra only though. Jscript is outdated.
I don't think there are any built in date difference functions. Yours works pretty well if you just want a good number of days difference. I wanted d/m/y diffs which used normal human differences (i.e. April 5th - Feb 5th = 2 months and not 1 month 28 days), so I wrote my own:
function dateDiff(startingDate, endingDate) {
var hasStartDay = (startingDate.length > 7) ? true : false;
if (!hasStartDay) {
startingDate = startingDate + '-02'; // avoid timezone issues
}
var startDate = new Date(new Date(startingDate).toISOString().substr(0, 10));
if (!endingDate) {
endingDate = new Date().toISOString().substr(0, 10); // need date in YYYY-MM-DD format
}
var endDate = new Date(endingDate);
if (startDate > endDate) {
var swap = startDate;
startDate = endDate;
endDate = swap;
}
var startYear = startDate.getFullYear();
var february = (startYear % 4 === 0 && startYear % 100 !== 0) || startYear % 400 === 0 ? 29 : 28;
var daysInMonth = [31, february, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
var yearDiff = endDate.getFullYear() - startYear;
var monthDiff = endDate.getMonth() - startDate.getMonth();
if (monthDiff < 0) {
yearDiff--;
monthDiff += 12;
}
var dayDiff = 0;
if (hasStartDay) {
dayDiff = endDate.getDate() - startDate.getDate();
if (dayDiff < 0) {
if (monthDiff > 0) {
monthDiff--;
} else {
yearDiff--;
monthDiff = 11;
}
dayDiff += daysInMonth[startDate.getMonth()];
}
}
return (yearDiff ? yearDiff + 'y ' : '') + (monthDiff > 0 ? monthDiff + 'm ': '') + (dayDiff ? dayDiff + 'd': '');
}
It handles regular foobar dates and also dates without a day value: "2018-08". It's pretty fault tolerant.
@MordredKLB Thanks for this function, maybe its useful for me ;-)
But for now i only need the day difference for calculating and displaying "autorating" depending on the times a song has been played since "first play" and "today".
Now i've encountered another problem with the latest v2.2.2.4 (that wasn't present in the old v1.2.3 that i used before... yes, i used a quite old version... :-* )
I coded a button script that has the option to enable additional buttons.
The commands and button names can be typed in a vb InputBox.
But all the time a button is enabled or disabled the default context menu of the jscript panel pops up... and i can't find the reason...
Can somebody (with enough time) please take a look at the code, and tell me what's wrong with it?
https://pastebin.com/tGJgTvta
P.S.: Attention!
Because you don't have the images for the upper two buttons:
If you want to try this script in a config be aware of that the upper left button exits foobar2000!
The upper right one is the menu button, all other buttons are obvious.
Problem solved.
I just forgot to add "return true" after "window.Reload" to suppress the context menu :-*
And again my optional button panel...
With the linked script i can add optional buttons via context menu and ask for the command and the button name with Input boxes.
With a function (line 335 in the script) i test on first click on the new button if the given command (like: View/Playlist Manager, Playback statisctics/Rating/5 or fb.Play()) is a main menu, context menu or a JScript command and "assign" it, so there's no need to test the command every hit on the button again.
And this works good.
But how can i test (and execute) a predefined function (like getMainMenu, when i created a function getMainMenu() in the Script, like i did at line 470)?
Any ideas are welcome ;)
Optional Button Panel (https://pastebin.com/nZ3z8ApM)
Btw.: If there is someone who has a better idea or a more elegant way to test commands: i'm open for any improvements/enhancements ;)
I'm new to javascript and not entirely sure this is the right place to ask, but it seems better than the others I've found. I've got the various js smooth components loaded into spider monkey panels and love them, but the playlist doesn't seem to support drag and drop. I can drag files onto a playlist in the playlist manager, but I'd like to move them within the playlist itself. Is it a matter of marrying the code in DragnDrop.js in the samples with that in jssp.js? Has anyone done this, and are there any common pitfalls for the unwary? I've successfully made play/pause and mute buttons toggle their images, but that's about my level of sophistication.
Btw. i replaced:
eval(tmp_string);
both times with:
var tmp_func = new Function('"use strict";' + tmp_string);
tmp_func();
in the script i linked HERE (https://hydrogenaud.io/index.php/topic,110516.msg975146.html#msg975146) in the meantime.
(I'm open for any better solution).
But my question is still relevant: how can i call and execute predefined functions
with arguments (i forgot to mention it above, because without arguments my code works well) with my code?
The problem is that sometimes the functions don't have arguments so it should work in both cases.
JScript Panel v 2.2.2.
fb.GetFocusItem() does not work
For for example:
var tfo = fb.TitleFormat("%artist%");
var items = tfo.EvalWithMetadb(fb.GetFocusItem());
"JavaScript runtime error:
Type mismatch"
Read the docs. fb.GetFocusItem can return null if nothing is selected so you must always check it first...
var metadb = fb.GetFocusItem();
if (metadb) {
//do something with metadb
}
@marc2003/snotlicker: still using your latest version of Coverflow View (originally from Br3tt) version 1.5.1 as posted by Grimes here (https://hydrogenaud.io/index.php?topic=110516.msg969499#msg969499) on JScript panel 2.4.0. It works well except with rightklick - error in line 3604
Context.BuildMenu(_menu, 1, -1);
or when typing a letter to jump to the respective artists - error in line 3510
if(list.total==0 || !fb.GetFocusItem(false)) return true;
Any chance to take a look into that?
I think it would even be great if Coverflow View could be included in the SMP Script Showcases (https://theqwertiest.github.io/foo_spider_monkey_panel/docs/script_showcase/single_panel_scripts/) from TheQweriest.
@marc2003/snotlicker: still using your latest version of Coverflow View (originally from Br3tt) version 1.5.1 as posted by Grimes here (https://hydrogenaud.io/index.php?topic=110516.msg969499#msg969499) on JScript panel 2.4.0. It works well except with rightklick - error in line 3604
Context.BuildMenu(_menu, 1, -1);
or when typing a letter to jump to the respective artists - error in line 3510
if(list.total==0 || !fb.GetFocusItem(false)) return true;
Any chance to take a look into that?
I think it would even be great if Coverflow View could be included in the SMP Script Showcases (https://theqwertiest.github.io/foo_spider_monkey_panel/docs/script_showcase/single_panel_scripts/) from TheQweriest.
BuildMenu only takes two parameters now. Just do:
Context.BuildMenu(_menu, 1);
fb.GetFocusItem does not take any parameters any longer:
if(list.total==0 || !fb.GetFocusItem()) return true;
@MordredKLB: Wow, that was quick + it works!! Thanks very much!!! :)
Enclosed is the updated script.
What do you think about adding it to the SMP showcases?
That'd be a question for TheQwertiest and possibly Marc. I'm not sure if there was a reason it was excluded to begin with.
I've never had anything to do with that particular script. Obviously the first thing you need to do is make all the changes necessary for it to work in SMP. If it works in JSP v2.4.0 right now, there is absolutely no way it's going to work without some tweaks. @TheQwertiest has detailed documentation on the changes required...
https://theqwertiest.github.io/foo_spider_monkey_panel/docs/guides/jsp_to_smp_migration_guide/
Hi, this is not working:
var objShell = new ActiveXObject('Shell.Application');
objShell.NameSpace(panel.tf('$directory_path(%path%)')).ParseName(panel.tf('%filename_ext%')).ModifyDate = '2018/09/07 15:51';
both
panel.tf('$directory_path(%path%)') and
panel.tf('%filename_ext%') return a correct value for the file to be changed, but date does not get modified.
If I run the same code, replacing 'panel.tf' values, from WSH, it does work. Any clue? Thanks.
Seems to work fine for me?? Bear in mind that if you have a last modified column in your playlist, it won't update automatically since you're updating the file externally. Running this directly after may help...
fb.RunContextCommandWithMetadb("Tagging/Reload info from file(s) if changed", panel.metadb);
Seems to work fine for me??
Actually it works. The reason my code is not working is because there are three lines just before,
var handles = fb.CreateHandleList(panel.metadb);
handles.UpdateFileInfoFromJSON(JSON.stringify(obj));
_.dispose(handles);
And it takes some time to update the file, i guess asynchronously, so when my code is run the file is not available. Is there any way to make sure UpdateFileInfoFromJSON has done its job before I update file modified time?
Bear in mind that if you have a last modified column in your playlist, it won't update automatically since you're updating the file externally. Running this directly after may help...
fb.RunContextCommandWithMetadb("Tagging/Reload info from file(s) if changed", panel.metadb);
Thanks for that tip!
Yes it's async but I would expect a single track to get updated pretty much instantly?? You get a progress dialog for longer operations and the component has no way of knowing when it's complete.
Anyway, check File>Preferences>Advanced>Tagging>General>Preserve file creation/access/modification time. That probably bypasses the need to write old timestamps back??
Yes it's async but I would expect a single track to get updated pretty much instantly??
Not really, otherwise my code would have worked. I solved it with a window.setTimeout call.
Anyway, check File>Preferences>Advanced>Tagging>General>Preserve file creation/access/modification time. That probably bypasses the need to write old timestamps back??
That could help. Thanks!.
In the sample script "Thumbs", I can search with %artist% in the last fm artist database. I have a lot of classical music and I'm interested in composer pictures. The composers name is stored in my %performer% tag. How can I search in the last fm database with %performer%?
Open the configuration window and enter this as the first line of the script before
var panel...DEFAULT_ARTIST = '$meta(performer,0)';
You could use
%performer% if you were sure all tags are single value. Lookups of multi-value tags would not work well.
Thank you, it works!
Hello all, i use JS Smooth Browser to see my new album in my librairie, i would like to have the most recent at the beginning so i add this in the Panel properties "sort order album : $date(%last_modified%) | %album% | %discnumber% | %tracknumber% | %title% ".
l works fine but my newest albums are at the end of the list ...is it possible to sort the list by descending ?
i try : SORT BY DESCENDING $date(%last_modified%) but nothing changed.....
thanks for your help.
You can only use standard title formatting there, not query syntax.
Try
$sub(99999999,$replace($date(%last_modified%),-,)) | %album% | ....
;) ;) ;)
Fine, thank you !
Feature request for sample script "playback buttons": add option to center buttons in panel. Thanks.
Replace existing buttons.update function with this...
buttons.update = function () {
var x_pos = (panel.w - (bs * 4)) / 2;
this.buttons.stop = new _.button(x_pos, 0, bs, bs, {normal : 'buttons\\stop.png'}, function (x, y, mask) { fb.Stop(); }, 'Stop');
this.buttons.play = new _.button(x_pos + bs, 0, bs, bs, {normal : !fb.IsPlaying || fb.IsPaused ? 'buttons\\play.png' : 'buttons\\pause.png'}, function (x, y, mask) { fb.PlayOrPause(); }, !fb.IsPlaying || fb.IsPaused ? 'Play' : 'Pause');
this.buttons.previous = new _.button(x_pos + (bs * 2), 0, bs, bs, {normal : 'buttons\\previous.png'}, function (x, y, mask) { fb.Prev(); }, 'Previous');
this.buttons.next = new _.button(x_pos + (bs * 3), 0, bs, bs, {normal : 'buttons\\next.png'}, function (x, y, mask) { fb.Next(); }, 'Next');
}
It's nice to see some Coverflow chatter here. Does anyone know how to highlight the cover of the now playing track, only? As opposed to highlighting any cover that's been selected. Thanks!
Actually, never mind. The Coverflow is buggy and doesn't work properly with JS Smooth playlist. If you click on the Coverflow's album cover, it will not highlight on JSS unless the cover happens to be in view. In other words JSS can't scroll up and down with coverflow. JS Playlist works fine.
I'm using v1.5.2: Bug Fixes by MordredKLB
EDIT... Actually, it's JSS that's the culprit. Don't know why it started doing this. It wasn't doing this before.
Another EDIT. :) It would seem using 2.5.6 version of JSS causes it to behave this way when 2.6.1 DLL is installed. Problem solved.
The script isn't at fault - the actual component has a bug that needs fixing. I'll look at pushing out a release later on today.
LOL, I'm keeping you busy. Anyway, thanks for verifying that.
How easy/hard is it to fix a line like this (from Darkone) now that "Dispose" doesn't work anymore.
this.onMouseOut = function() {
g_tooltip.Deactivate();
g_tooltip.Dispose();
}
It should be as simple as removing the line of code that contains the .Dispose call.
However, that would imply the script is calling window.CreateTooltip more than once in a panel instance which no longer permitted. If you remove that line and still get errors, post the whole script and I'll tell you how to adjust it.
Hey, thanks again! There was a domino effect, so the next trouble line was...
g_tooltip = window.CreateTooltip();
I changed it to...
g_tooltip = window.Tooltip;
Then I got another error about mousein or something. Anyway, I deleted all these entries and surprisingly (to me) it worked:
var g_tooltip;
this.tiptext = tiptext;
this.onMouseIn = function() {
g_tooltip = window.CreateTooltip();
g_tooltip.Text = this.tiptext;
g_tooltip.Activate();
}
this.onMouseOut = function() {
g_tooltip.Deactivate();
g_tooltip.Dispose();
(Also deleted some mousein/out entries in the main script)
Well there's no such thing as window.Tooltip. It won't throw errors because window is a global object so you'll end up with an undefined variable meaning you can't do anything with it.
Removing all that code means no tooltips but obviously they're not even close to being required if the button text/icons are clear.
...
Right, so, with an interest in seeing whether I can use JS to create a custom transport button panel and maybe even tailor the speed/pitch/tempo control, I installed a fresh portable FB2K and added JScript Panel from Github. So far so good.
I then added JScript Panel to the installed components, and simply replaced the whole Default UI default panel with a JScript Panel panel. So far so good.
Then I clicked in the panel as instructed (which brought up the editor), clicked "samples", selected "Track Info +Seekbar + Buttons", and then "OK". But this is what I ended up with:

Is that right? If not, what's gone wrong? What do I do now?
^ I'm guessing last thing on the first page of the docs (https://marc2k3.github.io/jscript-panel/docs/) -
Nearly all included samples require the installation of FontAwesome which you can grab here ...
As above, you're just missing the font.
https://github.com/FortAwesome/Font-Awesome/blob/4.x/fonts/fontawesome-webfont.ttf?raw=true
When present, it should look like this...
https://marc2k3.github.io/jscript-panel/gallery/#track-info-seekbar-buttons
If you want to change the size of the buttons/text easily, you can open the editor and add this at the start of the script..
DPI = 144; //150%
If you wanted double the size, you could use 192. You can play around with the values until you find what is best for you.
Sorry, I figured buttons would be graphic elements not fonts!
Regarding JS Smooth sample, can anyone help me find where to adjust source (playlist instead of library)?
It's not easy. Lots of new code would have to written. Making it read playlist contents instead of the media library when it initialises is easy enough but you want it to respond to playlist switching, items being added/removed/reordered etc. Also, the sort order is forced in Library mode but you'd want original order preserved as a playlist. Then you have the selection logic to contend with such as making your playlist viewer jump to selection etc.
Pretty sure WilB's Library Tree for SMP does it all with zillions of options not present in Smooth Browser so you should be using that.
It's not easy. Lots of new code would have to written.
ok thanks. It was listed as a feature on Falstaff's old deviant site, but no worries.
Libary Tree bogs down on my collection, while Smooth is still pretty smooth. I'm assuming it is better JSPanel performance over SMP currently.
Yeah it did exist previously but it was quite buggy and rather than fix the bugs, I removed it. I may consider restoring it at a later date but no promises.
As for SMP vs JSP, SMP really should be faster at everything. Not sure what is going on there??
This is a query about the JS Smooth Playlist Manager sample.
Right-click offers a variety of options, but not Save. I thought I might find (and alter) the list of options in the script, but it imports a load of other stuff and has limited functionality actually within the JS Smooth Playlist Manager script.
Any pointers?
I assume you're talking about Smooth Playlist Manager and not Smooth Playlist?
In theory it would be possible to add a Save item to the menu but it would only be a shortcut to the main menu command which saves the active playlist only. It's not possible to make it respond to the mouse position and save whichever playlist you happen to be right clicking on.
I assume you're talking about Smooth Playlist Manager and not Smooth Playlist?
Yes, sorry, have edited.
In theory it would be possible to add a Save item to the menu but it would only be a shortcut to the main menu command which saves the active playlist only. It's not possible to make it respond to the mouse position and save whichever playlist you happen to be right clicking on.
Better than nothing - how do I go about that?
Right click> save as... https://gist.githubusercontent.com/marc2k3/c980fe6ac21ad6bc7f532c76724a3f42/raw/9c12c335fd53e7c848da03496cc5212a8efeba8b/jsspm.js
Save it inside your foobar2000 profile folder\user-components\foo_jscript_panel\samples\smooth and overwrite the existing file.
edit: restart fb2k if it's running while you do this.
That's great, thank you. I've just adjusted it to read "Save Active Playlist..." (as a reminder it doesn't necessarily mean the one under the mouse).
I might implement a file picker dialog in the component which would make saving the clicked on playlist possible but of course that will be on my new fangled version, not the abandoned one you're using. :P
But the specific script might be translocatable?
Nope. The script would be calling a new method built in to the component which is written in C++. While you could look at the script changes, you can't utilise methods that don't exist in your version.
@marc2k3: You helped me before with a script addition to the spectrogram seekbar sample code that would force auto-deletion of any images in its cache folder every time the script was unloaded:
function on_script_unload() {
utils.ListFiles(spectrogram_cache).toArray().forEach(function (item) {
_deleteFile(item);
});
Since changing from JScript Panel 2.88 to JScript Panel 3 version 3.03 I find that this addition no longer works. I'd be most grateful if you could post an updated version of the code addition that does the same for 3.03--thanks a million!
function on_script_unload() {
utils.ListFiles(spectrogram_cache).toArray().forEach(function (item) {
utils.RemovePath(item);
});
}
function on_script_unload() {
utils.ListFiles(spectrogram_cache).toArray().forEach(function (item) {
utils.RemovePath(item);
});
}
Works perfectly, thank you very much!
I'm using spectrogramm seekbar and I want to say that png files of spectrograms take up too much disk space. There are much more efficient codecs, namely webp, jxl, avif and heic, but at least jpg. Right now there is no choice in which format the spectrogram file will be saved, but I really want it to appear.
ffmpeg generates a png with no choice. I guess I could the read the png, save as jpg and then delete the png. I'll look in to it as an option.
During early development of JSP3, I did toy with the idea of webp encoding but it's too expensive cpu wise. All javascript is running in the main thread and you don't want it blocking.
edit: before anyone says ffmpeg is also blocking, you know it's for a reason. :P
edit2: or check the post above yours to clear the cache automatically when fb2k exits. Of course that means repeat scanning on every new session.
You're wrong, ffmpeg is able to save the spectrogram in any graphic format, just change the file extension from .png to .jpg or .jxl. Just checked, he can do it. But jpg is an old format with bad compression, jxl is much better, please use it.
If encoding seems too long for you, you can add a secondary script that would create spectrograms for each library file in the background without disturbing the user. Or, let's say the user turned on a new album, a spectrogram in png was created for its first track, when playback reaches the second track, a png spectrogram will be created for the second track, and the picture of the spectrogram of the first track in the background will be compressed into webp or jxl.
I'll stand corrected then. Not sure where I got the png idea from. Perhaps a hangover from using SoX on a previous version. I can't remember.
I'll probably use webp. jxl is too obscure and would require people going out of their way to find a WIC decoder thingy. webp is generally supported out of the box on 10/11 or google provides a download for 7/8/8.1 users.
edit: I've made the changes here: https://github.com/marc2k3/jscript-panel/commit/a01d7024dba35463676798010f69f7343f0a5d49
But jpg is an old format with bad compression, jxl is much better, please use it.
Whether JXL is "better" depends on your point of view. JPG and MP3 are de facto standards and universally supported, regardless of whether they represent the pinnacle of compression ratio vs. fidelity. JXL is obscure, and damned if I'm going to adopt it just to save a few megabytes of disk space.
Thank you for listening to my request. The default webp is of very low quality, you can visually see how bad the new spectrograms look. If you add the ffmpeg options "-lossless 1 -compression_level 6", you get a lossless webp, which is about 1.5 or 1.8 times more compression ratio than png (I personally checked it). But I still prefer jxl for its relentless and unbelievable compression ratio.
The biggest problem with jxl in jscript-panel is that foobar2000 simply doesn't render .jxl images. I changed .png to .jxl on line 233 of seekbar.js as you did in this commit, first a white rectangle is shown on the background of the empty bar for a few seconds, saying that the spectrogram is in the process of being created, and after that a solid black background. The .jxl file is in the folder, but the image doesn't appear in foobar2000.
It is very sad. However, you can store spectrograms on hdd, which is much cheaper and more reliable than ssd. It would be great to add the option "delete older than a month, two, three months", otherwise a week is somehow not enough.
But jpg is an old format with bad compression, jxl is much better, please use it.
a few megabytes of disk space.
Several megabytes for each file, about 80% of its weight, while the files themselves can be hundreds or thousands.
My component can display jxl files if I do this....
https://github.com/saschanaz/jxl-winthumb#how-to-install
Is there a better way?
Incidentally, ffmpeg seems to barf and not generate any file at all.
Everything is in this image.
https://i.imgur.com/ILhtdZv.png
edit: this is all moot, it's not like I'm changing it for this. I just wanted to show that any program with WIC support *should* work if the relevant codecs are installed.
So of course I was being an idiot trying to run that command in powerhsell without prefixing it with cmd /c. Oops.
But while the file is generated, changing the file extension is seemingly not enough...
(https://i.imgur.com/mUFrhK4.png)
But you can edit it to whatever you like (or ignore it).
And now it's working, it's noticeably slower. I guess that "superiority" comes with a price.
(https://i.imgur.com/NCv20xL.gif)
Very strange! You can see from the screenshot that Foobar2000 shows .jxl files. I have these files in the spectrogram_cache folder, but they are not shown in the player itself. I installed jxl-winthumb, in other programs, jxl pictures began to be displayed after installing it. But not in Foobar2000.
Several megabytes for each file, about 80% of its weight, while the files themselves can be hundreds or thousands.
That's your own problem! Maybe instead of
jxl is much better, please use it.
...you actually meant "please make jxl available as an option".
But not in Foobar2000.
Not sure if you're talking about this component or foobar2000 in general??
fb2k itself has only been able to display jxl (and other exotic codecs) since v2 was released nearly 2 weeks ago.
As for my component, only foo_jscript_panel3 can do it. The was released back in April I think. The original foo_jscript_panel can not.
All this comes from utilising the windows imaging component (WIC). The C++ code is entirely generic and has no idea about what codecs you have installed. While the JSP3 source code is not online, I have another component which uses WIC and you can see the code is just a few lines here...
https://github.com/marc2k3/foo_cover_resizer/blob/51776f5480ad72e6a255fa1f955a5d61bba33cc7/src/Helpers.hpp#L7L16
Thanks for letting me know about the beta! On the beta version, jxl works for me too.
Now I will look for a way to transfer my settings from the stable version to the beta. Copying the profile folder results in an error at startup.
You can use v3.0.3 of my component with fb2k v1.5/1.6.
The
album art sample can display .jxl files if you manually add .jxl under File>Preferences>Display>Album Art. Wildcards are not supported like they are for common types like jpg/png/etc
The
thumbs sample for displaying multiple images will not display jxl files by default but the script can be edited, After the second line...
var thumbs = new _thumbs();
Add
thumbs.exts.push('jxl');
I am using jscript panel version number 3.03 on foobar version 1.6.7. .jxl doesn't work in this version, but it opens in Foobar2000 beta. And only with 64-bit architecture. But the plugins I need are not available for the 64-bit architecture, they only work in the 32-bit beta version, on which jxl does not work for me. Some kind of curse.
I don't know about any miniatures or album covers.
So I didn't test and just assumed... https://github.com/saschanaz/jxl-winthumb/issues/18
Do you have any ideas how to fix this? Add 64bit plugin support to 32bit foobar.
/backs out of thread slowly....
Not just for that question but your obsession with jxl. It's getting weird now.
I am asking for the favor of a JScript Panel 3 script that would take simple "now playing" information from Foobar v2 64-bit and write it to an external text file, appending lines within the file as each song is played to a specified limit (lines or file size). The information would be the date/time played and the <artist> - <title> information from the track, from either dynamic radio station metadata or fixed files. Nothing would need to be kept in a DB, just written into the text file appending each track while Foobar is in use. Thanks for any help you can provide.
I am asking for the favor of a JScript Panel 3 script that would take simple "now playing" information from Foobar v2 64-bit and write it to an external text file, appending lines within the file as each song is played to a specified limit (lines or file size). The information would be the date/time played and the <artist> - <title> information from the track, from either dynamic radio station metadata or fixed files. Nothing would need to be kept in a DB, just written into the text file appending each track while Foobar is in use. Thanks for any help you can provide.
This will do it in the background, nothing is displayed in the panel.
Set maxfilesize to your preferred limit (the value is in bytes)
var myhistory = fb.ProfilePath + "myhistory.txt";
var maxfilesize = 5242880; //5MB in bytes
if (utils.IsFile(myhistory) == false) {
utils.WriteTextFile(myhistory, "");
}
function save_history() {
var fsize = utils.GetFileSize(myhistory);
if (fsize < maxfilesize) {
var strContents = utils.ReadTextFile(myhistory);
} else {
strContents = "";
}
var now = Math.round(new Date().getTime() / 1000);
var artist = fb.TitleFormat("%artist%").Eval();
var title = fb.TitleFormat("%title%").Eval();
var strNewContents = strContents + "\n" + "[" + utils.TimestampToDateString(now) + "] " + artist + " - " + title;
if (artist && title) {
utils.WriteTextFile(myhistory, strNewContents);
}
}
function on_playback_new_track() {
save_history();
}
function on_playback_dynamic_info_track() {
save_history();
}
@zeremy function on_playback_dynamic_info_track() {
save_history();
}
That code might log double entries depending on stream. Since fb2k v1.6.6 came out with support for album art from radio streams, I updated that callback to supply a
type argument. It has a value of 0 for metadata updates and 1 for album art updates.
https://marc2k3.github.io/jscript-panel/docs/callbacks/#on_playback_dynamic_info_tracktype
https://marc2k3.github.io/jscript-panel/docs/interfaces/IMetadbHandle/#getalbumartart_id-want_stub
To avoid duplication...
function on_playback_dynamic_info_track(type) {
if (type == 0) save_history();
}
@marc2k3 Yeah , I missed that update on the callback, should have checked your docs.
Thanks for the info.
Thanks zeremy and marc2k3 for the scripts!
From the start I used marc2k3's replacement for the dynamic info. For fixed music files all works perfect, but for stream track metadata I am seeing doubling (but single in 3 cases) and occasionally tripling of artist/titles lines, and occasionally the station names preceded by a "?" in the artist field. Sample log below. Station changes were made by double-clicking a new stream as opposed to hitting stop first. Any way to fix this?
[2022-09-27 16:28:29] ? - Decennial Gothica Radio I
[2022-09-27 16:28:29] ? - Decennial Gothica Radio I
[2022-09-27 16:28:30] Pain - Dirty Woman
[2022-09-27 16:28:36] Arcana Elysium - Cold Road
[2022-09-27 16:28:36] Arcana Elysium - Cold Road
[2022-09-27 16:28:42] Sirenia - In a maniac
[2022-09-27 16:28:42] Sirenia - In a maniac
[2022-09-27 16:29:09] ? - Pangea
[2022-09-27 16:29:09] ? - Pangea
[2022-09-27 16:29:11] To Die For - Sorrow Remains
[2022-09-27 16:29:17] Fleetwood Mac - Little Lies (Extended Remix)
[2022-09-27 16:29:18] Fleetwood Mac - Little Lies (Extended Remix)
[2022-09-27 16:29:29] Nikola Iliev - Save Me (Original Mix)
[2022-09-27 16:29:30] Nikola Iliev - Save Me (Original Mix)
[2022-09-27 16:29:30] Nikola Iliev - Save Me (Original Mix)
[2022-09-27 16:30:13] Duran Duran - The Chauffeur [qdI]
[2022-09-27 16:30:13] Duran Duran - The Chauffeur [qdI]
[2022-09-27 16:30:37] Cairo Gang - Ice Fishing
[2022-09-27 16:30:37] Cairo Gang - Ice Fishing
[2022-09-27 16:30:38] Cairo Gang - Ice Fishing
[2022-09-27 16:30:45] Lettie - Never Want To Be Alone
[2022-09-27 16:30:45] Lettie - Never Want To Be Alone
[2022-09-27 16:30:45] Lettie - Never Want To Be Alone
[2022-09-27 16:30:53] ? - Lush: Mostly female vocals with an electronic influence. [SomaFM]
[2022-09-27 16:30:53] ? - Lush: Mostly female vocals with an electronic influence. [SomaFM]
[2022-09-27 16:30:53] Schiller - Sunrise
Well the callback responsible is getting more notifications than you would expect and that can only come from the server.
This should workaround it by not logging any consecutive duplicates.
// ==PREPROCESSOR==
// @import "%fb2k_component_path%samples\js\lodash.min.js"
// ==/PREPROCESSOR==
var limit = 100;
var tfo = fb.TitleFormat("[%artist% - ]%title%");
var path = "Z:\\fb2k_log.txt";
/////////////////////////////////////////////////////////////////////////////////////////////////////////
var last = '';
function on_playback_new_track() {
log_it();
}
function on_playback_dynamic_info_track(type) {
if (type == 0) {
log_it();
}
}
function now_as_string() {
var now = Math.floor(Date.now() / 1000);
return utils.TimestampToDateString(now);
}
function log_it() {
var current = tfo.Eval();
if (current != last) {
last = current;
var text = utils.ReadUTF8(path);
var arr = _(text.trim().split("\r\n"))
.filter(function (item) { return item.length > 0; })
.takeRight(limit - 1)
.value();
arr.push(now_as_string() + " " + current);
utils.WriteTextFile(path, arr.join("\r\n"));
}
}
Thanks marc2k3 for the new script! This one works great, no doubles, just the station name on one line followed by the track played on the next. I really appreciate it. BTW, can you confirm what the "var limit" number refers to (lines or file size), and if when the limit is reached the log will "scroll delete" the oldest entry from the top of the list?
I listen to a lot of Interent radio and sometimes I hear a song I want to refer back to but forgot the track artist/title; this log feature is perfect for helping to recall it.
It's 100 lines. You can obviously change it and the first entry is discarded to make way for a new one when the limit is reached,
OK, thanks!
Hi all,
I have this abstract of a script below that executes correctly when foobar is running but if i'm closing foobar and opening it again, this code crashes at line 18 ie :
img = utils.CreateImage(window.Width, 40);
Anyone would know why ?
Thanks in advance
// ==PREPROCESSOR==
// @name "StackBlur (text)"
// @author "marc2003"
// @import "%fb2k_component_path%helpers.txt"
// ==/PREPROCESSOR==
var colour = RGB(129, 166, 192);
var img = null;
var g_font = JSON.stringify({
Name : "Segoe UI",
Size : 32,
Weight : 700,
});
create_image();
function create_image() {
img = utils.CreateImage(window.Width, 40);
var g = img.GetGraphics();
text_to_draw = "FB";
g.WriteText(text_to_draw, g_font, colour, 150, 0, 40,40, 2, 2, 1, 1);
img.ReleaseGraphics();
g=null;
}
List item 5....
https://marc2k3.github.io/jscript-panel/docs/tips/
Thanks Marc,
It's true that while i'm reading your docs extensively, this tips section, i may have read it only once !
Still, i cant make it to work.
This is what i've done and now the
img = utils.CreateImage(ww, 40);
line raises an error, which is understandable as i'm not resizing the window at startup.
// ==PREPROCESSOR==
// @name "StackBlur (text)"
// @author "marc2003"
// @import "%fb2k_component_path%helpers.txt"
// ==/PREPROCESSOR==
var colour = RGB(129, 166, 192);
var img = null;
var ww;
var g_font = JSON.stringify({
Name : "Segoe UI",
Size : 32,
Weight : 700,
});
create_image();
function create_image() {
img = utils.CreateImage(ww, 40);
var g = img.GetGraphics();
text_to_draw = "FB";
g.WriteText(text_to_draw, g_font, colour, 150, 0, 40,40, 2, 2, 1, 1);
img.ReleaseGraphics();
g=null;
}
function on_size() {
ww=window.Width;
}
on_size is always called as part of the script initialisation process but that doesn't happen until any code not inside any function has run first.
But since you want the image based on the panel width, you should call create_image() from inside on_size like this.
var img = null;
var ww = 0;
// create_image(); // remove this.
function on_size() {
ww = window.Width;
create_image();
}
function create_image() {
if (img) img.Dispose();
img = utils.CreateImage(ww, 40);
var g = img.GetGraphics();
text_to_draw = "FB";
g.WriteText(text_to_draw, g_font, colour, 150, 0, 40,40, 2, 2, 1, 1);
img.ReleaseGraphics();
g=null;
}
and this solves it perfectly !
Thanks for your continued support Marc !
Ps : If i wanted to understand the on_size behavior (the fact it runs after a code not within a function has executed), would you have any pointers ?
Only code outside any function is run when the script parser evaluates the script. You can of course have your own 10,000 line function and call that. Assuming there are no errors during that phase, nothing would ever happen without callbacks sent by the component.
So the first thing that happens is that on_size is called. This has to be faked because if you're editing the script and clicking OK/Apply in the config window, that is not a cause for the panel to be resized. And when on_size is done, on_paint comes next.
After that, it depends entirely on the callbacks you include in the script and the actions you make on the panel and fb2k events such as playback starting/stopping etc. All that is documented on the callbacks page.
https://marc2k3.github.io/jscript-panel/docs/callbacks/
I should update the entry for on_size to make it clearer what happens on startup.
alright, it's clearer. Thanks !
Hi there !
Quick question : Is it possible to retrieve the query from an AutoPlaylist ?
I need to go deeper in a given playlist, ie keep the current filter and append it with another criteria.
I didnt see any Plman functions to provide it hence i'm checking here if there is any workarounds.
Thanks
No, that isn't possible. You can edit the query for an autoplaylist by right clicking any playlist switcher/tab/etc or using plman.ShowAutoplaylistUI
https://marc2k3.github.io/jscript-panel/docs/namespaces/plman/#plmanshowautoplaylistuiplaylistindex
ah too bad, Thanks for the answer anyways !
Me again !
I'm trying to make a generic Tagging function which will have 2 parameters : the tag and the value.
unfortunately, i can't manage to set the array correctly.
following the examples from the documentation/forum, i've tried :
arr.push({
tag : value,
});
and then
var str = JSON.stringify(arr);
where as tag and value are parameters from the function (here it's "Rating" and 5).
The result is using "Tag" as a string and not a variable. (so i get an array of : {"Tag":5} instead of {"Rating":5}.
I tried different methods to fill the array (.fill) but i read that the JS engine dont allow it.
Any workarounds ?
Thanks
You have to do it like this...
var obj = {};
obj[tag] = value;
arr.push(obj);
Me again !
I'm trying to make a generic Tagging function which will have 2 parameters : the tag and the value.
unfortunately, i can't manage to set the array correctly.
following the examples from the documentation/forum, i've tried :
arr.push({
tag : value,
});
and then var str = JSON.stringify(arr);
Just for your info, note according to docs JS supports ES5 (https://marc2k3.github.io/jscript-panel/), in ES6 what you wanted to do is named computed property names:
arr.push({
[tag] : value,
});
But that doesn't work in ES5. (in any case, just putting 'tag' without brackets does nothing)
As usual, it's perfect.
Thanks Marc !
@regor : thanks for the info
Best
Since it looks like foo_plorg (aka foo_playlist_organizer) (https://hydrogenaud.io/index.php/topic,80705.0.html) will not be getting any updates, I am wondering if a similar project would be doable in the JScript Panel. Not asking anyone to make this, just curious if its aesthetic and features could be ported to the JScript Panel.
Namely:
- Support for nodes/leafs (nested folders) for playlist organization
- Drag-and-drop support for reorganizing and relocating folders and playlists
- More in attached image mock-up
(Yes, I have seen a few other JScript playlist managers but did not find their UIUX compelling)
Since it looks like foo_plorg (aka foo_playlist_organizer) (https://hydrogenaud.io/index.php/topic,80705.0.html) will not be getting any updates, I am wondering if a similar project would be doable in the JScript Panel. Not asking anyone to make this, just curious if its aesthetic and features could be ported to the JScript Panel.
Namely:
- Support for nodes/leafs (nested folders) for playlist organization
- Drag-and-drop support for reorganizing and relocating folders and playlists
- More in attached image mock-up
(Yes, I have seen a few other JScript playlist managers but did not find their UIUX compelling)
One problem with such approach, and one of the reasons I did not even consider folders as nodes on my own manager (althought it's for SMP and not JSP), is that user experience for that design/UI only works fine for a small number of playlists and users not using playlist tabs.
It becomes a nightmare to manage +100 pls. You have to rearrange playlists one by one, etc. Playlist tab panel becomes cluttered,. Also the hierarchy is plugin/script dependent. i.e. a person with foo_plorg now has to recreate the entire folder node list on another plugin. And it will be the same on the future when switching to another plugin or installation. Also playlists must be always loaded on the program, since they appear on the manager only because the playlist is loaded within foobar (*). I see that approach too limited.
It's looks cool though. And obviously is good enough for many people.
Working with playlist files, instead of playlists instances within foobar, lets you programmatically add an associated category/folder to playlists. You don't need nodes, since you can simply filter the view for a given category/folder. I have toyed myself with using nodes, but not convinced yet.
In the end, I think foobar2000 current approach to playlists is wrongly designed and would need a rework from scratch, not with plugins. With a proper manager built-in (supporting playlist files), and also not forcing users to have playlists loaded 24/7.
(*) Autoplaylists may be saved as queries. That's what marck autoplaylist manager sample file on SMP does, but then you have to either show autoplaylists or playlists. Not both without a complete redesign of what playlist manager does.
I don't want to ignore your feedback like I don't appreciate the time you took to reply, but it did not answer the primary question: is porting foo_plorg's functionality/features (that I outlined) to JScript a doable task?
- Playlists and autoplaylists organized within nodes and sub nodes
- Drag and drop functionality of all items (to re-locate the position of playlists and nodes)
I don't want to ignore your feedback like I don't appreciate the time you took to reply, but it did not answer the primary question: is porting foo_plorg's functionality/features (that I outlined) to JScript a doable task?
- Playlists and autoplaylists organized within nodes and sub nodes
- Drag and drop functionality of all items (to re-locate the position of playlists and nodes)
Obviously? XD
If it's doable in SMP, it's doable in JSP. Thought that was implied with my reply. But your primary question would be better answered asking Peter or other developers to properly implement a native manager instead of a javascript plugin.
Also not seeing anyone who would do that task but marc, which would require a great amount of work... just to patch a really big hole in Foobar (i.e. a partial solution); unless he takes the route to create a full fledged manager, which means even more work. Maybe he is in the mood XD who knows
And I don't see a point to to add manual sorting on items on my own SMP manager, nodes/subnodes could be considered. But it seems you are limited to only use JSP (?)
You are clearly making an specific request, and being realistic, since there are only 1 or 2 users who would do that in JSP or SMP, I really think time would be better spent asking peter o CUI's developer to offer a proper playlist manager. But... can be done? Yes. And sticking to a limited set of functions (UI playlists and your screenshots), it's relatively easy.
Hey Marc! I was wondering if you can tell me where the code is that is creating these underlines in JSP settings?
Thanks!
(https://u.cubeupload.com/Fizbin/JSSUnderline.png)
Doing some more digging, I wasn't aware you could add an underline to fonts by using the number 4 or 5. I thought you could only do bold or italics. So now I know. ;D
That's using ye olde gdi.Font for JScript Panel 2.x.
For anyone using JSP3, they'll need to use Underline as part of a JS object before stringifying it...
https://marc2k3.github.io/jscript-panel/docs/fonts/ (scroll to end of page)
Feature request: Please add a scrollbar to sample script Text Display (for display of longer text).
I'm far too stupid for that. :))
Hi marc2k3, is it possible to change font used for buttons (Track Info + Seekbar + Buttons.txt) to another one by not editing common.js?
Copy the the entire _button function in to your panel and modify the last line starting with this.font =...
https://github.com/marc2k3/jscript-panel/blob/aab9410dfb29785e40fc848ca41e50e9282e091b/component/samples/js/common.js#L13-L50
Copy the the entire _button function in to your panel and modify the last line starting with this.font =...
https://github.com/marc2k3/jscript-panel/blob/aab9410dfb29785e40fc848ca41e50e9282e091b/component/samples/js/common.js#L13-L50
Got it! Thanks!
Hi there,
quick question.
I'm trying to open up a pdf file which path is built from tag. One simple example is :
Y:\classical\Mozart\Piano variations, Rondos etc\485.pdf
to open it up, i'm using this script which works to open an URL :
var WshShell = new ActiveXObject('WScript.Shell');
var pdf = BuildPDF();
WshShell.Run(pdf);
but the last line of code triggers an error.
Do you know what i'm doing wrong ?
thanks
Because the path has spaces in it, you need to wrap it in double quotes like this...
WshShell.Run("\"" + pdf + "\"");
If you're using fb2k v2 with component version 3.1.0 or later, you can avoid the WshShell ActiveX object completely and use
utils.Run(pdf);
This method does not require wrapping the command in double quotes.
Perfect Marc ! Great :)
I'm using v1 for now, havent really investigated v2 yet !
Thanks
Hi there,
i'm just checking but i dont think there is a way to do it :
I'm trying to do a simple pie chart and there is no function that can draw a slice of a circle, right ?
Thanks
It's definitely not possible with the built in drawing functions. Drawing/filling a circle is enough but not sections. Using JSP 2.8.8 or Spider Monkey Panel, you could probably achieve it with the DrawPolygon/FillPolygon methods. These never made it in to JSP3 because they use old Gdiplus APIs but I use Direct2D now. I'm not sure if there is a replacement/alternative as I never did check.
As an alternative, knocking up an SVG in plain text and using utils.LoadSVG would probably work.
As an alternative, knocking up an SVG in plain text and using utils.LoadSVG would probably work.
Thanks for the answer. Would you mind pointing me into a direction that would help me to understand the above ? (got to say, didnt get the whole sentence).
Typo samples script Text Display: (context menu) Horizontal/Vertical aligment. Should be alignment.
Request samples script Text Reader: Center Custom title.
aligment
I made the same typo in my docs and noticed/fixed it some time ago but didn't think to check the samples at the same time. It will be fixed in the next release, thanks.
As for the text reader title, you can insert this directly after
var panel = new _panel();panel.draw_header = function (gr, text) {
gr.WriteText(text, this.fonts.title, this.colours.highlight, LM, 0, this.w - (LM * 2), TM, DWRITE_TEXT_ALIGNMENT_CENTER, DWRITE_PARAGRAPH_ALIGNMENT_CENTER, DWRITE_WORD_WRAPPING_NO_WRAP, DWRITE_TRIMMING_GRANULARITY_CHARACTER);
gr.DrawLine(LM, TM + 0.5, this.w - LM, TM + 0.5, 1, this.colours.highlight);
}
As an alternative, knocking up an SVG in plain text and using utils.LoadSVG would probably work.
Thanks for the answer. Would you mind pointing me into a direction that would help me to understand the above ? (got to say, didnt get the whole sentence).
The point is that SVG is a vector graphics format where the graphics are defined using descriptions of (say) a circle at coordinate something, so it should be possible to build an SVG using code, and then load the SVG to create the graphic.
ok, so i've built the SVG file (not using code yet) and here it is :
<svg height="300" width="300" viewBox = "0 0 40 40">
<circle cx="10" cy="10" r="10" fill="black" />
<circle cx="10" cy="10" r="5" stroke="red" stroke-width="10" stroke-dasharray="calc(25 * 31.42 / 100) 31.42" transform= "rotate(-90) translate (-20)" fill="transparent" />
</svg>
when i try this code on Codepen.io i have the following result :

and when i'm loading this SVG file using the recommended method :
this.img = utils.LoadSVG(svg_file);
i have this result :

if you think i'm doing something wrong please let me know, otherwise, dont bother, took me the whole evening to just do that :) writing the SVG sounds like a mountain to me :)
Seems like calc() is for CSS (cascading style sheets in browsers) so you shouldn't be using it.
I really have no idea about any of it so you really are on your own.
edit: this is the SVG library I'm using.
https://github.com/sammycage/lunasvg
You can check the features/TODO (https://github.com/sammycage/lunasvg#features) sections of the readme.
ok, so i've built the SVG file (not using code yet) and here it is :
Nice try!
Seems like calc() is for CSS (cascading style sheets in browsers) so you shouldn't be using it.
...so try this:
<svg height="300" width="300" viewBox = "0 0 40 40">
<circle cx="10" cy="10" r="10" fill="black" />
<circle cx="10" cy="10" r="5" stroke="red" stroke-width="10" stroke-dasharray="7.855 31.42" transform= "rotate(-90) translate (-20)" fill="transparent" />
</svg>
Ok, i've just done a copy/paste of the SVG without the calc and here is the result :

Not there yet but much closer ! thanks.
i'll investigate further tomorrow but yeah, instead of calculating it using SVG, i will calculate it in JS and write the result in the svg file ... i'll start tomorrow.
Thanks !
You don't need to use an SVG file. You could create a string manually...
function create_svg(args) {
var svg ='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200">\n';
//do stuff with args
svg += ...
//done
svg += '</svg>\n';
return utils.LoadSVG(svg);
}
var img = create_svg(...);
Adding the \n at the end of each line isn't necessary but it would help make it readable if you need to dump it to the console for easy reading.
oh wow that sounds much easier now :)
thanks !
ok so i've tried to generate the SVG text :
function create_svg(numbr) {
numbr[0] = 100; numbr[1] = 25; numbr[2] = 25; numbr[3] = 50;
var color = [];
var radius = 40;
var offset = 0;
var circumf = 2 * Math.PI * radius;
color[1] = "blue"; color[2] = "red"; color[3] = "yellow";
var svg ='<svg height="500" width="500" >\n';
for (var i = 1 ; i< numbr.length; i++) {
var sliceAngle = numbr[i]/numbr[0]*circumf;
svg +='<circle r="' + radius + '" cx="100" cy="100" fill="none"\n';
svg +='stroke="' + color[i] + '"\n';
svg +='stroke-width="'+radius * 2 +'"\n';
svg +='stroke-dasharray="'+ sliceAngle + ' ' + circumf + '"\n'
svg +='stroke-dashoffset="'+offset +'"/>\n'
offset-=sliceAngle;
}
svg += '</svg>\n';
return utils.LoadSVG(svg);
}
I reset the numbr array for simplicity.
Here is the result :

So it works well except the black triangles in the center, i have not idea where they are coming from
Also, the
fill="transparency"
that i was using before in the SVG is not recognized. It has to be replaced by
fill="none"
. Maybe it's the reason for the black triangles...
Thanks for the help !
I might look at switching the SVG library soon. The developer of Columns UI (musicmusic) is making a fb2k component which provides an alternative SVG rendering backend for components to use. No idea how long this will take - it looks like work only started on it yesterday.
https://github.com/reupen/svg-services/pull/1
Sounds promising !
Too bad he's not committing to Text (the other library "Sammycage" didnt either).
So it works well except the black triangles in the center, i have not idea where they are coming from
With all due respect to the writer of the SVG library, I wonder how well debugged it is!
With all due respect to the writer of the SVG library, I wonder how well debugged it is!
well, here is the final result, using my library data.
I dont see anymore these black triangles (even though i'm using the same algorithm that led to these triangles), i think there is only a slight issue to close the pie at roughly 359°.
Biggest issue however is the inability to use Text so i cannot integrate labels & percentage in the graph itself.
Impressive.
marc2k3, I'm using DrawImage (normal album art and blurred at the background) and Writetext (fb.TitleFormat("%playback_time%")) on the same panel. As I understand for the playback time to be updated every second, I should use
function on_playback_time() {window.Repaint();}
The issue I noticed is with playing 24bit/44Hz Flac files only and using Spectrum Analyzer - it somehow freezes every second, so I though it is related to that window.Repaint. When I delete lines for showing album art - there is no freeze. If I leave album art but delete function on_playback_time - no freeze but also playback time is not updating.
Function for albumart:
function update_album_art() {
if (g_img) g_img.Dispose();
g_img = null;
g_metadb = fb.IsPlaying ? fb.GetNowPlaying() : fb.GetFocusItem();
if (g_metadb) {
g_img = g_metadb.GetAlbumArt(); // omitting the type defaults to front
if (g_img) {
blur_img = g_img.Clone();
blur_img.StackBlur(radius);
}
}
window.Repaint();
}
Is there a way to do repaint for playback time only or am I getting blurred image in a wrong way?
Use window.RepaintRect with the same x,y,w,h as your WriteText.
https://marc2k3.github.io/jscript-panel/docs/namespaces/window/#windowrepaintrectx-y-w-h
If it's currently the whole panel, fix it to a smaller area just large enough for the playback time.
hey there,
I'm stuck again, and need help !
I'm trying to have a 2 states button (active/inactive) so the
var buttons = new _buttons();
buttons.update = function () {
this.buttons.stop = new _button(100, 0, 35, 35, { char : chars.stop, colour: RGB(255, 250, 250)}, null, function () { console.log("foo");}, 'foo');
this.buttons.Text = new _button(150, 0, 35, 35, { char : chars.console, colour : RGB(255, 250, 250)}, null, function () { console.log("bar"); }, 'bar');
}
in the "Track info + Seekbar + Buttons.txt" example looks perfect for that as i can play with the "char" element.
Also, i have other buttons in the panel using the "SimpleThemedButton + Tooltip" example (i do prefer the round style of the buttons.
My issue is that i dont really understand how to trigger the function
console.log("foo")
Here is the Left mouse button up function that is supposed to manage both buttons type :
function on_mouse_lbtn_up(x, y) {
g_down = false;
if (buttons.lbtn_up(x, y)) {
return;
}
if (cur_btn) {
if (cur_btn.func) cur_btn.func();
cur_btn.changeState(ButtonStates.hover);
window.Repaint();
}
}
As you can see, i didnt touch the original "SimpleThemedButton + Tooltip" function but i simply added
if (buttons.lbtn_up(x, y)) {
return;
}
to follow the example of "Track info + Seekbar + Buttons.txt"
Well, when i click on the this.buttons.stop, nothing happens.
Am i doing something wrong, is that feasible at all ?
thanks
Are you calling buttons.move(x,y) from on_mouse_move and are tooltips appearing over the buttons? Executing button clicks inside on_mouse_lbtb_up is entirely dependent on that working properly.
well i wasn't and the
if (buttons.move(x, y)) {
return;
}
in the on_mouse_move(x, y) did the trick.
re the tooltip, it appears randomly for a very short while i'll investigate tonight.
Thanks Marc !!
@etipI'm currently in the process of migrating my SVG rendering code to use musicmusic's component I mentioned earlier. It has no issues with that pie chart...
(https://i.imgur.com/pI5PVPs.png)
But it is about 2.5MB for the 64bit version which I'm testing with. I guess the 32bit version is probably a bit smaller.
sounds good, how do you measure the size ? seems high for a simple pie chart
Edit : can you use : fill="transparent" ?
Yes the fill is transparent. I used this from a earlier post of yours but where fooball had replaced the calc() code with actual values.
<svg xmlns="http://www.w3.org/2000/svg" height="300" width="300" viewBox = "0 0 40 40">
<circle cx="10" cy="10" r="10" fill="black" />
<circle cx="10" cy="10" r="5" stroke="red" stroke-width="10" stroke-dasharray="7.855 31.42" transform= "rotate(-90) translate (-20)" fill="transparent" />
</svg>
There are some changes:
1) The opening svg tag has to include this...
xmlns="http://www.w3.org/2000/svg"
2) width and height arguments are mandatory eg
var img = utils.LoadSVG(svg_text, w, h);
yep, looks much better, i think the reason why is that "Transparent" is supported which wasnt the case with previous component.
quick question the new Width and height arguments, are they the 'height="300" width="300" ' from the SVG file ?
width and height are whatever you want the returned image to be. That's the whole point of SVG, the source can be any size and you get a scaled image without quality loss.
If you loaded a tiny 16x16px png file with utils.LoadImage and then used the Resize method to make it 1024x1024, it would look terrible.
Just as a follow up, you can parse XML with ActiveXObjects like this...
var svg_file = fb.ComponentPath + 'samples\\svg\\android.svg';
var svg_text = utils.ReadUTF8(svg_file);
var xmlDoc = new ActiveXObject("Msxml2.DOMDocument.6.0");
xmlDoc.async = false;
xmlDoc.loadXML(svg_text);
if (xmlDoc.parseError.errorCode == 0) {
var svg = xmlDoc.childNodes[0];
// width / height not present in the android.svg but you could access them if you know they are with other content
console.log(svg.getAttribute("viewBox"));
}
Hi Marc,
Tested the update this morning with the new SVG library
It looks better, the pie close correctly at 360°, thanks !!
here is the result :

i will try to check if it accepts "text" but i think i read it was not using it.
This is the library I'm now using (scroll down for the readme)
https://github.com/RazrFalcon/resvg
and look here...
https://github.com/RazrFalcon/resvg#limitations
yep, thanks, i tried it, it seems the <text> tag is not recognized.
this library seems much better than the other one though.
ok so i was able to test the <text> tag and it works well ! It's much easier to manage the percentage within the SVG creation function rather than going back to the paint function.
I also tested the transform/Skew/rotate function of the <text> tag and it works well as well.
Here is my function (if anyone is interested):
function create_svg(crit) {
var color = [];
var radius = 35;
var width = window.Width / 3;
var height = window.Height;
var offset = 0;
var circumf = 2 * Math.PI * radius;
color[1] = "lime"; color[2] = "fuchsia"; color[3] = "gold";
var svg ='<svg xmlns="http://www.w3.org/2000/svg" height="' + height + '" width="' + width + '" viewBox="0 0 200 200" >\n';
for (var i = 1 ; i< crit.length; i++) { //loop to draw all the slices
var sliceAngle = crit[i]/crit[0]*circumf;
svg +='<circle r="' + radius + '" cx="100" cy="100" fill="none"\n';
svg +='stroke="' + color[i] + '"\n';
svg +='stroke-width="'+radius * 2 +'"\n';
svg +='stroke-dasharray="'+ sliceAngle + ' ' + circumf + '"\n';
svg +='stroke-dashoffset="'+offset + '"\n';
svg += 'transform="rotate(-90) translate(-200)"/>';
offset-=sliceAngle;
var perc = Math.round(crit[i]/crit[0]*100).toFixed(0) + "%"; // percentage as text of the slice
//// Below to calculate X/Y pos of the percentage in the pie //////
var cum = 0;
var sav = 0;
for (var j = 1 ; j< i+1; j++) {
cum +=crit[j];
}
sav = cum-crit[i] + (crit[i]/2);
var angle = radians(360*sav/crit[0] -90);
var xPos = 100+Math.cos(angle) * radius/2 ;
var yPos = 100+Math.sin(angle) * radius/2 ;
//// End of calculation //////////
svg +='<text x = "'+xPos+'" y = "'+yPos+'" fill="Blue" font-family="Segoe UI" font-size="13" font-weight="bold">' + perc + '</text>\n'; // put the percentage in the slice
svg+= '<text x = "'+ (43*i) +'" y = "183" fill="White" font-family="Segoe UI" font-size="13" font-weight="bold">' + perc + '</text>\n'; // put the percentage below
svg+= '<rect x = "'+ (43*i) +'" y = "185" height="7" width="22" fill="'+color[i]+'"/>\n';
}
svg += '</svg>\n';
//console.log(svg);
return utils.LoadSVG(svg);
}
function radians(degrees)
{
var pi = Math.PI;
return degrees * (pi/180);
}
function takes as a parameter an array with the number for each slice (i chose to have the first element being the total)
I tried to spot the percentages (written in blue) within the pie but it doesnt work, the x/y coordinates and not good (if anyone has knowledge there, i'd be curious to see what i did wrong).
The paint function draws each graph in a loop.
Here is the result :

For these wondering about the yellow arrow in the top left corner, it is a switch button that switches the view from graph to text as shown below :

Edit : To calculate the coordinates, i've used the following guide :
https://quantrix.com/answers/questions/question/how-to-place-labels-inside-of-a-pie-chart/
Quick question on the window.NotifyOthers(name, info) function
I have a panel that draws a simple list and i would like to choose the content of the list with another panel. So i would like to pass on an array between these 2 panels.
I cant make it happen.
So on the sending panel i have this (basic example):
function notif() {
var data = [];
for (var i = 0; i <plman.PlaylistCount ; i++) {
data.push({
value : plman.GetPlaylistName(i),
});
}
window.NotifyOthers("simple_list", data);
}
then on the other panel (called 'simple_list') i dont really know how to use the
on_notify_data(name, info) callback. i tried all sort of things with no success.
I didnt find any example of it.
Any help would be appreciated :)
thanks
Quick question on the window.NotifyOthers(name, info) function
I have a panel that draws a simple list and i would like to choose the content of the list with another panel. So i would like to pass on an array between these 2 panels.
I cant make it happen.
So on the sending panel i have this (basic example):
function notif() {
var data = [];
for (var i = 0; i <plman.PlaylistCount ; i++) {
data.push({
value : plman.GetPlaylistName(i),
});
}
window.NotifyOthers("simple_list", data);
}
then on the other panel (called 'simple_list') i dont really know how to use the
on_notify_data(name, info) callback. i tried all sort of things with no success.
I didnt find any example of it.
Any help would be appreciated :)
thanks
In script A you put the window.NotifyOthers("simple_list", data); part.
Data is the data to pass to the other panel (I think you got that right).
In Script B, you put the callback. It's a async process, so Panel B gets "notified" at some point after running window.NotifyOthers, and the arguments on the callback are the string "simple_list" and the data you sent.
function on_notify_data(name, info) {
if (name === "simple_list" && info) { // only want to react to our data on Script A, and ensure data is received
if (info.length) { //Array contains items?
// Do your thing with the data
const data = [...info]; // Make a copy, info will not be available later if used in other functions
}
}
}
Note I used some ES6 code, not sure if destructuring is available on JSP.
thank you ! it works like a charm and is incredibly easy to use !
i'm coming back on the destructuring topic. Yes, it's not available on JSP and i used the following way to handle this :
var data = [];
data = info;
Is that the best way ? i can see some unexpected behaviors and i'm not sure what i did was right.
thanks !
i'm coming back on the destructuring topic. Yes, it's not available on JSP and i used the following way to handle this :
var data = [];
data = info;
Is that the best way ? i can see some unexpected behaviors and i'm not sure what i did was right.
thanks !
Nop, because you are overwriting the [] reference with info's reference.
When you assign Arrays [] and objects {} to a variable, you are only storing the reference.
a = [3, 4];
a does not contain [3,4], but only points to that thing.
So when you do
b = a;
b[0] = 1;
In fact you have changed the original array to [1, 4]. And both a and b variables point to the same array.
In jsp you should be able to do something like
const data = JSON.parse(JSON.stringify(info));
You can also manually copy every item:
const data = info.map(function(a) {return a;}); // This works because it's an array
etc.
Even better is not passing the array at all. Just send a name only and get the other panels to update themselves.
But even that shouldn't be necessary. It's hard to see why you'd need it given the built in callbacks for any playlist manager type scripts to update themselves when playlists are renamed/added/removed in other panels.
thanks, my playlist example was just an easy example, i'll eventually send arrays of artists/composers ... with the associated # of occurences/songs.
@Regor : thanks, the var data = JSON.parse(JSON.stringify(info)); works !
Yo two questions about JS Playlist on JS Script 3.0.14 and Foobar2000 1.6.14.
1) Why playlist custom background image not work https://i.imgur.com/SxCg0DZ.png https://i.imgur.com/kVuoxl9.png (works with album and artist option, just not with default image, tried different formats for the image path and nothing).
2) How to change fonts in the playlist view (CollumsUI and DefaultUI methods listed at https://jscript-panel.github.io/gallery/jsplaylist/ not work, as in, the option to change the fonts for "JSScript" or something similar doesn't exist, and other options don't modify it)
thanks
Edit: for problem #2, I can change font and font size for JS Playlist though common list items in the ColumnsUI setting, but I can't choose different versions of a font (like black or italics).
1) currently, it only supports paths relative to the foobar2000 profile folder. The next release will be updated to support absolute paths.
2) https://hydrogenaud.io/index.php/topic,110499.msg1020722.html#msg1020722
edit: I forgot to mention the JS Playlist code only extracts the name from the font returned by window.GetFontCUI / window.GetFontDUI so other properties like italic are ignored. I'll look at adding some notes to make this clearer.
Thanks for the reply, I guess I'll learn some JS on youtube as code is black magic to me. Also the background feature still doesn't work even with images in Users\currentuser\AppData\Roaming\Foobar2000, so I'll just use the default playlist and try again when 2.0 releases a stable version an I can use the updated component.
Any image inside the profile folder should definitely work with the current version. This fb2k logo is bundled with the component and works fine...
user-components\foo_jscript_panel3\samples\images\foobar2000.png
(https://i.imgur.com/BaSy2R0.png)
Hello,
I searched this subforum since it's jscript-panel-related, but I also googled elsewhere, but I wasn't able to find a solution for the following minor inconvenience: The tooltip fontsize of jscript panel elements are pretty large in comparison to Windows' native tooltip fontsize and I'd like to reduce them to match the other fontsizes.
(https://i.imgur.com/JwMggXt.png)
better image of what I mean (can't edit original post, sorry):
(https://i.imgur.com/R3RH13j.png)
(offtopic) by the way I managed to get a button to work that changes depending on state (active,inactive,hoveronactive,hoveroninactive). Thanks to the awesome people in this forum.
You should be able to add this inside your panel(s)...
window.SetTooltipFont("Segoe UI", 12);
The default was 16, You can override with any sensible value,
Thank you. However, it spits out the following error message:
JScript Panel v2.3.6.1 (Volume by marc2003)
Laufzeitfehler in JavaScript:
Das Objekt unterstützt die Eigenschaft oder Methode "SetTooltipFont" nicht
File: <main>
Line: 9, Col: 1
Runtime error in JavaScript:
The object does not support the property or method "SetTooltipFont".
This is the code I'm using for one of my jscript panels:
// ==PREPROCESSOR==
// @name "Volume"
// @author "marc2003"
// @import "%fb2k_component_path%samples\complete\js\lodash.min.js"
// @import "%fb2k_component_path%samples\complete\js\helpers.js"
// @import "%fb2k_component_path%samples\complete\js\volume.js"
// ==/PREPROCESSOR==
window.SetTooltipFont("IBM Plex Serif", 12);
var volume = new _.volume(0, 0, 0, 0);
//volume.c1 = _.RGB(238, 238, 238);
volume.c1 = _.RGB(108, 144, 116);
volume.c2 = _.RGB(118, 158, 127);
function on_size() {
volume.w = window.Width;
volume.h = window.Height;
}
function on_paint(gr) {
gr.FillSolidRect(volume.x, volume.y, volume.w, volume.h, volume.c1);
gr.FillSolidRect(volume.x, volume.y, volume.pos(), volume.h, volume.c2);
}
function on_volume_change() {
volume.volume_change();
}
function on_mouse_wheel(s) {
volume.wheel(s);
}
function on_mouse_move(x, y) {
volume.move(x, y);
}
function on_mouse_lbtn_down(x, y) {
volume.lbtn_down(x, y);
}
function on_mouse_lbtn_up(x, y) {
volume.lbtn_up(x, y);
}
By the way this script works only in
jscript panel, not in
jscript panel 3 So maybe your solution was for
jscript panel 3?
window.SetTooltipFont does exist in JScript Panel 2.4.something. The last release was 2.8.8. Your version 2.3.6.1 is very old.
Upgrading might break something so you could just remove that code and edit samples\complete\js\helpers.js instead.
look for var tooltip = window.CreateTooltip() and replace it with var tooltip = window.CreateTooltip("Segoe UI", 12)
That worked! And I could wonder for a long time why so many scripts I tried didn't work. Because I use a very old version. Darn it! But now it works and, as some english speaking people say, "never touch a running system" and so that will have to do for now as far as customising Foobar is concerned. Thanks again!
Inside your panel, replace the on_paint function with this:
function on_paint(gr) {
gr.FillSolidRect(volume.x, volume.y, volume.w, volume.h, volume.c1);
gr.FillSolidRect(volume.x, volume.y + volume.h - volume.pos(), volume.w, volume.pos(), volume.c2);
}
Then open js_marc2003\js\volume.js and replace the this.move function with this:
this.move = function (x, y) {
this.mx = x;
this.my = y;
if (this.trace(x, y)) {
y -= this.y;
var pos = y < 0 ? 1 : y > this.h ? 0 : 1 - (y / this.h);
this.drag_vol = 50 * Math.log(0.99 * pos + 0.01) / Math.LN10;
_.tt(this.drag_vol.toFixed(2) + " dB");
if (this.drag)
fb.Volume = this.drag_vol;
this.hover = true;
return true;
} else {
if (this.hover)
_.tt("");
this.hover = false;
this.drag = false;
return false;
}
}
and replace the this.pos function with this:
this.pos = function () {
return _.ceil(this.h * (Math.pow(10, fb.Volume / 50) - 0.01) / 0.99);
}
Make sure reload the panel after editing the .js file.
It was a bit like walking in circles in a forest where every tree looks the same. Finding the right files to edit is not so easy because there are so many files with exactly the same name stored under different paths.
First I looked for the
volume.js file and went to the appdata folder of the "old" Jscript panel (no1, not no3).
So this path:
[...]AppData\Roaming\foobar2000-v2\user-components\
foo_jscript_panel\samples\jsResult: error message. :-\
Then I thought maybe it must be the new
JScript 3 panel ([...]user-components\
foo_jscript_panel3\samples\js), but a similar result again :o
JScript Panel 3.2.2 (Volume by marc2003)
Runtime error in JavaScript
The object does not support the property or method "FillSolidRect".
File: <main>
Line: 31, Col: 2
Then I looked at your forum post again and noticed that there was no
marc2003 folder in the paths, so looked further and the jscript rabbit hole lead me to towards a folder within the
spider monkey panels main folder ([…]user-components\
foo_spider_monkey_panel\samples\complete\js). I wasn't surprised and accepted my error message.
Then, out of desperation I also gave the
uie jsplitter panel a try ([…]user-components\
foo_uie_jsplitter\samples\js) …aaaand error message again. :'(
I was about to give up until I noticed that there are several
volume.js files in every single dedicated panel main folder. This time I went back to the JScript (numero uno) panel path and found the correct
volume.js in a folder called
'complete' (C:\Users\%username%\AppData\Roaming\foobar2000-v2\
foo_jscript_panel\samples\complete\js), which then worked perfectly. Phew! Stupid as a donkey but with my head through the wall it worked after all. :D
I finally have a rotated or vertical volume bar thanks to your jscript and the awesome community!
The exact paths for your particular component version/script are right there in the snippet you posted earlier...
This is the code I'm using for one of my jscript panels:
// ==PREPROCESSOR==
// @name "Volume"
// @author "marc2003"
// @import "%fb2k_component_path%samples\complete\js\lodash.min.js"
// @import "%fb2k_component_path%samples\complete\js\helpers.js"
// @import "%fb2k_component_path%samples\complete\js\volume.js"
// ==/PREPROCESSOR==
Now I feel dumb. Albeit the marc2003 folder path was wrong or is now wrong or was right in the past but not now. It was all a bit confusing.
I decided to move from ancient foo_custom to Playback Statistics however when I rate the song in the playlist the rating is being written both to the file and the DB. How can I stop modifying the files?
It's impossible to say what the problem is when you're not stating the version of fb2k, component version and script.
There were changes during early fb2k v2 betas where playback statistics were built in to fb2k and certain scripts were updated to make use of this. But since fb2k 2.0 beta 18 was released, internal playback statistics were dropped and foo_playcount is once again required. The latest component is compatible with these changes.
https://jscript-panel.github.io/gallery/jsplaylist/#clickable-ratings
https://jscript-panel.github.io/gallery/smooth-playlist/#clickable-ratings
Heya - Newb here!
i've been reading and trying a bunch of stuff from the docs.
i simply can't seem to grasp if or how it's possible to interact with a component that 1. isn't "supported" by jsp3 and 2. isn't persay open source.
namely the foo_youtube.
- if it might be possibly to get the list from a search queue as an object etc, to be able to make a customizable interface for the component.
i was able to get it to open the normal "popup search" with fb.RunMainMenuCommand("View/Youtube Source/Search on Site")
and couldn't seem to parse a "metadata" to it like metadata.RunContextCommand("Youtube Source/Search/Songs by this Artist")
don't know if i would need to craft an object looking like metadata with a title for the search string or some.
maybe i would need to decode or Reverse Engineer the foo_youtube to figure it out, but i simply don't know
maybe it's as simply as, it can't be done?
maybe it's as simply as, it can't be done?
Correct.
Hi there,
I'm trying to controle the X location of a button but i dont see any way to succeed.
What i want to achieve is to have that button 50 pixels from the right panel's limit.
The below code doenst work but i'm afraid that even if it did, the button will not set to a correct position if the window is resized.
// ==PREPROCESSOR==
// @name "Volume"
// @author "marc2003"
// @import "%fb2k_component_path%helpers.txt"
// @import "%fb2k_component_path%samples\js\lodash.min.js"
// @import "%fb2k_component_path%samples\js\common.js"
// @import "%fb2k_component_path%samples\js\volume.js"
// ==/PREPROCESSOR==
var buttons = new _buttons();
var w, h;
buttons.update = function () {
this.buttons.test = new _button(w-50 , 5 , 50, 40, { char: chars.stop , colour: RGB(255, 255, 0) }, null, function () { console.log('test'); }, 'TT test' );
}
buttons.update();
function on_paint(gr) {
console.log(w);
buttons.paint(gr);
}
function on_size() {
w = window.Width;
h = window.Height;
}
function on_mouse_lbtn_up(x, y) {
if (buttons.lbtn_up(x, y)) {
return;
}
}
function on_mouse_move(x, y) {
if (buttons.move(x, y)) {
return;
}
}
I've been trying to add a parameter to the paint function of _button within "common.js" with 0 success.
function _button(x, y, w, h, normal, hover, fn, tiptext) {
this.paint = function (gr, x_start) {
if (this.current) {
gr.WriteText(this.current.char, this.font, this.current.colour, x_start, this.y, this.w, this.h, 2, 2);
}
}
Any help is welcome !
There are buttons in my track info + seekbar + buttons sample and they always stick to the right hand side of the panel. Should be obvious really...
https://github.com/jscript-panel/component/blob/ddbb875d5fef480c134710009566eaa0fc3f2f57/samples/Track%20Info%20%2B%20Seekbar%20%2B%20Buttons.txt#L178
indeed, thanks.
I was missing the panel component !
Coming from here (https://hydrogenaud.io/index.php/topic,116669.msg1023336.html#msg1023336).
I don't mean the text alignment. I mean the font rendering. I think (as a noob) it has something to with GDI versus Directwrite, right? In my screenshot the same font wit the same size looks different and sadly really ugly in the JSP3 Text Display. :(
Well there's not a lot I can do about your personal preference. You'll just have to choose not to use it.
BTW, this is Tahoma with GDI on the left (using an old version of JScript Panel2) and DirectWrite on the right. The difference is.... meh.
(https://i.imgur.com/vmzVfPd.png)
Not even sure why you're using XP era relic like Tahoma. Segoe UI which has been the default windows font since Vista looks much better.
All good. Sorry, I don't wanted to bother you. I just asked. :) But in your screenshots it looks pretty similar indeed. Strange...
It think it's a matter of taste. I find Tahoma much more pleasent than Segoe UI as a OS font. Altough it isn't bad at all.
Anyway... thank you very much for answering and your great work here. I really appreciate it. :)
All,
Like others, i was using the playlist_organizer (aka foo_plorg) component until i switched to V2.
As i was missing it, I then tried to redevelop it using JScript Panel 3 functionalities.
I did it originally for myself and i'm far from being a professional developer and as a consequence, this is far from being optimized or well designed or coded correctly.
However it works for me and i'm using it on a daily basis.
There are been a few requests for such a replacement in the playlist_organizer thread but instead of posting there, i decided to post it here, to make sure, i have a few things right (and not all wrong).
the following document contains 3 files :
- main.js file which is the panel script
- panel_pl_organizer.js which is a replacement of the panel.js (i simply added a few things)
- pl_organizer.js which is the main code
The last 2 files should be in the "foo_jscript_panel3\samples\js" folder.
Please let me know if it's ok to spread it as a temporary replacement for the foo_plorg component or should i keep it for myself !
The last 2 files should be in the "foo_jscript_panel3\samples\js" folder.
Nobody should ever be putting their own files in the component folder. This is because they get wiped whenever you upgrade.
You really should be instructing people to extract files to a unique folder inside the user's profile and you can use %fb2k_profile_path% to locate them in the preprocessor section like this....
// ==PREPROCESSOR==
// @name "Playlist Manager"
// @author "Seb + inspiration and abstract from marc2003"
// @import "%fb2k_component_path%helpers.txt"
// @import "%fb2k_component_path%samples\js\lodash.min.js"
// @import "%fb2k_component_path%samples\js\common.js"
// @import "%fb2k_profile_path%pl_organizer\panel_pl_organizer.js"
// @import "%fb2k_profile_path%pl_organizer\pl_organizer.js"
// ==/PREPROCESSOR==
edit: you also use fb.ComponentPath as a path for writing a file as well which is bad. Replace with fb.ProfilePath.
@etip
Hi :)
https://i.imgur.com/MQT2oxt.png
1.) How to change "folder name font size" ? (add to right click)
2.) I want to display both items and size.
Thanks.
Thanks Marc for your advices ! i hope i took them into account.
@Air KEN i linked the font size menu to both playlists and folders so when you increase the size both should increase. let me know how it works for you.
So now the following zip contains 3 files :
- main.js file which is the panel script
- panel_pl_organizer.js which is a replacement of the panel.js (i simply added a few things)
- pl_organizer.js which is the main code
The last 2 files are to be copied in the fb.ProfilePath + "\pl_organizer" folder
@etip
https://i.imgur.com/eFlDloM.png
fixed.
The font size changes for both the playlist name and folder name.
Many Thanks.
@etip
additional request:
1.) Playlist multiple selection
2.) mouse action (Double click, Middle button)
3.) Context menu (Playlist view)
4.) I want to display both items and size.
Thanks.
@Airken Thanks for the feedback.
I'll think about the multiple selection but tbh, i dont really get your points 2 and 3. What would want to achieve with the double click/middle button and what would you want in the context menu ?
@etip
Thank you for your reply.
2.) mouse action (Double click, Middle button)
Send to Playlist or Play etc...
Like other Playlist Panels
3.) Context menu (Playlist view)
Playlist view context menu:
Utilities > Send to playlist... , Add to playback queue, Tagging and Prpperties etc...
3) should be built in to Smooth Playlist Manager / JSplaylist as well. I'll look at adding this.
edit: it's been done, etip can look at this if you want...
https://github.com/jscript-panel/component/commit/dc38b897badd7973d5b65313a5e0b7004aa567ac
@marc2k3 Thanks.
Smooth Playlist Manager (+ itemes > context menu)
https://i.imgur.com/1P2hXaz.png
Is it possible to add a group division function by Folder to Smooth Playlist Manager?
It is luxurious for user to be able to select "Playlist Organizer" and "Smooth Playlist Manager".
Thanks.
Someone could do it but I will not. I rarely if ever have more than 2-3 playlists on the go at once. Most of the time it's double click an album from Smooth Browser>send to playlist and play. Yes, I'm so boring that I generally listen to albums in their entirety before moving on to the next.
so i added the context menu (thanks
@marc2k3)
i also added both Size and # of files in a playlist. The switch button in the top right corner switches between the # of files to the # of files + the size (i wont be using this so i took a shortcut).
Not sure i'll do the multiple selection because it's a significant change and i just dont have the courage right now.
The following zip contains 3 files :
main.js file which is the panel script
panel_pl_organizer.js which is a replacement of the panel.js (i simply added a few things)
pl_organizer.js which is the main code
The last 2 files are to be copied in the fb.ProfilePath + "\pl_organizer" folder
Hi! I installed the JPEG XL WIC extensions and now I have thumbnails + Windows Photo Viewer support for JPEG XL, but the album art JSPanel still won't shot a cover.jpx album art. Should the detection of the WIC extension be automatic?
It should but work but there are 2 things to note:
-It only works with 64bit fb2k 2.0. AFAIK, there is no 32bit version of the JXL DLL. In addition to working with the 64bit version of this component, it should also work with default UI and Columns UI.
-The album art preferences must explicitly specify the file extension. Wildcards won't work.
It should but work but there are 2 things to note:
-It only works with 64bit fb2k 2.0 / JScript Panel3. AFAIK, there is no 32bit version of the JXL DLL.
-The album art preferences must explicitly specify the file extension. Wildcards won't work.
Well that explains it, time to transition to foobar 2.0, Thanks for the quick reply!
My original post wasn't entirely accurate making it look like JSP3 is a requirement. Default UI and 64bit Columns UI should also support it.
Hi :) etip
Playlist Organizer (Playlist Manager) (JScript Panel 3 Script) 2023-03-10
https://hydrogenaud.io/index.php/topic,110516.msg1023599.html#msg1023599
Many Thanks.
https://i.imgur.com/yhPyoxs.png
https://i.imgur.com/W4a6lCe.png
Darker colours come from using Default UI (top) as opposed to Columns UI (bottom).
(https://i.imgur.com/7SxDP5c.png)
Thanks for the reply, I was thought you were using custom build that able to change that main dark background.
---
I have another question. In regard to Track Info + Seekbar + Buttons script. I would like to add a shuffle/default toggle button that can switch between different icon and colour states.
I'm not sure how to make the toggle function work, and I'm not a programmer, so I have them on a separate button instead.
May I ask how to make it on one button toggle?
Many thanks
//default
this.buttons.regular = new _button(panel.w - LM - (bs * 4), y, bs, bs, {
char: !fb.RunMainMenuCommand('Playback/Order/Default') || fb.RunMainMenuCommand('Playback/Order/Shuffle (tracks)')
? '\uF074'
: chars.music,
colour: RGB(255, 255, 255)
}, null, function () {
if (fb.RunMainMenuCommand('Playback/Order/Shuffle (tracks)')) {
fb.RunMainMenuCommand('Playback/Order/Default');
}
}, !fb.RunMainMenuCommand('Playback/Order/Default') || fb.RunMainMenuCommand('Playback/Order/Shuffle (tracks)')
? 'Default'
: 'Shuffle');
//shuffle
this.buttons.shuffle = new _button(panel.w - LM - (bs * 5), y, bs, bs, {
char: '\uF074',
colour: fb.StopAfterCurrent
? colours.sac
: colours.test
}, null, function () {
fb.RunMainMenuCommand('Playback/Order/Shuffle (tracks)');
}, 'Shuffle');
Hi there, yet another newbie questions.
[Track Info + Seekbar + Buttons]
1. How can I use SVG on the buttons instead of char?
[JS Playlist]
2. How to make the rating color change when on hover just like the standalone rating sample script or like the default rating hover on DUI?
3. Is it possible to load characters from a different set of fonts, such as MaterialIcons fonts?
After hours upon hours, I'm satisfied enough to have this look and function properly.
Thanks for the samples, @marc2k3, even a newbie like me who is new to JavaScript learned a few things here.
(https://i.imgur.com/uYt4pUy.gif)
Your previous post where you were trying to determine the char to display after running main menu commands was too painful for me to respond to. I had to lie down and recover.
I hope you discovered plman.PlaybackOrder as a property than can be used to get and set and the on_playback_order_changed callback.
Yes, that on_playback_order_changed took me a while (days) to figure out. Eventually, I was able to get the function to work properly using setup; perhaps, this is sufficient for me.
//shuffle
this.buttons.shuffle = new _button(panel.w / 2 - 100, 12, bs, bs, {
char : (plman.PlaybackOrder == 0) ? chars.shuffle
: (plman.PlaybackOrder == 4) ? chars.shuffle
: (plman.PlaybackOrder == 5) ? chars.shuffle2
: (plman.PlaybackOrder == 6) ? chars.shuffle2
: chars.shuffle,
colour : (plman.PlaybackOrder == 0) ? colours.buttons
: (plman.PlaybackOrder == 4) ? colours.accent
: (plman.PlaybackOrder == 5) ? colours.sac
: (plman.PlaybackOrder == 6) ? colours.red
: colours.buttons,
}, null, function () {
shuffle_switch();
}, (plman.PlaybackOrder == 0) ? 'Enable Shuffle'
: (plman.PlaybackOrder == 4) ? 'Shuffle Tracks'
: (plman.PlaybackOrder == 5) ? 'Shuffle Album'
: (plman.PlaybackOrder == 6) ? 'Shuffle Folder'
: 'Shuffle');
function shuffle_switch() {
if (plman.PlaybackOrder < 6 && plman.PlaybackOrder > 3) {
plman.PlaybackOrder += 1;
}
else if (plman.PlaybackOrder === 6) {
plman.PlaybackOrder = 0;
}
else {
plman.PlaybackOrder = 4;
}
window.Repaint();
}
//finally
function on_playback_order_changed() {
buttons.update();
window.Repaint();
}
Thumbs script: Double click on a picture opens external picture viewer. I prefer to use internal foobar2000 picture viewer (see: double click on DUI Album Art Viewer). Is it possible?
Not at the moment, no.
The included
album art script already supports it. It has a customisable double click action....
(https://i.imgur.com/giNP5yc.png)
This is because it takes an album_art_data_ptr object as input so I implemented as a metadb handle method where you supply the desired album art id....
https://jscript-panel.github.io/docs/interfaces/IMetadbHandle/#showalbumartviewerart_id-want_stub
Because thumbs loads any old random image from disk, it's obviously not possible right now. I do know to how to create an album_art_data_ptr from image file paths but it would require a brand new method in the component itself. I'll think about it.
edit: the component already has an internal helper method for doing this. Embedding album art requires an album_art_data_ptr and my methods take an image file path for that.
edit2: look at all this code I had to write...
STDMETHODIMP Fb::ShowPictureViewer(BSTR path)
{
album_art_data_ptr data = AlbumArt::path_to_data(path);
if (data.is_valid())
{
fb2k::imageViewer::get()->show(core_api::get_main_window(), data);
}
return S_OK;
}
I'm super tired now. :))
Thumbs script: Want to download and display Last.fm artist pictures for classical composers. My problem: The artist field (%artist%) is for example "Englund - Klas, Tampere Philharmonic Orchestra", so it gives no result. "Einar Englund" instead gives results, but its in my %composer% tag. How do I replace %artist% with %composer% in Thumbs script? Thanks.
You've asked this before (except it was %performer%). Same technique applies now...
https://hydrogenaud.io/index.php/topic,110516.msg992040.html#msg992040
Marc,
I did implement a scrollbar to the Playlist organizer script. The scrollbar appears when i reload the script but does not when Foobar is launched.
Would you have any pointers/direction to look at ? I frankly have no idea why this can happen.
https://hydrogenaud.io/index.php/topic,123820.new.html#new
Thanks in advance
I'm not looking at the code but remember that window.Width / window.Height is always zero on fb2k startup. I guess that's your issue??
unfortunately not, i'm setting width & height during the on_size callback and the scrollbar Size is also setup during this callback :
this.size = function () {
this.panel_h = window.Height;
this.panel_w = window.Width;
this.w = window.Width - cScrollBar.width-5;
this.h = window.Height - TM;
...
p_scrollbar.setSize(this.panel_w - cScrollBar.width, this.ylist, cScrollBar.width, this.h);
p_scrollbar.setCursor(this.rows, this.items, this.offset);
}
Do you know when the on_size callback kicks when the script is launched ?
it's actually quite weird as the scrollbar loads correctly at startup but at the end of the loading (cursor goes back to normal), the scrollbar disappears. See below :
As I've made clear before, I did not write the scrollbar code but it has always worked perfectly for me with thousands of items in JS Playlist and Smooth Playlist. Only your own code can make it appear/disappear? :o
As for on_size, it's always called when a script initialises. Any code not inside a function runs first then on_size kicks in then on_paint.
After that, a script does nothing until various callbacks are triggered by fb2k core reporting changes/your mouse/keyboard etc.
ok, thanks. This order is important to me to try to understand what's going on, as you said, it's my code that has an issue (i had no doubt !)
Thanks
3.2.15 for fb2k 2.0 (Beta 18 is the enforced minimum requirement but using the final release is highly recommended)
https://jscript-panel.github.io/docs/
The most recent new button set is a nice addition.
But how can we add more fonts?
You edit your copy of the script - I thought you already did this??
Nevermind. Previously, I intended to add a few more font options, but after testing a few material icon variants, I think the segoe mdl is a good enough alternative.
(https://i.imgur.com/MqeZoC3.gif)
I'm already changing it for the next release, It's not consistent across Windows 10/11 - the console icon I chose is borked on 11.
I'll be using Segoe Fluent Icons. It's included in 11 and can be downloaded for 10.
https://learn.microsoft.com/en-us/windows/apps/design/style/segoe-fluent-icons-font
https://github.com/jscript-panel/component/commit/a8f3c198560af85a4b5619b952147507e1bc6ea8
Yeah, that fluent version looks more consistent.
Segoe Fluent Icons
(https://i.imgur.com/PLloZHa.png)
Segoe MDL2 Assets
(https://i.imgur.com/U3Vx5Vq.png)
tab stack in JSP 3 is pretty ugly .
How to replace it with button image or SVG to switch tabs ?
how to hide and show var panel = new_panel on left click mouse ?
how to change coordinate of the panel ? i know : panel.w and panel.h but the x and y position ?
all of this in jscript panel 3 . thanks
tab stack in JSP 3 is pretty ugly .
How to replace it with button image or SVG to switch tabs ?
how to hide and show var panel = new_panel on left click mouse ?
how to change coordinate of the panel ? i know : panel.w and panel.h but the x and y position ?
all of this in jscript panel 3 . thanks
I think tab stacks are unrelated to JSP 3, but rather a basic UI element from foobar or a Windows element.
Marc did mention replacing the tabs with a single panel but only for JSP panels on this post, but it was too advance for me.
If each tab contained a single JScript Panel it would be easy enough. You could replace the tabs with a single panel and add this code...
// ==PREPROCESSOR==
// @author "marc2003"
// @name "Panel Receiver"
// ==/PREPROCESSOR==
var script = window.GetProperty('2K3.SCRIPT', 'user-components-x64\\foo_jscript_panel3\\samples\\JS Playlist.txt');
var pre = '';
var text = utils.ReadUTF8(fb.ProfilePath + script);
var lines = text.split('\r\n');
if (lines[0].indexOf('// ==PREPROCESSOR==') == 0) {
for (var i = 0; i < lines.length; i++) {
if (lines[i].indexOf('// @import') == 0) {
var fq = lines[i].indexOf('"') + 1;
var lq = lines[i].lastIndexOf('"') - fq;
var file = lines[i].substr(fq, lq).replace('%fb2k_profile_path%', fb.ProfilePath).replace('%fb2k_component_path%', fb.ComponentPath);
pre += utils.ReadUTF8(file) + '\n';
} else if (lines[i].indexOf('// ==/PREPROCESSOR==') == 0) {
break;
}
}
}
eval(pre + text);
(function (global) {
var original_callback = global.on_notify_data;
global.on_notify_data = function (name, info) {
if (name == 'load_script') {
window.SetProperty('2K3.SCRIPT', info);
window.Reload();
} else if (original_callback) {
original_callback(name, info);
}
}
})(this);
Now you need a secondary panel which contains a button/menu that would send notifications to this panel whenever it was clicked. You should just need to supply the full script path something like this...
// must be relative to fb.ProfilePath - do not make it absolute
window.NotifyOthers('load_script', 'user-components-x64\\foo_jscript_panel3\\samples\\smooth browser.txt');
edit: of course any current "state" would be lost each time new content is loaded.
--------------
How to replace it with button image or SVG to switch tabs ?
I'd like to know this as well, although I'm not sure how the built-in panels would fit in.
ColumnsUI would be the only way for beginners like me, as the other option like panel splitter or jsplitter are for advance user only.
There is an open issue on ColumnsUI GitHub regarding these tab stacking to make tab appearance customisable.
https://github.com/reupen/columns_ui/issues/555
Actually, I did modify mine, but only as far as changing its tabs colour background.
(https://i.imgur.com/uxP2dtK.png)
If you are on Columns UI, why not use the Panel Stack Splitter (see here (https://wiki.hydrogenaud.io/index.php?title=Foobar2000:Components_0.9/Panel_Stack_Splitter_(foo_uie_panel_splitter))) to place your panels?
Don't get too much confused by the scripting options. To just place panels, you can use the 'Panel List' tab which is pretty much straight-forward.
thanks you very much for your help
Playback History + Now Playing 2 (foo_nowplaying2)+ Text Reader
Now Playing 2 (foo_nowplaying2)
https://hydrogenaud.io/index.php/topic,124427.0.html
https://i.imgur.com/NNUtmqr.png
Playback history is displayed in Text Reader in cooperation.
Garbled characters in Text Reader (Japanese).
foo_nowplaying2 is not garbled.
Thanks.
I would like some help with the samples jsplaylist.
I would like to set the correct aspect ratio of the image to the background of the playlist (see pictures below) and reduce the star character / rating.
I understood that the interested module is the main.js but more than having changed the font size of group 1 and 2 I was unable to do thanks
JS Playlist
(https://i.postimg.cc/yDBZCZTB/Screenshot-2023-07-25-073937.png) (https://postimg.cc/yDBZCZTB)
EL Playlist
(https://i.postimg.cc/ZC6dQcpV/Screenshot-2023-07-25-074006.png) (https://postimg.cc/ZC6dQcpV)
in playlist.js line 140 and 141 : g_font_awesome_20
you can change to g_font_awesome_12
in main.js line 1306 you have the font size . maybe you can add a line :
g_font_awesome_18 = _font("FontAwesome", 18); with the size you want and put in playlist.js :g_font_awesome_18
For the background image i don't know
Is it possible to make a text like the title song ( gr.WriteText ) to scroll from left to right in Jscript Panel 3 ?
The offset is only vertical in WriteTextLayout( ) ? I can not figure out how to do it another way ? Thanks You .
Hello,
how can I set the font and color in JScrip3/Samples:Properties. I already got the color of the heading (see Appendix).
Playback History + Now Playing 2 (foo_nowplaying2)+ Text Reader
Now Playing 2 (foo_nowplaying2)
https://hydrogenaud.io/index.php/topic,124427.0.html
https://i.imgur.com/NNUtmqr.png
Playback history is displayed in Text Reader in cooperation.
Garbled characters in Text Reader (Japanese).
foo_nowplaying2 is not garbled.
Thanks.
and
I would like a Pre-second update option in Text Reader.
I would like a Pre-second update option in Text Reader.
Related to Air KEN's requests for the Text Reader sample:
1) Offer an "auto-refresh" option for Text Reader that will auto-refresh itself each time the text file it's displaying is written to.,
2) Enable the display of Unicode UTF-8; e.g., while the text file (and window title) correctly shows "2023-07-25 17:55:59 Blacknasty - Давай Идти Никуда," it is displayed in the main Text Reader window as: (https://i.imgur.com/aSK2DVe.png)
Thanks for your consideration!
I would like a Pre-second update option in Text Reader.
Related to Air KEN's requests for the Text Reader sample:
1) Offer an "auto-refresh" option for Text Reader that will auto-refresh itself each time the text file it's displaying is written to.,
2) Enable the display of Unicode UTF-8; e.g., while the text file (and window title) correctly shows "2023-07-25 17:55:59 Blacknasty - Давай Идти Никуда," it is displayed in the main Text Reader window as: (https://i.imgur.com/aSK2DVe.png)
Thanks for your consideration!
I think it's probably because the font is different.
I want to change the font, but I can't find which script it is.
// @import "%fb2k_component_path%helpers.txt"
// @import "%fb2k_component_path%samples\js\lodash.min.js"
// @import "%fb2k_component_path%samples\js\common.js"
// @import "%fb2k_component_path%samples\js\panel.js"
// @import "%fb2k_component_path%samples\js\text.js"
Solved the garbled problem.
I found that it depends on the installed fonts.
It may be a font other than this.
MaterialIconsRound-Regular,Segoe Fluent Icons fonts
https://mega.nz/file/9S0xQaDL#VCGminQGRN28M5uDaaJgbyx8dM55VnIMyEla7Aa-F2A
for confirmation.
Text Reader right click > Configure... > Samples > Text Reader.
Text Reader right click > Fixed width font on/off repeat.
The text reader has been updated in the latest release to try and handle files with other encodings other than UTF8. If it were proper UTF8 (with or without BOM is fine), the previous versions would not have issues.
It has to be manually chosen from the right click menu and may not always work. If it does, great. If not, meh.
All the comments about refreshing and what not I'm just plain ignoring. Don't like it? Don't use it..
The text reader has been updated in the latest release to try and handle files with other encodings other than UTF8. If it were proper UTF8 (with or without BOM is fine), the previous versions would not have issues.
It has to be manually chosen from the right click menu and may not always work. If it does, great. If not, meh.
All the comments about refreshing and what not I'm just plain ignoring. Don't like it? Don't use it..
After replacing the Text Reader sample with the 3.3.2 release, the window does show correct Cyrillic from the target file with "UTF8" selected in the context menu. Thank you!
Did not mean to annoy you with the feature request for the additional refresh option.
Hello,
https://imgbox.com/QJK3K1wu
Is it possible for the graphic thumbnails to be displayed in the same order as in the image? So the front cover comes first, then the back cover and a photo of the disc. Apart from that - is it possible to change the background of the thumbnails to make it the same as the large photo? Besides, couldn't you set the photo size differently so that it fits the overall window? (I also marked it in the image). Many thanks in advance for your help!
There's no easy way to sort the files in a specfic order so you'd to bypass adding all images in folder and add them manually. If you browse the component folder\samples\js and open the file thumbs.js in a text editor, line 563 should be...
this.files = _getFiles(this.folder, this.exts);
You can replace it with something like...
this.files = [];
this.files.push(this.folder + "\\front.jpg");
this.files.push(this.folder + "\\back.jpg");
this.files.push(this.folder + "\\disc.jpg");
Note that title formatting and wildcards are not supported here - the filename/extension must match. And it doesn't matter if a given filename isn't valid for all folders - it will be ignored.
Thanks for the help!
I noticed that if there are only 2 graphics in the folder (for example, front and back covers), when I go to the second photo, it automatically changes to the first one after a second or two. When there are 3 photos (front cover, back cover, disc) this problem does not occur. One more question - if the name of the disc file is also in .png, should I enter:
this.files.push(this.folder + "\\disc.jpg;disc.png");
?
Edit:
Okay, I see that now the covers saved in the file are not displayed, only those in the folder. Can't you combine it so that the built-in ones and those in the folder are displayed? Do you have to do either way?
Hi,
I am using the panel pre-configured with the "Text Display" sample
and I have not touched anything in the JS code,
but I have tweaked some of the options from the context menu to display the custom text that I want
and to also display the album cover as the background.
But, something that I really want but can't seem to get working is just trying to add a simple blur to this album cover BG.
I have tried coding this myself and other snippets I have found from here produced JS errors.
So, it would be of great help to know how I can make it all work!
I have the latest version of both FB2K (2.0 / 32 bits) and the JScript 3.0 panel.
Thanks in advance for any help!
there is actually a simple function that does that (https://jscript-panel.github.io/docs/interfaces/IJSImage/#stackblurradius).
Take a look and let us know if you managed to make it work.
there is actually a simple function that does that (https://jscript-panel.github.io/docs/interfaces/IJSImage/#stackblurradius).
Take a look and let us know if you managed to make it work.
(https://i.postimg.cc/68jGr5xj/Immagine-2023-09-29-144148.png) (https://postimg.cc/68jGr5xj)
:))
I tried implementing in that "Stack Blur" function before,
but it doesn't seem to work out at all.
In fact, the album art object does not appear to support this method,
because all I get is a "Object doesn't support property or method 'StackBlur' " error in the console when I try to do so.
So, I am really clueless on how I can fix that issue.
Thanks.
you are probably not applying the StackBlur method to an image.
Can you show us the code ?
Thanks
On line 16 of samples\js\albumart.js is this...
this.img = img;
Simply insert this on a new line after it...
this.img.StackBlur(50); // valid values are 2-254
It worked!
I added the new line to the JS file,
but as I am using multiple JScript panels that also displays the album cover,
they're all using that same "albumart" JS script file,
so obviously, (almost) all of the album covers got blurry.
So, to fix that,
I simply duplicated the JS file with a new name ("albumart+blur.js"), added in the StackBlur to it
and in the code for my "Text Display" panel, in the Preprocessor area,
I just changed the import path for the old "albumart" to reflect the new name for the new script just like so!
// @import "%fb2k_component_path%samples\js\albumart+blur.js"
After saving the script, it only applied the blur here, which is perfectly what I wanted!
Thanks for the help!
Good to know you got it working, but if I'm not mistaken, all changes made in the JS Sample directories would be overwritten upon update.
Anyway, here's my newbie attempt at a text reader with album art blur code.
We could change the blur radius and the overlay shade here.
// ==PREPROCESSOR==
// @name "Text Display + Album Art Blur"
// @author "marc2003"
// @import "%fb2k_component_path%helpers.txt"
// @import "%fb2k_component_path%samples\js\lodash.min.js"
// @import "%fb2k_component_path%samples\js\common.js"
// @import "%fb2k_component_path%samples\js\panel.js"
// @import "%fb2k_component_path%samples\js\albumart.js"
// @import "%fb2k_component_path%samples\js\text_display.js"
// ==/PREPROCESSOR==
// https://jscript-panel.github.io/gallery/text-display/
var radius = 50;
var overlay = 180;
var g_img = null;
var g_metadb = null;
var g_info = '';
var panel = new _panel({ custom_background : true });
var albumart = new _albumart(0, 0, 0, 0);
var text = new _text_display(LM, 0, 0, 0);
var blur_img = null;
var ww = 0, wh = 0;
update_album_art();
StackBlur(radius);
panel.item_focus_change();
function update_album_art() {
if (g_img) g_img.Dispose();
g_img = null;
g_info = '';
g_metadb = fb.IsPlaying ? fb.GetNowPlaying() : fb.GetFocusItem();
if (g_metadb) {
g_img = g_metadb.GetAlbumArt(); // omitting the type defaults to front
if (g_img) {
blur_img = g_img.Clone();
blur_img.StackBlur(radius);
}
}
window.Repaint();
}
//
function StackBlur(radius) {
if (blur_img) blur_img.Dispose();
blur_img = g_img.Clone();
g_img.StackBlur(radius);
}
//
function on_colours_changed() {
panel.colours_changed();
text.refresh(true);
//
window.Repaint();
}
function on_font_changed() {
panel.font_changed();
text.refresh(true);
}
function on_item_focus_change() {
panel.item_focus_change();
//
if (!fb.IsPlaying) update_album_art();
}
function on_metadb_changed() {
albumart.metadb_changed();
text.metadb_changed();
}
function on_mouse_lbtn_dblclk() {
if (g_metadb) g_metadb.ShowAlbumArtViewer(0);
}
function on_mouse_lbtn_up(x, y) {
text.lbtn_up(x, y);
}
function on_mouse_move(x, y) {
text.move(x, y);
}
function on_mouse_rbtn_up(x, y) {
return panel.rbtn_up(x, y, text);
}
function on_mouse_wheel(s) {
text.wheel(s);
}
function on_paint(gr) {
panel.paint(gr);
var bg = window.IsDefaultUI ? window.GetColourDUI(1) : window.GetColourCUI(3);
gr.Clear(bg);
if (g_img) {
_drawImage(gr, blur_img, 0, 0, panel.w, panel.h, image.crop);
}
_drawOverlay(gr, 0, 0, panel.w, panel.h, overlay);
text.paint(gr);
}
// get notified of album art changes when listening to a supported stream
function on_playback_dynamic_info_track(type) {
if (type == 1) update_album_art();
// type 0 is metadata which we're not interested in
}
function on_playback_new_track() {
panel.item_focus_change();
//
update_album_art();
}
function on_playback_pause() {
text.refresh();
}
function on_playback_stop(reason) {
text.refresh();
//
if (reason != 2) {
update_album_art();
}
}
function on_playback_time() {
text.playback_time();
}
function on_playlist_items_added() {
panel.item_focus_change();
}
function on_playlist_items_removed() {
panel.item_focus_change();
}
function on_playlist_items_reordered() {
text.refresh();
}
function on_playlist_switch() {
panel.item_focus_change();
//
if (!fb.IsPlaying) update_album_art();
}
function on_size() {
panel.size();
text.w = panel.w - (LM * 2);
text.h = panel.h;
text.size();
ww = window.Width;
wh = window.Height;
}
Preview
(https://i.imgur.com/MpG6P0d.png)
@ eurekagliese
THX.
Already put into practice.
(https://i.postimg.cc/XZvKt341/Screenshot-2023-10-01-122841.png) (https://postimg.cc/XZvKt341)
Edit: When restarting foobar2000 it goes into error.
JScript Panel 3.3.4 (Text Display + Album Art Blur by marc2003)
JavaScript run-time error
Cannot retrieve the 'Clone' property of a null or undefined reference
File: <main>
Line: 52, Col: 2
Solved.
I accidentally added the .js file too.
All you need is the txt file, in the samples directory.
I suppose my advice about editing .js files was not good. A better alternative is to transplant the method that handles updates in to the .txt file that goes in the panel.
Inside a panel with the text display script, insert this directly after
var albumart = new _albumart(0, 0, 0, 0);albumart.metadb_changed = function () {
var img = null;
if (panel.metadb) {
img = panel.metadb.GetAlbumArt(this.properties.id.value);
}
if (this.img) this.img.Dispose();
this.img = null;
this.tooltip = this.path = '';
if (img) {
this.img = img;
this.img.StackBlur(50); // valid values are 2-254
this.tooltip = 'Original dimensions: ' + this.img.Width + 'x' + this.img.Height + 'px';
this.path = this.img.Path;
if (this.path.length) {
this.tooltip += '\nPath: ' + this.path;
}
}
window.Repaint();
}
@marc2k3
A: Line 27 this.img.StackBlur(2); // valid values are 2-254
Is there no choice but to modify A to make AlbumArt not blurry?
Eh? The original is not blurred. This edit is only for those who want blur.
I know that.
context menu > Album art background ← normal condition.
Is it possible to add a blurred state and a switching option?
I'm sorry for taking up your precious time.
I know that.
context menu > Album art background ← normal condition.
Is it possible to add a blurred state and a switching option?
I'm sorry for taking up your precious time.
The code I posted earlier actually does that.
It's blurred by default and can be switched to normal if the album art is check on in context menu.
@eurekagliese
I have already tried your script. thank you.
I thought it was great that you could easily switch between these two +1 functions with Option.
1.) Album Art normal
2.) Album Art Blur
3.) Text only
@marc2k3
Thanks.
v3.3.5
Reply #1273 https://hydrogenaud.io/index.php/topic,110499.msg1033624.html#msg1033624
Album art background
(https://foobar2000.xrea.jp/up/files/up1652.png)
Enable blur effect
(https://foobar2000.xrea.jp/up/files/up1653.png)
Is there a script like this?
If you can edit Samples Script, you can probably create it, but I don't have that knowledge.
(Track Info + Seekbar + Buttons.txt etc...)
Now Playing Info
(https://i.imgur.com/HxsvBiW.png)
Add a normal Text Display panel and make sure the album art option is turned off. Also, make sure vertical alignment is set to bottom.
Then on line 16, you should find this...
var text = new _text_display(LM, 0, 0, 0);
Insert this directly after it...
text.paint = function (gr) {
if (!this.text_layout) return;
var h = panel.h - this.text_layout.CalcTextHeight(text.w) - 50;
_drawImage(gr, albumart.img, 20, 20, panel.w, h, image.centre);
gr.WriteTextLayout(this.text_layout, this.colour_string, this.x, this.y + _scale(12), this.w, this.ha, this.offset);
this.up_btn.paint(gr, this.default_colour);
this.down_btn.paint(gr, this.default_colour);
}
With some modifications:
(https://i.postimg.cc/2bMS4jYJ/Screenshot-2023-10-03-191525.png) (https://postimg.cc/2bMS4jYJ)
:D
Add a normal Text Display panel and make sure the album art option is turned off. Also, make sure vertical alignment is set to bottom.
Then on line 16, you should find this...
var text = new _text_display(LM, 0, 0, 0);
Insert this directly after it...
text.paint = function (gr) {
if (!this.text_layout) return;
var h = panel.h - this.text_layout.CalcTextHeight(text.w) - 50;
_drawImage(gr, albumart.img, 20, 20, panel.w, h, image.centre);
gr.WriteTextLayout(this.text_layout, this.colour_string, this.x, this.y + _scale(12), this.w, this.ha, this.offset);
this.up_btn.paint(gr, this.default_colour);
this.down_btn.paint(gr, this.default_colour);
}
@marc2k3
Many Thanks.
I needed to adjust the X axis.
(https://i.imgur.com/ezV3qbY.png)
_drawImage(gr, albumart.img, 0, 20, panel.w, h, image.centre);
(https://i.imgur.com/jGpYEkI.png)
I meant to write panel.w - 40 for the width but forgot.
My settings:
lines 17-26
text.paint = function (gr) {
if (!this.text_layout) return;
var h = panel.h - this.text_layout.CalcTextHeight(text.w) -10;
_drawImage(gr, albumart.img, 0, 0, panel.w, h, image.center);
gr.WriteTextLayout(this.text_layout, this.colour_string, this.x, this.y + _scale(180), this.w, this.ha, this.offset);
this.up_btn.paint(gr, this.default_colour);
this.down_btn.paint(gr, this.default_colour);
}
lines 110-115
function on_size() {
panel.size();
text.w = panel.w - (LM * 4);
text.h = panel.h - (LM * 4);
text.size();
}
result:
(https://i.postimg.cc/bZt0dcdw/Screenshot-2023-10-04-121453.png) (https://postimg.cc/bZt0dcdw)
Oh, I see.
Thanks.
Line 21: _drawImage(gr, albumart.img, 20, 20, panel.w - 40, h, image.centre);
(https://i.imgur.com/GqdIX8F.png)
A change would need to be made for vertical alignment to work properly.
The image must translate with the text in the following way:
top image
text bottom
image center
text center
bottom image
text top.
In the end I managed to find the right settings with a static image.
Now even the vertical alignment is optimal.
// ==PREPROCESSOR==
// @name "Text Display + Album Art"
// @author "marc2003"
// @import "%fb2k_component_path%helpers.txt"
// @import "%fb2k_component_path%samples\js\lodash.min.js"
// @import "%fb2k_component_path%samples\js\common.js"
// @import "%fb2k_component_path%samples\js\panel.js"
// @import "%fb2k_component_path%samples\js\albumart.js"
// @import "%fb2k_component_path%samples\js\text_display.js"
// ==/PREPROCESSOR==
// https://jscript-panel.github.io/gallery/text-display/
var panel = new _panel({ custom_background : true });
var albumart = new _albumart(0, 0, 0, 0);
var text = new _text_display(LM, 0, 0, 0);
text.paint = function (gr) {
if (!this.text_layout) return;
var h = panel.h - this.text_layout.CalcTextHeight(text.w) +40;
_drawImage(gr, albumart.img, 0, 0, panel.w, h, image.center);
gr.WriteTextLayout(this.text_layout, this.colour_string, this.x, this.y + _scale(60), this.w, this.ha, this.offset);
this.up_btn.paint(gr, this.default_colour);
this.down_btn.paint(gr, this.default_colour);
}
panel.item_focus_change();
function on_colours_changed() {
panel.colours_changed();
text.refresh(true);
}
function on_font_changed() {
panel.font_changed();
text.refresh(true);
}
function on_item_focus_change() {
if (panel.selection.value == 0 && fb.IsPlaying) return;
panel.item_focus_change();
}
function on_metadb_changed() {
albumart.metadb_changed();
text.metadb_changed();
}
function on_mouse_lbtn_up(x, y) {
text.lbtn_up(x, y);
}
function on_mouse_move(x, y) {
text.move(x, y);
}
function on_mouse_rbtn_up(x, y) {
return panel.rbtn_up(x, y, text);
}
function on_mouse_wheel(s) {
text.wheel(s);
}
function on_paint(gr) {
panel.paint(gr);
text.paint(gr);
}
function on_playback_dynamic_info_track(type) {
if (type == 0) text.metadb_changed();
else if (type == 1 && text.properties.albumart.enabled) albumart.metadb_changed();
}
function on_playback_new_track() {
panel.item_focus_change();
}
function on_playback_pause() {
text.refresh();
}
function on_playback_stop(reason) {
if (reason != 2) {
panel.item_focus_change();
}
}
function on_playback_time() {
text.playback_time();
}
function on_playlist_items_added() {
text.refresh();
}
function on_playlist_items_removed() {
text.refresh();
}
function on_playlist_items_reordered() {
text.refresh();
}
function on_playlist_switch() {
on_item_focus_change();
}
function on_size() {
panel.size();
text.w = panel.w - (LM * 4);
text.h = panel.h - (LM * 4);
text.size();
}
@ApacheReal
We're just changing these values, right?
Can I change it from the context menu?
(https://i.imgur.com/BJsqNoq.png)
@Air KEN
You can make the changes you prefer and give ok.
If they don't work, you can always reload the sample.
If they work well for you, you can export
and overwrite the Text Display + Album Art in the samples directory.
These settings are fine with a $font(Segoe UI,15)
As mentioned above, for optimal use, the image must translate when the vertical alignment is changed
(https://i.postimg.cc/MM9KMfJw/Screenshot-2023-10-04-143251.png) (https://postimg.cc/MM9KMfJw)
(https://i.postimg.cc/0Mkyyd3Z/Screenshot-2023-10-04-143352.png) (https://postimg.cc/0Mkyyd3Z)
(https://i.postimg.cc/R3Q0mbPN/Screenshot-2023-10-04-143454.png) (https://postimg.cc/R3Q0mbPN)
For these modded text display scripts which always display album art not as the background, this function needs updating....
function on_playback_dynamic_info_track(type) {
if (type == 0) text.metadb_changed();
else if (type == 1 && text.properties.albumart.enabled) albumart.metadb_changed();
}
should now be...
function on_playback_dynamic_info_track(type) {
if (type == 0) text.metadb_changed();
else if (type == 1) albumart.metadb_changed();
}
But it only matters for online streams which supply album art. It can be ignored for local file playback.
(https://i.imgur.com/3V6PH3w.png)
Is it bothersome to blur the image as a background?
The font color also changes according to the background color.
Can also be Enable Dynamic.
(https://i.imgur.com/3V6PH3w.png)
Is it bothersome to blur the image as a background?
The font color also changes according to the background color.
That would be nice!
Here's a quick and dirty bodge job for having album art above the text and a blurred album art background.
// ==PREPROCESSOR==
// @name "Text Display"
// @author "marc2003"
// @import "%fb2k_component_path%helpers.txt"
// @import "%fb2k_component_path%samples\js\lodash.min.js"
// @import "%fb2k_component_path%samples\js\common.js"
// @import "%fb2k_component_path%samples\js\panel.js"
// @import "%fb2k_component_path%samples\js\albumart.js"
// @import "%fb2k_component_path%samples\js\text_display.js"
// ==/PREPROCESSOR==
// https://jscript-panel.github.io/gallery/text-display/
var panel = new _panel({ custom_background : true });
var albumart = new _albumart(0, 0, 0, 0);
var text = new _text_display(LM, 0, 0, 0);
albumart.blur_img = null;
albumart.metadb_changed = function () {
var img = null;
if (panel.metadb) {
img = panel.metadb.GetAlbumArt(0);
}
if (this.img) this.img.Dispose();
if (this.blur_img) this.blur_img.Dispose();
this.img = this.blur_img = null;
this.tooltip = this.path = '';
if (img) {
this.img = img;
if (text.properties.albumart_blur.enabled) {
this.blur_img = this.img.Clone();
this.blur_img.StackBlur(60);
}
this.tooltip = 'Original dimensions: ' + this.img.Width + 'x' + this.img.Height + 'px';
this.path = this.img.Path;
if (this.path.length) {
this.tooltip += '\nPath: ' + this.path;
}
}
window.Repaint();
}
text.paint = function (gr) {
if (!this.text_layout) return;
if (this.properties.albumart.enabled) {
_drawImage(gr, this.properties.albumart_blur.enabled ? albumart.blur_img : albumart.img, 0, 0, panel.w, panel.h, image.crop);
_drawOverlay(gr, 0, 0, panel.w, panel.h, 120);
}
var h = panel.h - this.text_layout.CalcTextHeight(this.w) - 50;
_drawImage(gr, albumart.img, 20, 20, panel.w - 40, h, image.centre);
gr.WriteTextLayout(this.text_layout, this.colour_string, this.x, this.y + _scale(12), this.w, this.ha, this.offset);
this.up_btn.paint(gr, this.default_colour);
this.down_btn.paint(gr, this.default_colour);
}
panel.item_focus_change();
function on_colours_changed() {
panel.colours_changed();
text.refresh(true);
}
function on_font_changed() {
panel.font_changed();
text.refresh(true);
}
function on_item_focus_change() {
if (panel.selection.value == 0 && fb.IsPlaying) return;
panel.item_focus_change();
}
function on_metadb_changed() {
albumart.metadb_changed();
text.metadb_changed();
}
function on_mouse_lbtn_up(x, y) {
text.lbtn_up(x, y);
}
function on_mouse_move(x, y) {
text.move(x, y);
}
function on_mouse_rbtn_up(x, y) {
return panel.rbtn_up(x, y, text);
}
function on_mouse_wheel(s) {
text.wheel(s);
}
function on_paint(gr) {
panel.paint(gr);
text.paint(gr);
}
function on_playback_dynamic_info_track(type) {
if (type == 0) text.metadb_changed();
else if (type == 1) albumart.metadb_changed();
}
function on_playback_new_track() {
panel.item_focus_change();
}
function on_playback_pause() {
text.refresh();
}
function on_playback_stop(reason) {
if (reason != 2) {
panel.item_focus_change();
}
}
function on_playback_time() {
text.playback_time();
}
function on_playlist_items_added() {
text.refresh();
}
function on_playlist_items_removed() {
text.refresh();
}
function on_playlist_items_reordered() {
text.refresh();
}
function on_playlist_switch() {
on_item_focus_change();
}
function on_size() {
panel.size();
text.w = panel.w - (LM * 2);
text.h = panel.h;
text.size();
}
The right click menu options for enabling/blurring the background should work as expected. And the vertical alignment must be set to bottom as per my previous mod.
Here's a quick and dirty bodge job for having album art above the text and a blurred album art background.
// ==PREPROCESSOR==
// @name "Text Display"
// @author "marc2003"
// @import "%fb2k_component_path%helpers.txt"
// @import "%fb2k_component_path%samples\js\lodash.min.js"
// @import "%fb2k_component_path%samples\js\common.js"
// @import "%fb2k_component_path%samples\js\panel.js"
// @import "%fb2k_component_path%samples\js\albumart.js"
// @import "%fb2k_component_path%samples\js\text_display.js"
// ==/PREPROCESSOR==
// https://jscript-panel.github.io/gallery/text-display/
var panel = new _panel({ custom_background : true });
var albumart = new _albumart(0, 0, 0, 0);
var text = new _text_display(LM, 0, 0, 0);
albumart.blur_img = null;
albumart.metadb_changed = function () {
var img = null;
if (panel.metadb) {
img = panel.metadb.GetAlbumArt(this.properties.id.value);
}
if (this.img) this.img.Dispose();
if (this.blur_img) this.blur_img.Dispose();
this.img = this.blur_img = null;
this.tooltip = this.path = '';
if (img) {
this.img = img;
if (panel.display_objects.length) {
if (panel.display_objects[0].properties.albumart_blur.enabled) {
this.blur_img = this.img.Clone();
this.blur_img.StackBlur(60);
}
}
this.tooltip = 'Original dimensions: ' + this.img.Width + 'x' + this.img.Height + 'px';
this.path = this.img.Path;
if (this.path.length) {
this.tooltip += '\nPath: ' + this.path;
}
}
window.Repaint();
}
text.paint = function (gr) {
if (!this.text_layout) return;
if (this.properties.albumart.enabled) {
_drawImage(gr, this.properties.albumart_blur.enabled ? albumart.blur_img : albumart.img, 0, 0, panel.w, panel.h, image.crop);
_drawOverlay(gr, 0, 0, panel.w, panel.h, 170);
}
var h = panel.h - this.text_layout.CalcTextHeight(this.w) - 50;
_drawImage(gr, albumart.img, 20, 20, panel.w - 40, h, image.centre);
gr.WriteTextLayout(this.text_layout, this.colour_string, this.x, this.y + _scale(12), this.w, this.ha, this.offset);
this.up_btn.paint(gr, this.default_colour);
this.down_btn.paint(gr, this.default_colour);
}
panel.item_focus_change();
function on_colours_changed() {
panel.colours_changed();
text.refresh(true);
}
function on_font_changed() {
panel.font_changed();
text.refresh(true);
}
function on_item_focus_change() {
if (panel.selection.value == 0 && fb.IsPlaying) return;
panel.item_focus_change();
}
function on_metadb_changed() {
albumart.metadb_changed();
text.metadb_changed();
}
function on_mouse_lbtn_up(x, y) {
text.lbtn_up(x, y);
}
function on_mouse_move(x, y) {
text.move(x, y);
}
function on_mouse_rbtn_up(x, y) {
return panel.rbtn_up(x, y, text);
}
function on_mouse_wheel(s) {
text.wheel(s);
}
function on_paint(gr) {
panel.paint(gr);
text.paint(gr);
}
function on_playback_dynamic_info_track(type) {
if (type == 0) text.metadb_changed();
else if (type == 1) albumart.metadb_changed();
}
function on_playback_new_track() {
panel.item_focus_change();
}
function on_playback_pause() {
text.refresh();
}
function on_playback_stop(reason) {
if (reason != 2) {
panel.item_focus_change();
}
}
function on_playback_time() {
text.playback_time();
}
function on_playlist_items_added() {
text.refresh();
}
function on_playlist_items_removed() {
text.refresh();
}
function on_playlist_items_reordered() {
text.refresh();
}
function on_playlist_switch() {
on_item_focus_change();
}
function on_size() {
panel.size();
text.w = panel.w - (LM * 2);
text.h = panel.h;
text.size();
}
The right click menu options for enabling/blurring the background should work as expected. And the vertical alignment must be set to bottom as per my previous mod.
Thank you, the display looks great!
All this studied with the crop image, which cuts the image and for me it is not possible, just see the difference between the left panel (crop image) and the right panel (center image):
(https://i.postimg.cc/47jPqZ3C/Screenshot-2023-10-04-185357.png) (https://postimg.cc/47jPqZ3C)
Then I don't understand the small double image and then the large one.
I can't use it.
@marc2k3
Wow, it really came out. thank you.
Use "Album art background" and "Enable blur effect" differently depending on Album Art.
It is convenient to be able to switch using the context menu.
I feel there are many possibilities.
Many Thanks.
"Enable blur effect"
(https://foobar2000.xrea.jp/up/files/up1660.png)
Album Art Move
(https://foobar2000.xrea.jp/up/files/up1663.png)
I have a mod version that I have been working on for more than 10 years and it is quite complex.
The skin uses mirrored, modular panels for the left and right and fixed panels in the center.
So I had to make changes to fit this new Text Display which I called Text Display + Album Art Picture in Picture.
Having a Text Display in which dynamic data enters when listening, changing, pausing, skipping the track as listed below:
the progress bar for local files;
the progress bar for streaming radio;
information on the last track listened to;
I had to create two different Text Display + Album Art Picture in Picture, blocking the small picture in picture image:
Text Display + Album Art Picture in Picture (left) with adapted lines (54-55):
var h = panel.h - this.text_layout.CalcTextHeight(this.w);
_drawImage(gr, albumart.img, -225, 3, panel.w - 40, panel.h - 600, image.centre);
Text Display + Album Art Picture in Picture (right) with adapted lines (54-55):
var h = panel.h - this.text_layout.CalcTextHeight(this.w);
_drawImage(gr, albumart.img, -225, 3, panel.w + 940, panel.h - 600, image.centre);
see photo:
(https://i.postimg.cc/qzHT2z32/Screenshot-2023-10-05-090023.png) (https://postimg.cc/qzHT2z32)
Numbers edited by me.
Text Display + Album Art Script (.txt)
https://foobar2000.xrea.jp/up/files/up1668.zip
Text Display + Album Art 3
checked:
Pre-second updates
Album art background
Enable blur effect
Horizontal alignment > Center
Vertical alignment > Bottom
(https://i.imgur.com/mVV8Hz9.png)
Text Display + Album Art 5
checked:
Pre-second updates
Album art background
Enable blur effect
Horizontal alignment > Center
Vertical alignment > Top
(https://i.imgur.com/pWUrqyD.png)
^Seems like a waste of time having per second updates enabled with no time display??
Any changes to tags are detected automatically as are list index changes from adding/removing/reordering playlist items.
Oops I forgot.
[Playback Time: %playback_time% / ][%length%]
I don't know if it's a problem that arose with the latest JS Scrip 3 update, but I noticed a big problem, if you keep two panels open with related samples, when skipping the track, one of the two panels, the one inactive upon selection, changes randomly.
This is a big problem for me.
I have no idea what you're on about. You'll have to be more specific.
edit: also, terms like related and inactive are nonsensical. They have no meaning in any discussion about multiple instances.
Doing some tests, the problem seems to be, when skipping the track, the switch between an active panel and an inactive panel, the latter should not change when skipping the track, but stay still.
At this point, I think that the problem is not JS Scrip Panel 3, because the problem also occurs with spider monkey panel.
The cause is to be found elsewhere, but I have no idea where.
the switch between an active panel and an inactive panel
I see you're doubling down on the gibberish. What's inactive or active in your mind has no basis in reality.
It may be nonsense, but in this video you can clearly see what I mean, talking about an active panel, of the last one selected, from a non-active panel.
With the next track I expect the panel to be inactive, it positions itself on another panel when it should be stationary.
https://www.youtube.com/watch?v=BsvvhhV0-kE
I found the cause of the problem on next (trace) command in the right panel.
This happens by pressing next, but also when automatically changing tracks in a playlist. If I am positioned at the 5th button in the right panel, the automatic change also occurs on the left panel, always at the 5th button.
You are on button 4 on the right panel and on button 2 on the left panel and you wait for the normal sequential track change of the next song, well on the right panel you remain positioned on button 4, but the left panel does not remain on button 2, but it changes automatically on button 4 etc....
"Enable blur effect"
ESL panels enable custom layouts, and you can actually merge two panels.
https://imgur.com/a/Y4vtRrA
(https://imgur.com/a/Y4vtRrA)
Is there a simple way to modify the colour of unfilled rating stars?
It would be good if that had its own colour variable.
(https://i.imgur.com/oXiMdWq.png)
to
(https://i.imgur.com/dM17fYS.png)
The rating sample code
function _rating(x, y, h, colour) {
this.paint = function (gr) {
if (panel.metadb) {
for (var i = 0; i < this.get_max(); i++) {
gr.WriteText(i + 1 > (this.hover ? this.hrating : this.rating) ? chars.rating_off : chars.rating_on, JSON.stringify({Name:'FontAwesome',Size:this.h-2}), this.colour, this.x + (i * this.h), this.y, this.h, this.h, 2, 2);
}
}
}
Don't edit the js file but put this in the main panel directly after
var rating = new _rating....rating.paint = function (gr) {
if (panel.metadb) {
var font = JSON.stringify({Name:'FontAwesome',Size:this.h-2});
for (var i = 0; i < this.get_max(); i++) {
if (i + 1 > (this.hover ? this.hrating : this.rating)) {
gr.WriteText(chars.rating_off, font, RGB(192, 192, 192), this.x + (i * this.h), this.y, this.h, this.h, 2, 2);
} else {
gr.WriteText(chars.rating_on, font, this.colour, this.x + (i * this.h), this.y, this.h, this.h, 2, 2);
}
}
}
}
Don't edit the js file but put this in the main panel directly after var rating = new _rating....
rating.paint = function (gr) {
if (panel.metadb) {
var font = JSON.stringify({Name:'FontAwesome',Size:this.h-2});
for (var i = 0; i < this.get_max(); i++) {
if (i + 1 > (this.hover ? this.hrating : this.rating)) {
gr.WriteText(chars.rating_off, font, RGB(192, 192, 192), this.x + (i * this.h), this.y, this.h, this.h, 2, 2);
} else {
gr.WriteText(chars.rating_on, font, this.colour, this.x + (i * this.h), this.y, this.h, this.h, 2, 2);
}
}
}
}
That was quick!
Thank you very much!
Preview
(https://i.imgur.com/4U8btXX.png)
I found the cause of the problem on next (trace) command in the right panel.
This happens by pressing next, but also when automatically changing tracks in a playlist. If I am positioned at the 5th button in the right panel, the automatic change also occurs on the left panel, always at the 5th button.
You are on button 4 on the right panel and on button 2 on the left panel and you wait for the normal sequential track change of the next song, well on the right panel you remain positioned on button 4, but the left panel does not remain on button 2, but it changes automatically on button 4 etc....
Problem solved
I modified the scripts that implement the switch.
For the three Multi Panels on the right I used do.vispanel.switch
For the three Multi Panels on the left I used do.megavis.switch
"Enable blur effect"
ESL panels enable custom layouts, and you can actually merge two panels.
https://imgur.com/a/Y4vtRrA
(https://imgur.com/a/Y4vtRrA)
@always.beta
Thanks.
I'll give it a try.
ーーーーーーーーー
Is there a demand for horizontal orientation?
(https://i.imgur.com/fzetPIi.png)
--------------
imaginary image (Front/Back Cover)
(https://i.imgur.com/rqUHOhq.png)
Great thanks. :))
(https://i.postimg.cc/K3fTbxfq/Screenshot-2023-10-06-170344.png) (https://postimg.cc/K3fTbxfq)
How do I change the volume step when using the mouse wheel to normal?
The volume wheel step is good from 0 to -10db, but when dropped from -10db to -100db, it seems "unnatural". Is there an easy method to increase the wheel step only when it falls below -10db?
I tried this code, however it produces an overflow error after certain values, and the transition from 0 to -10 is not as smooth as it should be.
function on_mouse_wheel(s) {
var vl = vol2pos(fb.Volume);
vl += s / 20;
fb.Volume = pos2vol(vl);
vol2pos and pos2vol are for volume sliders ensuring they behave the same the built in DUI toolbar volume control with regards to dragging / rendering.
It's nonsensical to try and use them inside on_mouse_wheel. The most sensible way thing to do is to use fb.VolumeUp and fb.VolumeDown because these respect the step settings from the advanced preferences (File>Preferences>Advanced>Playback>Volume step (db) ). If you really must bypass this, simply fb.Volume += whatever.
vol2pos and pos2vol are for volume sliders ensuring they behave the same the built in DUI toolbar volume control with regards to dragging / rendering.
It's nonsensical to try and use them inside on_mouse_wheel. The most sensible way thing to do is to use fb.VolumeUp and fb.VolumeDown because these respect the step settings from the advanced preferences (File>Preferences>Advanced>Playback>Volume step (db) ). If you really must bypass this, simply fb.Volume += whatever.
Thanks, I think I got it by using switch case on certain value, albeit it may need some adjustment.
Hi there again, I'm trying to get an accent colour from GetNowPlayingColours array.
I tried using the Luminance to select the colour, but I don't know how to retrieve it and stop at the correct colour.
For example, in this album art, colours 0 and 1 do not match; so, skip to the next phase, where colour 2 will be used as the colour accent.
(https://i.imgur.com/EbSVN6T.png)
function checkColour() {
var g_accent_arr = GetNowPlayingColours();
g_accent = g_accent_arr[(accent_index) + 4]
var i = accent_index
if (Luminance(g_accent) > 0.6) {
console.log("OK")
}
else {
i++
}
}
You're mixing things up really. The screenshot you posted is from the basic GetColourScheme sample which doesn't do anything except display the colours in order from most dominant to least.
The GetNowPlayingColours() from helpers.txt is something else entirely and it's what I used for dynamic colours in JSPlaylist and the Smooth samples. The calulations are done for you.
If not playing or there is no art, it returns an empty array so always check for that. If a valid image is found then array length is always 4. Colours are returned in this order....
https://github.com/jscript-panel/component/blob/3547fd4dcdcae0a8e893ae26e083d7a40edccc60/helpers.txt#L283
The background_colour is always the most dominant and the selected_background_colour is calculated to have a luminace value with the biggest distance away from the background_colour. That should be your accent. The text colours are always black or white calculated with DetermineTextColour - this ensures it's always readble.
Thank you for responding and explaining. I've been using selected_background_colour as g_color_selection for a while now.
Actually, I was trying to always find the light accent, as I'm trying to match it with the dark blur background for the tracks. So the question would be how to always calculate Luminance from dark background or RGB(0,0,0). I tried to emulate using the calculation from the GetNowPlayingColours diff, but had no luck and since this just a minor issue, I might try it again later.
Anyway, I have another question that has been bugging me for a while.
When I set the g_colour_text from GetNowPlayingColours as the button colour, it took about 4 seconds for the button to update the colour when I selected and started a new track.
I have already added the buttons.update() to some function, but several functions, such as on_playback_new_track, on_item_focus_change, and on_colors_changed, returned an error.
Object doesn't support property or method 'update'
The metadb are set to fb.GetNowPlaying. When set to fb.GetFocusItem, it does change on the fly when selecting a new track but as expected it doesn't get the colour for next track, although it can be passed by activating the cursor follow playback.
(https://i.imgur.com/tYovEiH.gif)
I'm asking for help.
I display my covers in JScript Panel3 / Album Art.
When I place the cursor over the displayed cover, a pop-up window always appears with information about the cover (see appendix).
How can I turn off this pop-up window?
Sorry for my english. It's google translate.
Clicking the panel immediately dismisses it but if you really want to prevent it completely... right click the panel > Configure. Add this code...
function _tt() {}
Excellent. Thanks for the quick help.
I have been using the DarkOne4Mod on foobar for a long time since I've been on Windows. I was on the initial version of the theme all the way to the current version and it uses the JScript component to load most of the panels in the layout.
I have now moved to Linux (ZorinOS) and I'm having trouble getting one particular panel to show up.
I attached a photo to show exactly what I mean.
I think I'm encountering the error/crash due to some font differences between Linux and Windows.
Can someone help me out as to what to edit in the Panel settings to get this to work please?
Console:
Error: JScript Panel (DarkOne4Mod - Display Panel v1.0 build20160929 by super-gau and tedGo, includes partial codes by fbuser, Br3tt and T.P Wang): Invalid parameter. File: <main>
Line: 184, Col: 3
<source text only available at compile time>
I thought one of those variables was not initialized but my trying to solve it myself didn't work so far.
JScript panel version: 1.1.6
Foobar version: 2.0 (x86) running via PlayOnLinux
Console:
Error: JScript Panel (DarkOne4Mod - Display Panel v1.0 build20160929 by super-gau and tedGo, includes partial codes by fbuser, Br3tt and T.P Wang): Invalid parameter. File: <main>
Line: 184, Col: 3
<source text only available at compile time>
I thought one of those variables was not initialized but my trying to solve it myself didn't work so far.
JScript panel version: 1.1.6
Foobar version: 2.0 (x86) running via PlayOnLinux
Does Linux have Microsoft Sans Serif font? If not, type in one you do have. (Try Arial Black) It still shouldn't crash, however. At least it wouldn't in Windows.
Or delete the line or put a // in front of it and see what happens.
I suggest downloading the latest non modded Darkone here...
https://foobar-users.de/index.php?topic=4851.0
Thank you for responding and explaining. I've been using selected_background_colour as g_color_selection for a while now.
Actually, I was trying to always find the light accent, as I'm trying to match it with the dark blur background for the tracks. So the question would be how to always calculate Luminance from dark background or RGB(0,0,0). I tried to emulate using the calculation from the GetNowPlayingColours diff, but had no luck and since this just a minor issue, I might try it again later.
Anyway, I have another question that has been bugging me for a while.
When I set the g_colour_text from GetNowPlayingColours as the button colour, it took about 4 seconds for the button to update the colour when I selected and started a new track.
I have already added the buttons.update() to some function, but several functions, such as on_playback_new_track, on_item_focus_change, and on_colors_changed, returned an error.
Object doesn't support property or method 'update'
The metadb are set to fb.GetNowPlaying. When set to fb.GetFocusItem, it does change on the fly when selecting a new track but as expected it doesn't get the colour for next track, although it can be passed by activating the cursor follow playback.
(https://i.imgur.com/tYovEiH.gif)
Hello,
How did you arrange the tabs in two rows? What I mean is the point where you have icons above and captions below (Console, New Tab, etc.).
Hello,
How did you arrange the tabs in two rows? What I mean is the point where you have icons above and captions below (Console, New Tab, etc.).
Hello there,
Make sure to first install the font (icon) you want to use. I'm using Microsoft's Segoe Fluent Icons font for this one. Download Link (https://aka.ms/SegoeFluentIcons)
Then, using the Character Map app, you may view and select it.
(https://i.imgur.com/32EP4XD.gif)
Console:
Error: JScript Panel (DarkOne4Mod - Display Panel v1.0 build20160929 by super-gau and tedGo, includes partial codes by fbuser, Br3tt and T.P Wang): Invalid parameter. File: <main>
Line: 184, Col: 3
<source text only available at compile time>
I thought one of those variables was not initialized but my trying to solve it myself didn't work so far.
JScript panel version: 1.1.6
Foobar version: 2.0 (x86) running via PlayOnLinux
Does Linux have Microsoft Sans Serif font? If not, type in one you do have. (Try Arial Black) It still shouldn't crash, however. At least it wouldn't in Windows.
Or delete the line or put a // in front of it and see what happens.
I suggest downloading the latest non modded Darkone here...
https://foobar-users.de/index.php?topic=4851.0
Yeah thanks. Commenting it out worked to remove the error, but left a blank panel
But changing the font to one that I did have worked perfectly. I had to use FreeSerif which is close enough to the size of what Microsoft Sans Serif would've been.
You're the man, and thanks again.
Merry Christmas (:
Hello,
How did you arrange the tabs in two rows? What I mean is the point where you have icons above and captions below (Console, New Tab, etc.).
Hello there,
Make sure to first install the font (icon) you want to use. I'm using Microsoft's Segoe Fluent Icons font for this one. Download Link (https://aka.ms/SegoeFluentIcons)
Then, using the Character Map app, you may view and select it.
(https://i.imgur.com/32EP4XD.gif)
Thank you! One more question - is it possible to darken the area (or change the color) that I marked on the screenshot? https://imgbox.com/bJx5uR3l
@ms1602
That's a very good lookin' .mp4 screendump!
What program did you use for that?
@ms1602
That's a very good lookin' .mp4 screendump!
What program did you use for that?
Paint 3D.
Thank you! One more question - is it possible to darken the area (or change the color) that I marked on the screenshot? https://imgbox.com/bJx5uR3l
For the time being, I don't believe that is possible on the Default UI. ColumnsUI can do it, however you may have to change and compile the component from source yourself.
For the JScript panel part, it can be done.
@marc2k3
I always enjoy using it. thank you.
v3.3.8
"Album Art + Text Display" sample
Are the following options no longer available?
- Context menu > Horizontal alignment/Vertical alignment
Thanks.
Yep, no alignment options. There's a note in the script if you look in the panel or the online copy here...
https://github.com/jscript-panel/component/blob/96dd92ef8890cf3554ec59810d608c40bf4aa6be/samples/Album%20Art%20%2B%20Text%20Display.txt#L12-L20
Whatever mods you had previously will continue to work so keep using them if needed. There have not been any changes to the underlying .js files.
got it. thank you.
@marc2k3
Isn't "%codec_long%" field supported?
for example:
%codec% Monkey's Audio → %codec_long% Monkey's Audio / High
Foobar2000:Version 2.1 Preview Change Log
2023-06-05
https://wiki.hydrogenaud.io/index.php?title=Foobar2000:Version_2.1_Preview_Change_Log#2023-06-05
Yes it's supported. I don't have any monkey's audio files to test but for an mp3 I'm listening to right now....
I was finally able to confirm it (Why?).
Thanks.
I display the Cdec profile and the bitrate in JScript Panel 3 3.3.9 / Text Display (see appendix).
Unfortunately, an incorrect bit rate is always displayed when starting the file. Instead of 320 kbps it says 328 kbps (see appendix).
Only when I carry out further manipulation (stop or pause) or I edit the properties will the value be displayed correctly.
My costume text:
$font(Microsoft Sans Serif,16,700)%codec_profile% / %bitrate% kbps
Where is the error?
I hope you understand Google Translate. Sorry
Use %__bitrate%
Small cause - big effect. A little underline...
THX for the help.
Use %__bitrate%
Just curious.
What's the difference between %bitrate% (which I use myself and don't have problems with) and %__bitrate% (or $info(bitrate) ) ?
I found another option:
Enable per-seconds updates. Then the correct bitrate comes according to the value set in Preferences/Advanced/Properties dialog/VBR bitrate updates per second.
The displayed VBR values also change every second.
If it says "0" seconds, then the CBR value is correct and the VBR values do not change.
I found another option:
Enable per-seconds updates. Then the correct bitrate comes according to the value set in Preferences/Advanced/Properties dialog/VBR bitrate updates per second.
The displayed VBR values also change every second.
If it says "0" seconds, then the CBR value is correct and the VBR values do not change.
Yes, I find this a bit annoying especially with AAC radio streams altering between anything like 123 and 130kbps.
I forgot to add this callback inside the main panel script which updates VBR bitrates according to the preferences...
function on_playback_dynamic_info() {
text.refresh();
}
Unfortunately, this doesn't change the fact that the correct kbps value is only displayed after about 1 second.
This is the value set in Preferences/Advanced/Properties dialog/VBR bitrate updates per second.
If it says "0", then the VBR values do not change. But the correct values are displayed without delay.
I inserted the added code in the main panel script and also in the Text Display Script for testing.
But maybe I'm doing something wrong?
I'm using standard fb2k SDK methods like any other component. Whatever string is returned from the various title format methods are completely untouched by me. I really don't see how I can do anything about it.
Same problem with "Item Details". Only MP3's (CBR/VBR) are affected. So its not a problem with the JScript.
Recently the developer of https://github.com/saschanaz/jxl-winthumb released a 32-bit version of the wic plugin for the jxl codec. And I again return to my old desire to store a cache of spectrogram images in jxl format. This plugin works, but in foobar2000 the entire jxl image on the panel is covered with a white translucent color, in other programs there is no such behavior, the file itself is of normal color, which means the problem is how the jscript panel processes wic. Find and fix this issue please.
Attach the jxl file as embedded art to an audio track. See if fb2k 2.0+ or Columns UI artwork panels display it correctly. I can't test because I don't have admin rights for registering DLLs right now.
Since I have no idea about the above issue I posted and shared my code in an old jxlthumb issue that mentioned fb2k here...
https://github.com/saschanaz/jxl-winthumb/issues/22#issuecomment-1805551035
edit: so my code isn't at fault. Something in jxlthumb needs fixing.
@marc2k3 :
I recently updated to the latest version (i was lagging behind a few versions) and for some reasons my rating in JS Playlist are grey instead of the previous version in which they were golden.
Maybe i missed a step or i didnt find the option to change the color. Would you happen to know why ?
thanks
Grey :

Golden :
This is a side effect of the dynamic colour support that was added. It defaults to the text colour because that makes sure it's always readable regardless of background colour.
But if you don't use dynamic colours, I guess I should restore the old behaviour or make it customisable. I'll have a fix in the next release.
@etip , if you can't wait for the next release, these files should fix your issue. Save inside the component folder/samples/jsplaylist
https://raw.githubusercontent.com/jscript-panel/component/main/samples/jsplaylist/main.js
https://raw.githubusercontent.com/jscript-panel/component/main/samples/jsplaylist/playlist.js
yep, it works, Thanks !
In regard to JS Playlist:
Is there anything I can do on my end to eliminate displaying the information indicated by the red arrows in the two graphics?
Edit: Maybe I am posting in the wrong subforum?
Forget the above request. I figured out a way! :)
Edit: ...But it does leave a section of empty vertical space.
Is there an auto size function for the contents of a panel?
When I reduce the display of the panel, in the thumbs and album art samples I see an adaptation, while in the text display and texer reader samples, the text does not adapt to the reduction of the panel.
Edit: ...But it does leave a section of empty vertical space.
Change the row height to 1.
Change the row height to 1.
Anything below a setting of 3 in the row height loses the track count and total duration display. (At least on this PC it does)
Anyway, I think it is fine the way it is set up now.
Hello, sorry for budging in... I was just wondering if is it possible to write values to a Song's Details tab? I want to implement my version of foo_playcount as it's not customisable...
Especially the Played field and the Last played field, in foo_playcount their tags are %play_count% and %last_played% respectively.
I've attached an image to show what I exactly meant...
I've been modding the samples\Status Bar.txt file, and I have it working pretty well. I've come upon a couple issues though.
First, I added items in the context menu for changing the font and fontsize via InputBoxes. After getting the new value, I found that refresh() and window.Repaint() don't suffice, and I've gone with window.Reload(). This works, but after it does, a standard context menu for a default panel shows of its own accord. Is there a way to suppress that?
Second, I'm getting results I don't expect from utils.CalcTextWidth(). I've taken to multiplying the result by a fudge factor that looks pretty close to 96 pixels / 72 points. Does the function return a value in points?
Ah, so I found the step I omitted after changing the font/fontsize and before trying to refresh: I hadn't actually rerun CreateFontString. :-[ Still, the appearing context menu on Reload was weird.
And the CalcTextWidth bit is clear to me now. Give it points, get points back. Want pixels? Give it pixels.
Hello, sorry for budging in... I was just wondering if is it possible to write values to a Song's Details tab? I want to implement my version of foo_playcount as it's not customisable...
Especially the Played field and the Last played field, in foo_playcount their tags are %play_count% and %last_played% respectively.
I've attached an image to show what I exactly meant...
Found an extension called External Tagger which can tag files and send them to a SQLite DB or APE tags, not sure if it's possible to integrate it with this. There's m-Tags as well but haven't been having a lot of success so far...
Playback statistics were built in to JSP2 (and SMP inherited them) but it was removed in JSP3. I'm working on bringing them back. It's basically done, I just haven't written the docs. That's a hateful job.
You retrieve values with standard title formatting and setting values is done via various handle methods like
handle.SetPlaycount(25);
Integration with the properties dialog is all done automatically. Here's an old screenshot as an example:
(https://kbuffington.github.io/foo_jscript_panel/images/single.png)
The one major flaw in previous implementations is that the title formatting was hard coded to %artist% - %title%. All I cared about was storing last.fm stats which worked well for me but it was probably less useful for everyone else. The new version is entirely configurable. But any changes to the title format will wipe all previous data. It has to be used with care!
That's a hateful job.
Speaking as a retired technical writer, I'll freely review and or edit any Foobar2000 developer's documentation, if that will ever help.
@Azuriye - see the latest release page/docs
https://github.com/jscript-panel/release/releases
@2tec - thanks for the offer. Not sure you'd want to check all the content on my docs site though.
https://jscript-panel.github.io/docs/
It's quite a lot and goes way beyond the average fb2k component. :P
This is the script I modified from samples. Now I want to make the slider display at the start position of the seekbar and display "0:00" on both sides of the seekbar after the playback stops
@Azuriye - see the latest release page/docs
https://github.com/jscript-panel/release/releases
@2tec - thanks for the offer. Not sure you'd want to check all the content on my docs site though.
https://jscript-panel.github.io/docs/
It's quite a lot and goes way beyond the average fb2k component. :P
Hello! Thanks a lot for implementing this feature, have a small doubt about whether the Playback Statistics (foo_playcount) plugin is needed or if can I remove it now and implement everything with the JScript Panel. Also is it possible to have a context menu to hook it with my foobar toolbar buttons? I've attached images below to explain...
The component already exposes 10 main menu commands and you can use them for your needs.
https://jscript-panel.github.io/docs/callbacks/#on_main_menuindex
Your code inside the callback can make it function like a context menu item...
(not tested as I don't have a fb2k instance with me right now but you get the idea)
function on_main_menu(index) {
if (index >= 1 && index <= 5) {
var items = fb.GetSelection(); // should work with playlist or library viewer selections
if (items.Count == 0) return;
for (var i = 0; i < items.Count; i++) {
items.GetItem(i).SetRating(index);
}
items.RefreshStats();
}
// use one the remaining indexes for setting zero rating or whatever.
}
This is the script I modified from samples. Now I want to make the slider display at the start position of the seekbar and display "0:00" on both sides of the seekbar after the playback stops
Inside on_paint, there is this...
if (fb.IsPlaying) {
...
}
Just add an else like...
if (fb.IsPlaying) {
...
} else {
gr.WriteText("0:00", bold_font, colours.time, seekbar.x - _scale(51), (panel.h - _scale(12)) / 2, _scale(45), _scale(12), DWRITE_TEXT_ALIGNMENT_TRAILING, DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
gr.WriteText("0:00", bold_font, colours.time, seekbar.x + seekbar.w + _scale(12), (panel.h - _scale(12)) / 2, _scale(45), _scale(12), DWRITE_TEXT_ALIGNMENT_LEADING, DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
}
The component already exposes 10 main menu commands and you can use them for your needs.
https://jscript-panel.github.io/docs/callbacks/#on_main_menuindex
Your code inside the callback can make it function like a context menu item...
(not tested as I don't have a fb2k instance with me right now but you get the idea)
function on_main_menu(index) {
if (index >= 1 && index <= 5) {
var items = fb.GetSelection(); // should work with playlist or library viewer selections
if (items.Count == 0) return;
for (var i = 0; i < items.Count; i++) {
items.GetItem(i).SetRating(index);
}
items.RefreshStats();
}
// use one the remaining indexes for setting zero rating or whatever.
}
My bad, I'm sorry for not checking the documentation... However, Thanks a lot for implementing so many features! was about to lose hope and move to MusicBee until you implemented the new feature.
The component already exposes 10 main menu commands and you can use them for your needs.
https://jscript-panel.github.io/docs/callbacks/#on_main_menuindex
Your code inside the callback can make it function like a context menu item...
(not tested as I don't have a fb2k instance with me right now but you get the idea)
function on_main_menu(index) {
if (index >= 1 && index <= 5) {
var items = fb.GetSelection(); // should work with playlist or library viewer selections
if (items.Count == 0) return;
for (var i = 0; i < items.Count; i++) {
items.GetItem(i).SetRating(index);
}
items.RefreshStats();
}
// use one the remaining indexes for setting zero rating or whatever.
}
Hello @marc2k3 I guess I've found a bug with the above code... Here is my implementation so far.
function on_main_menu(index) {
switch (index) {
case 1:
var handle_list = plman.GetPlaylistSelectedItems(plman.ActivePlaylist); // I've tried var items = fb.GetSelection(); as well but still the same result.
if (handle_list.Count == 0) return;
if (fb.GetSelectionType() != 1) return;
var tfo = fb.TitleFormat("%jsp3_loved%");
var favourites = tfo.EvalWithMetadbs(handle_list).toArray();
for (var i = 0; i < handle_list.Count; i++) {
if (favourites[i] === "1") handle_list.GetItem(i).SetLoved(0);
else handle_list.GetItem(i).SetLoved(1);
}
handle_list.RefreshStats();
break;
}
}
I have a playlist of 604 tracks selected and on properties tab shows the same...
Upon applying the function and checking the properties tab there are 645 tracks? Around 41 duplicate tracks made in when applying the setLoved function...
Upon further inspecting the playlist of the correct and wrong tracks I've found out it's duplicates with the same track name but different albums.
I've attached images for you to look into. The left playlist is the correct playlist and the right playlist is wrong, You can see how there are entries added in the right playlist but weren't there to begin with in the left playlist.
This is the script I modified from samples. Now I want to make the slider display at the start position of the seekbar and display "0:00" on both sides of the seekbar after the playback stops
Inside on_paint, there is this...
if (fb.IsPlaying) {
...
}
Just add an else like...
if (fb.IsPlaying) {
...
} else {
gr.WriteText("0:00", bold_font, colours.time, seekbar.x - _scale(51), (panel.h - _scale(12)) / 2, _scale(45), _scale(12), DWRITE_TEXT_ALIGNMENT_TRAILING, DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
gr.WriteText("0:00", bold_font, colours.time, seekbar.x + seekbar.w + _scale(12), (panel.h - _scale(12)) / 2, _scale(45), _scale(12), DWRITE_TEXT_ALIGNMENT_LEADING, DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
}
Thanks Marc for your help. I added your code but not getting the expected result. Hope to get your help again.
Below is the result I want.
Upon further inspecting the playlist of the correct and wrong tracks I've found out it's duplicates with the same track name but different albums.
I've been explicit about this. An earlier comment in this thread before I released the component:
The one major flaw in previous implementations is that the title formatting was hard coded to %artist% - %title%. All I cared about was storing last.fm stats which worked well for me but it was probably less useful for everyone else. The new version is entirely configurable. But any changes to the title format will wipe all previous data. It has to be used with care!
When I announced the component release in the main thread:
Playback statistics are back. The title format pattern for binding database records to tracks is no longer hard coded. It can edited to anything you like.
If you missed that, the changelog and release page included this:
https://jscript-panel.github.io/docs/playback-statistics/
Read with care. Behaviour and functionality has changed since the previous implementation in JScript Panel 2.
Specifically...
Unlike previous implementaions in other scripting components, this allows you to customise the title formatting that database records are bound to.
The default is $lower($meta(artist,0) - %title%) but it can be changed via File>Preferences>Advanced>Tools>JScript Panel 3>Playback Statistics Title Format.
Note that changing this requires an immediate foobar2000 restart and any previously saved data is lost forever. Be careful!
Remember that if you think of using %path%, you must also include %subsong%. One physical file can have the same path for multiple handles if it's a cuesheet or other type of track with multiple chapters.
You can grumble all you like about me using a crappy default but I'm not apologising to anyone who doesn't read or did read it but doesn't understand the premise.
Upon further inspecting the playlist of the correct and wrong tracks I've found out it's duplicates with the same track name but different albums.
I've been explicit about this. An earlier comment in this thread before I released the component:
The one major flaw in previous implementations is that the title formatting was hard coded to %artist% - %title%. All I cared about was storing last.fm stats which worked well for me but it was probably less useful for everyone else. The new version is entirely configurable. But any changes to the title format will wipe all previous data. It has to be used with care!
When I announced the component release in the main thread:
Playback statistics are back. The title format pattern for binding database records to tracks is no longer hard coded. It can edited to anything you like.
If you missed that, the changelog and release page included this:
https://jscript-panel.github.io/docs/playback-statistics/
Read with care. Behaviour and functionality has changed since the previous implementation in JScript Panel 2.
Specifically...
Unlike previous implementaions in other scripting components, this allows you to customise the title formatting that database records are bound to.
The default is $lower($meta(artist,0) - %title%) but it can be changed via File>Preferences>Advanced>Tools>JScript Panel 3>Playback Statistics Title Format.
Note that changing this requires an immediate foobar2000 restart and any previously saved data is lost forever. Be careful!
Remember that if you think of using %path%, you must also include %subsong%. One physical file can have the same path for multiple handles if it's a cuesheet or other type of track with multiple chapters.
You can grumble all you like about me using a crappy default but I'm not apologising to anyone who doesn't read or did read it but doesn't understand the premise.
My bad, haven't understood what it fully meant, but it'd definitely fix my issue of duplicate tracks by using path and subsong...
Also is it possible to have a skip field like how we have for play count or would that complicate things up? Would be nice to have skip statistics so that the user knows track ABC has been presented X times and skipped Y times?
I'm not totally averse to adding more fields but foo_skip and foo_skipcount provide that already.
Admittedly I have no idea how those records are bound to tracks.
I'm not totally averse to adding more fields but foo_skip and foo_skipcount provide that already.
It's just that it would be better to have all of them in one plugin that way the user can customise the logic behind what counts as a play or a skip...
Hi there,
I am new to JScript Panel.
I installed the latest version, and used the sample "Text Display" (as-is, it is not modified).
I see this small square box at the bottom of the panel.
When I click the square box, it goes to the top of the panel.
Any idea how to get rid of it?
(https://i.ibb.co/Wzh61vJ/2023-11-24-07-22-06-foobar-USB-foobar2000.png)
"Most included samples require the installation of FontAwesome which you can grab here" https://jscript-panel.github.io/docs/
(Its an arrow)
^ It would be great to have an option (or pointer to modify the code) to disable those scroll arrows though, because the trouble is when you only want a small 20px height panel, all you get are arrows and no text. (At least that was the case last time I used it)
"Most included samples require the installation of FontAwesome which you can grab here" https://jscript-panel.github.io/docs/
(Its an arrow)
Got it. Thank you.
^ It would be great to have an option (or pointer to modify the code) to disable those scroll arrows though, because the trouble is when you only want a small 20px height panel, all you get are arrows and no text. (At least that was the case last time I used it)
I'll remove them in the next release.
edit: code has been updated on github. If anyone wants it right now, save this inside your component folder\samples\js
https://raw.githubusercontent.com/jscript-panel/component/main/samples/js/text_display.js
A new component has been released with text display arrows removed and skipcount added to playback stats. Links in main thread.
If possible in the next version of Text Display add the option Album Art bottom, Text top, at the moment I had to add an additional sample panel to recreate the effect as shown in the images:
(https://i.postimg.cc/vDrNYK5C/Screenshot-2023-11-26-065820.png) (https://postimg.cc/vDrNYK5C)
(https://i.postimg.cc/H89Z6JpT/Screenshot-2023-11-26-065912.png) (https://postimg.cc/H89Z6JpT)
By the way marc2k3, I feel like someone has mentioned this before but is it possible to have JSPlaylist imitate how SimPlaylists work? It will be a really great addition for users who want to switch from SimPlaylists as it's an old component and hasn't been updated so the white borders and bars are really visible in FB2K 2.0, The only two features which are missing are Sub-groups and positioning the album art cover to the left of the tracks apart from that JSPlaylist seems to be very close to replicating SimPlaylists...
If I recollect a WSH Panel version of JSPlaylist had the option to display album art cover to the left of the tracks. I've attached three images including the one with the WSH Panel taken from a Reddit post...
By the way marc2k3, I feel like someone has mentioned this before but is it possible to have JSPlaylist imitate how SimPlaylists work? It will be a really great addition for users who want to switch from SimPlaylists as it's an old component and hasn't been updated so the white borders and bars are really visible in FB2K 2.0, The only two features which are missing are Sub-groups and positioning the album art cover to the left of the tracks apart from that JSPlaylist seems to be very close to replicating SimPlaylists...
If I recollect a WSH Panel version of JSPlaylist had the option to display album art cover to the left of the tracks. I've attached three images including the one with the WSH Panel taken from a Reddit post...
This problem you raise has been my struggle since I installed foobar many years ago. I am referring to the management of groups.
A long time ago, when I was working with Default UI I installed Simplaylist, which has been the playlist manager that I liked the most when it came to grouping albums with several discs. I remember that the only thing that I didn't like was the line that it drew when painting the %discnumber% metadata to the right since it was enough to frame the album the line that was painted in the abum. I think I could not remove it as I was very limited when programming scripts.
Then I installed Columns UI which is more customizable. After creating different scripts I got the current look (Image) which is not perfect either as I don't like that the grouping that deals with the %discnumber% does not allow painting to the right of the cover and does it on top. I have been asking for years to music music that is its creator, but until today I have not obtained it. Even so the appearance of albums with several discs looks pretty good, at least it's the best I could program. I recommend you to install it and try it.
The right panel showing the covers with their most important data is made from the JsPlaylist before Marc2k3 decided to remove the collapsing of the albums.
Then I installed Columns UI which is more customizable. After creating different scripts I got the current look (Image) which is not perfect either as I don't like that the grouping that deals with the %discnumber% does not allow painting to the right of the cover and does it on top. I have been asking for years to music music that is its creator, but until today I have not obtained it. Even so the appearance of albums with several discs looks pretty good, at least it's the best I could program. I recommend you to install it and try it.
Hey there! Thanks for sharing your insight, just few days ago a friend of mine also showcased me his CUI theme and it caught me by surprise...
Spending my weekend setting up CUI only to release at the end of today that all my efforts are in vain as resizing in CUI wasn't viable with my theming which consists of Spider Monkey and a JScript 3 panel, my layout basically couldn't scale properly when minimised or on fullscreen and I've exhausted all options such as locking layouts and etc. but that didn't resolve the issue to any degree.
This ultimately made me go back to DUI... Now, about JSPlaylist the in-built Playlist Manager/Organizer which is tucked in a small arrow mark looks neat and subtle. It will definitely be a nice to have if JSPlaylist could imitate SimPlaylist to some extent while giving the user the option to do so within the JSPlaylist's option panel.
Then I installed Columns UI which is more customizable. After creating different scripts I got the current look (Image) which is not perfect either as I don't like that the grouping that deals with the %discnumber% does not allow painting to the right of the cover and does it on top. I have been asking for years to music music that is its creator, but until today I have not obtained it. Even so the appearance of albums with several discs looks pretty good, at least it's the best I could program. I recommend you to install it and try it.
Hey there! Thanks for sharing your insight, just few days ago a friend of mine also showcased me his CUI theme and it caught me by surprise...
Spending my weekend setting up CUI only to release at the end of today that all my efforts are in vain as resizing in CUI wasn't viable with my theming which consists of Spider Monkey and a JScript 3 panel, my layout basically couldn't scale properly when minimised or on fullscreen and I've exhausted all options such as locking layouts and etc. but that didn't resolve the issue to any degree.
This ultimately made me go back to DUI... Now, about JSPlaylist the in-built Playlist Manager/Organizer which is tucked in a small arrow mark looks neat and subtle. It will definitely be a nice to have if JSPlaylist could imitate SimPlaylist to some extent while giving the user the option to do so within the JSPlaylist's option panel.
I have to tell you that I made several queries to Marc2k3 when I set up my 64-bit foobar2000. I was testing JsPlaylist to see if I liked the groupings. But I didn't like them and I made several requests and he answered me that the component was an inheritance of Br3tt and that he didn't plan to make improvements.
I have to tell you that I made several queries to Marc2k3 when I set up my 64-bit foobar2000. I was testing JsPlaylist to see if I liked the groupings. But I didn't like them and I made several requests and he answered me that the component was an inheritance of Br3tt and that he didn't plan to make improvements.
Ah fair enough, unfortunately I don't think CUI would be a viable option for me yet due to the issue I've mentioned above but apart from that I guess I'm left with nothing on table...
I'm never going back on the changes I've made to JSPlaylist. If anyone doesn't like it, don't use it. It really is that simple.
And subgroups are never going to happen. Anyone can transplant the jsplaylist folder from the component folder to somewhere else where it will untouched by component upgrades and make their own changes.
By the way marc2k3, is it possible in JSPlaylist > Colours > Text to separate this header section alone and name it as Highlight? Similar to how foobar2000 has a colour section for Text and Highlight separately in Colors and Font?
By the way marc2k3, is it possible in JSPlaylist > Colours > Text to separate this header section alone and name it as Highlight? Similar to how foobar2000 has a colour section for Text and Highlight separately in Colors and Font?
Try this one. Copy and replace the files into your jsplaylist folder. Mine is on
C:\Users\Username\AppData\Roaming\foobar2000-v2\user-components\foo_jscript_panel3\samples\jsplaylist
(https://i.imgur.com/u83Vnnt.png)
Try this one. Copy and replace the files into your jsplaylist folder. Mine is on
C:\Users\Username\AppData\Roaming\foobar2000-v2\user-components\foo_jscript_panel3\samples\jsplaylist
(https://i.imgur.com/u83Vnnt.png)
Hey, thanks a lot for sharing your patches! I've also noticed you in the DUI Gallery forum post, but to reconfirm for the JS playlist, are you using FontAwesome? or is it a custom font?
Try this one. Copy and replace the files into your jsplaylist folder. Mine is on
C:\Users\Username\AppData\Roaming\foobar2000-v2\user-components\foo_jscript_panel3\samples\jsplaylist
Hey, thanks a lot for sharing your patches! I've also noticed you in the DUI Gallery forum post, but to reconfirm for the JS playlist, are you using FontAwesome? or is it a custom font?
Yes, it's the default FontAwesome.
Yes, it's the default FontAwesome.
Thanks for confirming.
Just posting a reminder that any mods to files inside the component folder are wiped out on component updates. I will add this for the next release but if you do mods that aren't going to be included, you really should copy the files elsewhere and update the import paths in the main panel.
Just posting a reminder that any mods to files inside the component folder are wiped out on component updates. I will add this for the next release but if you do mods that aren't going to be included, you really should copy the files elsewhere and update the import paths in the main panel.
Yeah will keep that in mind thanks.
(https://i.imgur.com/fJP2lds.png)
Suggestion to Marc regarding the JSPlaylist. I made the following minor changes:
- Added custom rating colour
- Adjust mood and rating off colour
- Option to hide visible borders (On selected tracks, Headers and Album art)
- Mood size adapt to single track line mode
- Added a toggle switch for last.fm playcount sync
I've added highlight and rating to the colours menu in the latest release. I'm not interested in the other options.
I've added highlight and rating to the colours menu in the latest release. I'm not interested in the other options.
No problem, thanks for the update tho!
- Added custom rating colour
- Adjust mood and rating off colour
- Option to hide visible borders (On selected tracks, Headers and Album art)
- Mood size adapt to single track line mode
- Added a toggle switch for last.fm playcount sync
Interesting, the theme.
I'm making some changes.
Where can I find the icon set you used?
(https://i.postimg.cc/3dzBTYxS/Screenshot-2023-12-05-100032.png) (https://postimg.cc/3dzBTYxS)
- Added custom rating colour
- Adjust mood and rating off colour
- Option to hide visible borders (On selected tracks, Headers and Album art)
- Mood size adapt to single track line mode
- Added a toggle switch for last.fm playcount sync
Interesting, the theme.
I'm making some changes.
Where can I find the icon set you used?
(https://i.postimg.cc/3dzBTYxS/Screenshot-2023-12-05-100032.png) (https://postimg.cc/3dzBTYxS)
Hi there, it's from the Segoe Fluent Icons font.
(https://i.imgur.com/32EP4XD.gif)
@ eurekagliese
Thank you. I'm studying and implementing the theme.
64 bit:
(https://i.postimg.cc/qhnW1YNg/Screenshot-2023-12-05-134506.png) (https://postimg.cc/qhnW1YNg)
(https://i.postimg.cc/bDqp2kYZ/Screenshot-2023-12-05-134958.png) (https://postimg.cc/bDqp2kYZ)
Hello again, Marc. Is there any plan to add more features to the last.fm bio like fetch the artist's country flag, genre, and additional information like the layout on Wil-B's Biography.
(https://i.imgur.com/zOqkZKv.png)
It's not likely. I use the lastfm API and that information is not present in the JSON I fetch. I assume that SMP script is scraping the html from the website which I really don't want to do.
edit: and yes I'm a big fat hyprocrite for scraping html to download images but that's because I have no other choice. :P
Understandable. Thank you for your response.
At some point I'll probably integrate text and images in the same panel and have a blurry background so it looks a bit nicer.
If people had file tags with the country, I guess displaying that would be super simple as well but I have no idea what standard people are using for that.
Actually I use the tagger tool in SMP Biography to tag genres from last.fm, and it also fetches the artist's locale.
(https://i.imgur.com/azNsV4m.png)
(https://i.imgur.com/P2nB5Rl.png)
I previously used Grimes' Flag script (which works as intended), but I had to manually provide a nation tag to each artist, which is a time-consuming approach that may not be preferable when we like to discover new artists.
I thought it would be cool if there was a country flag script that would automatically fetch and surprise us with where they originated from.
Last.fm Bio + Image
Nice!
(https://i.imgur.com/cCqxgYp.png)
Regarding flags, it can be done with the
Twitter Color Emoji font.
https://github.com/13rac1/twemoji-color-font/releases
Stock windows fonts don't support it.
I'm not checking now but I guess there must be an easier way to map country codes to the unicode needed.
I just manually tested this for GB...
var gb = '\uD83C\uDDEC\uD83C\uDDE7';
edit: a quick google found this...
https://gist.github.com/angusjf/cb53d2adabd072331a5aedb05c86cc54
I'll probably bundle it in the next component release and then you can...
// _jsonParseFile is from samples\js\common.js
var flags_json = _jsonParseFile(fb.ComponentPath + "country_flags.json");
then..
flags_json['gb'].flag
flags_json['us'].flag
etc
The gist is missing like 20 countries.
You have a complete table of ISO-3 codes, full name and ISO-2 codes conversion tables on my scripts (https://github.com/regorxxx/World-Map-SMP). Also multiple helpers to handle name variations and capitalization (since Last.fm provides the country name, but not the ISO codes).
I use images for flags, though, which are also there. So if you want to use images, there is no need to reinvent the wheel... for fonts that may be the best option.
I'm not going to use images. I'm currently messing around with a title format function built in to the component. Then they can be inlined in any text anywhere.
I'd probably add a utils.GetCountryFlag method or similar for when JS without title format is required,
That looks great; on second thought fonts resize much better than images so I may switch and use that + my current conversion tables.
That won't be possible until SMP gets DirectWrite support.
It's good to see it's on its way!
Hello marc2k3, is it possible to let JScript Panels access this panel in Preferences>Keyboard shortcuts? Some components only expose keyboard shortcuts instead of the traditional way through RunContextCommand. What I'm trying to achieve is when I click a JScript Button it executes the keyboard shortcut context. Either this approach or maybe allowing JScript to send key combinations so that Keyboard shortcuts pick it up and run the command?
Hello marc2k3, is it possible to let JScript Panels access this panel in Preferences>Keyboard shortcuts? Some components only expose keyboard shortcuts instead of the traditional way through RunContextCommand.
This actually not what you can call "the traditional way". It is just the option to execute context menu commands.
As you're screen shot shows a part of the random pools keyboard shortcut section, I guess you are refering to its shortcuts for single pools, for which no menu entry exist. But as you also can see on the screen shot, they are listed under [main] and not [context]. Therefore you need to execute them with RunMainMenuCommands().
This actually not what you can call "the traditional way". It is just the option to execute context menu commands.
My bad my wording was wrong there.
As you're screen shot shows a part of the random pools keyboard shortcut section, I guess you are refering to its shortcuts for single pools, for which no menu entry exist. But as you also can see on the screen shot, they are listed under [main] and not [context]. Therefore you need to execute them with RunMainMenuCommands().
Thanks a-lot, I had some issues figuring out this but it was a combination of incorrect Pool names, fixing this worked like a charm. Thanks a-lot!
Thanks for the update Marc. Another question, how the country flag code read from multiple value tag like <COUNTRY> Gothenburg; Västra Götaland; Sweden ?
Title format would be
$country_flag($meta(country,$sub($meta_num(country),1)))
JS could be
var flag = ''
var handle = fb.GetFocusItem();
if (handle) {
var f = handle.GetFileInfo();
var country = f.MetaFind("country");
if (country > -1) {
var num = f.MetaValueCount(country);
var last_value = f.MetaValue(country, num - 1);
flag = utils.GetCountryFlag(last_value);
}
}
Thank you for the prompt response!
(https://i.imgur.com/sFl5crL.png)
@eurekagliese
Text Display.txt
Custom context...
Could you please upload it?
Thanks.
@eurekagliese
Text Display.txt
Custom context...
Could you please upload it?
Thanks.
Sure, here you go
$font(Segoe UI,24)
[%title% ]$crlf()
$font(Segoe UI,14)
[%artist% ] [$font(Twitter Color Emoji,18)$country_flag($meta(country,$sub($meta_num(country),1)))$font() ]$crlf()
[%album% '('%year%')']$crlf()
Make sure to install the Twitter Color Emoji font first
https://github.com/13rac1/twemoji-color-font/releases/download/v14.0.2/TwitterColorEmoji-SVGinOT-14.0.2.zip
Great!
Thanks.
(https://i.imgur.com/fNDjXmd.png)
I installed the fonts:
https://github.com/13rac1/twemoji-color-font#examples
but to me only the acronym of the nation appears and not the flag:
(https://i.postimg.cc/7f4qb520/Screenshot-2023-12-11-135109.png) (https://postimg.cc/7f4qb520)
Try to reboot first
System reboot was missing. Thank you.
(https://i.postimg.cc/qNRFbrKz/Screenshot-2023-12-11-141046.png) (https://postimg.cc/qNRFbrKz)
Restarting fb2k is enough to pick up new fonts. A system reboot is far too extreme.
(https://i.imgur.com/sFl5crL.png)
@eurekagliese
If you look closely, you can see that "Last.fm Bio + Image" is placed above and below.
It can be used for vertically long or almost square panels.
Could you please share "Last.fm Bio + Image" Script?
I'm sorry for always asking for your help.
Thanks.
(https://i.imgur.com/sFl5crL.png)
@eurekagliese
If you look closely, you can see that "Last.fm Bio + Image" is placed above and below.
It can be used for vertically long or almost square panels.
Could you please share "Last.fm Bio + Image" Script?
I'm sorry for always asking for your help.
Thanks.
It's not a problem at all. I'm happy to share.
Here's the code, of course the credit goes to Marc, I just changed tiny bit of it.
// ==PREPROCESSOR==
// @name "Last.fm Bio"
// @author "marc2003"
// @import "%fb2k_component_path%helpers.txt"
// @import "%fb2k_component_path%samples\js\lodash.min.js"
// @import "%fb2k_component_path%samples\js\common.js"
// @import "%fb2k_component_path%samples\js\panel.js"
// @import "%fb2k_component_path%samples\js\lastfm.js"
// @import "%fb2k_component_path%samples\js\thumbs.js"
// @import "%fb2k_component_path%samples\js\text.js"
// ==/PREPROCESSOR==
var margin = _scale(12);
var panel = new _panel();
var lastfm = new _lastfm();
var text = new _text('lastfm_bio', 0, 0, 0, 0);
var thumbs = new _thumbs();
text.paint = function (gr) {
var colour = thumbs.blur_img ? RGB(255, 255, 255) : panel.colours.text;
var colourh = thumbs.blur_img ? RGB(255, 255, 255) : panel.colours.highlight;
gr.WriteText(this.header_text(), panel.fonts.title, colourh, this.x, margin, this.w, panel.h - (margin * 2), DWRITE_TEXT_ALIGNMENT_LEADING, DWRITE_PARAGRAPH_ALIGNMENT_CENTER, DWRITE_WORD_WRAPPING_NO_WRAP, DWRITE_TRIMMING_GRANULARITY_CHARACTER);
if (this.text_layout) {
gr.WriteTextLayout(this.text_layout, colour, this.x, this.y + margin, this.w, this.ha, this.offset);
this.up_btn.paint(gr, colour);
this.down_btn.paint(gr, colour);
}
}
thumbs.image_containsxXY = function (x, y) {
return this.images.length && this.containsXY(x, y);
}
thumbs.move = function (x, y) {
this.mx = x;
this.my = y;
return this.containsXY(x, y);
}
thumbs.paint = function (gr) {
if (this.images.length) {
_drawImage(gr, this.blur_img, 0, 0, panel.w, panel.h, image.crop_top);
_drawOverlay(gr, 0, 0, panel.w, panel.h, 120);
this.image_xywh = _drawImage(gr, thumbs.images[thumbs.image], this.x, this.y, this.w, this.h, image.crop_top);
} else {
this.image_xywh = [];
}
}
thumbs.size = function () {}
thumbs.wheel = function (s) {
if (this.containsXY(this.mx, this.my)) {
if (this.images.length > 1) {
this.image -= s;
if (this.image < 0) {
this.image = this.images.length - 1;
}
if (this.image >= this.images.length) {
this.image = 0;
}
window.Repaint();
}
return true;
}
return false;
}
panel.item_focus_change();
function on_colours_changed() {
panel.colours_changed();
window.Repaint();
}
function on_download_file_done(path, success, error_text) {
text.download_file_done(path, success, error_text);
}
function on_font_changed() {
panel.font_changed();
window.Repaint();
}
function on_http_request_done(task_id, success, response_text) {
thumbs.http_request_done(task_id, success, response_text);
}
function on_item_focus_change() {
if (panel.selection.value == 0 && fb.IsPlaying) return;
panel.item_focus_change();
}
function on_key_down(k) {
text.key_down(k);
thumbs.key_down(k);
}
function on_metadb_changed(handles, fromhook) {
if (fromhook) return;
text.metadb_changed();
thumbs.metadb_changed();
}
function on_mouse_lbtn_up(x, y) {
text.lbtn_up(x, y);
thumbs.lbtn_up(x, y);
}
function on_mouse_move(x, y) {
text.move(x, y);
thumbs.move(x, y);
}
function on_mouse_lbtn_dblclk(x, y) {
thumbs.lbtn_dblclk(x, y);
}
function on_mouse_rbtn_up(x, y) {
if (text.containsXY(x, y)) {
return panel.rbtn_up(x, y, text);
}
return panel.rbtn_up(x, y, thumbs);
}
function on_mouse_wheel(s) {
if (thumbs.wheel(s)) return;
text.wheel(s);
}
function on_paint(gr) {
panel.paint(gr);
thumbs.paint(gr);
text.paint(gr);
}
function on_playback_dynamic_info_track(type) {
if (type == 0) {
text.metadb_changed();
thumbs.metadb_changed();
}
}
function on_playback_new_track() {
panel.item_focus_change();
thumbs.playback_new_track();
}
function on_playback_stop(reason) {
if (reason != 2) {
panel.item_focus_change();
}
}
function on_playback_time() {
thumbs.playback_time();
}
function on_playlist_switch() {
on_item_focus_change();
}
function on_size() {
panel.size();
var half = panel.h / 2;
thumbs.x = margin;
thumbs.y = margin;
thumbs.w = panel.w - (margin * 2);
thumbs.h = half - (margin * 2);
text.x = margin;
text.y = half;
text.w = panel.w - margin;
text.h = half;
text.size();
}
I suppose I could add a toggle or maybe auto detect panel dimensions and use the best fit.
BTW, that mod above is not quite correct. The text touches the right hand side of the panel when it shouldn't.
Inside on_size...
text.w = panel.w - margin;
should be
text.w = panel.w - (margin * 2);
Thank you for the correction.
Perhaps a toggle would be better there.
That's amazing.
Many Thanks.
---
My head is full of country code.
I'm not doing a component release just now but here are some modded files if anyone wants to test the toggle now.
It also fixes automatic image downloads not working for streams. The original thumbs its based on is fine. It's just this new image/text mod that is borked.
Note that the toggle option is only available when right clicking the image (or where the image should be if none are present). Right clicking the text displays text only options.
Save thumbs.js inside the component folder/samples/js
Use the .txt file inside the panel.
@marc2k3
Thank you for your continued quick work.
(https://i.imgur.com/3Fn06n9.png)
In my case, Image:Text=6:4 is good.
Set the ratio of Image and Text as a percentage, Is it troublesome to be able to change it with Panel Properties?
@ erukeagliese
I use your Custom Track 3.0 script
With the jscript-panel 3.3.20 update the script crashes, probably because the samples albumart has been modified.
As soon as you update the script, if you can post it.
Thank you.
Cannot retrieve the 'text_objects' property of a null or undefined reference
File: ....foobar2000\profile\user-components\foo_jscript_panel3\samples\js\albumart.js
Line: 198, Col: 2
Inside that script, look for
var panel = new _panel();
Move it so it's the first line of code.
Inside that script, look for
var panel = new _panel();
Move it so it's the first line of code.
Thank you!
@ erukeagliese
I use your Custom Track 3.0 script
With the jscript-panel 3.3.20 update the script crashes, probably because the samples albumart has been modified.
As soon as you update the script, if you can post it.
Thank you.
Cannot retrieve the 'text_objects' property of a null or undefined reference
File: ....foobar2000\profile\user-components\foo_jscript_panel3\samples\js\albumart.js
Line: 198, Col: 2
I've updated the script with some minor improvement.
- Albumart cursor
- Volume knob toggle
Inside that script, look for
var panel = new _panel();
Move it so it's the first line of code.
Thank you!
@ erukeagliese
I use your Custom Track 3.0 script
With the jscript-panel 3.3.20 update the script crashes, probably because the samples albumart has been modified.
As soon as you update the script, if you can post it.
Thank you.
Cannot retrieve the 'text_objects' property of a null or undefined reference
File: ....foobar2000\profile\user-components\foo_jscript_panel3\samples\js\albumart.js
Line: 198, Col: 2
I've updated the script with some minor improvement.
- Albumart cursor
- Volume knob toggle
A thousand thanks
Great script.
I only changed two lines to have the Clear playlist function instead of Remove Playlist.
(https://i.postimg.cc/n9FgrDV0/Screenshot-2023-12-13-114414.png) (https://postimg.cc/n9FgrDV0)
Hello again, Marc. Is there any plan to add Gradient to DrawEllipse and FillEllipse?
I only see the FillGradientRectangle and FillGradientRectangleAdvanced methods that accept the str object.
Thanks
By the way, regarding the jscript-panel.github.io site, perhaps the built-in search can be better. It seems it's only search the whole word.
When I searched for "Gradient," it simply returned "No matching documents."
@marc2k3
I am always grateful for your help.
Can I add "Thumbs Image Options" to "Last.fm Bio + Image"?
Thumbs Image Option:
Crop (focus on centre)
Crop (focus on top)
Stretch
Centre
Thanks.
I'm deliberately suppressing those options for this script and I don't really want to change it. But you can edit the code at the end of line 48 inside the panel. Change
image.crop_top to one of...
image.crop
image.centre
image.stretch
> I'm deliberately suppressing those options for this script and I don't really want to change it
Yes, I understand.
> But you can edit the code at the end of line 48 inside the panel. Change image.crop_top to one of...
I'm sorry for saying it was impossible.
Changed to image.centre. feel well.
Thanks.
JScript Panel 3.3.20 (Custom Track 3.1 by eurekagliese)
JavaScript runtime error
Unable to get property 'colour' of undefined or null reference
File: <main>
Line: 1931, Col: 4
Get this error when I play an album cover with an single color, seems to be the only issue I've found
Can I set background color opacity in JSplaylist?
I want to peel off the mask of a beautiful girl in wallpaper.
But I'm ignorant. Could you please save the princess?
Thx!
Thanks for bio scripts!
(https://i.imgur.com/PfXMOIl.png)
Hello again, Marc. Is there any plan to add more features to the last.fm bio like fetch the artist's country flag, genre, and additional information like the layout on Wil-B's Biography.
I'm in the process of changing my mind on this. A preview...
I'm looking forward to it.
Here are some files for testing. Save the .js in the component folder\samples\js - the .txt goes in the panel. It's optional and can be turned off via the right click menu. The Twitter Color Emoji font is required for country flags.
@marc2k3
panel crashes.
samples\js\text.js
Last.fm Bio + Images
JScript Panel 3.3.20 (Last.fm Bio + Images by marc2003)
JavaScript 実行時エラー
'_firstElement' は定義されていません。
File: C:\Users\teamf\Documents\Online Soft 03\foobar2000\foobar2000 DUIK x64 (STANDARD)\foobar2000\profile\user-components-x64\foo_jscript_panel3\samples\js\text.js
Line: 233, Col: 6
@marc2k3
panel crashes.
samples\js\text.js
Last.fm Bio + Images
JScript Panel 3.3.20 (Last.fm Bio + Images by marc2003)
JavaScript 実行時エラー
'_firstElement' は定義されていません。
File: C:\Users\teamf\Documents\Online Soft 03\foobar2000\foobar2000 DUIK x64 (STANDARD)\foobar2000\profile\user-components-x64\foo_jscript_panel3\samples\js\text.js
Line: 233, Col: 6
replace "_firstElement" with "_.isElement" in text.js will fix it
I forgot this file (save in samples\js folder)
@seongbin
Many Thanks.
> replace "_firstElement" with "_.isElement" in text.js will fix it
_.isElement
Line: 233
Line: 264
Line: 265
(https://i.imgur.com/KCrsPAy.png)
@marc2k3
Could you arrange the three files in Reply #1233 ?
text.js, Last.fm Bio + Images.txt and common.js
Thanks.
Hello again, Marc. Is there any plan to add more features to the last.fm bio like fetch the artist's country flag, genre, and additional information like the layout on Wil-B's Biography.
I'm in the process of changing my mind on this. A preview...
Good to see it's coming. Thank you!
JScript Panel 3.3.20 (Custom Track 3.1 by eurekagliese)
JavaScript runtime error
Unable to get property 'colour' of undefined or null reference
File: <main>
Line: 1931, Col: 4
Get this error when I play an album cover with an single color, seems to be the only issue I've found
Thanks for the feedback, I'll look into it. For now, simply Reload the script whenever you play a song with a better album cover.
PS. Pardon me if the issue from my script is cluttering the thread.
@marc2k3
Flag display
text.js, common.js and Last.fm Bio + Images.txt
(https://i.imgur.com/Cz6zU1e.png)
Pretty sure that only happens with the original code bundled with the component. If you really apply the .txt I attached, it should be fine. :/
edit: I'm attaching a zip with updated samples. It must be extracted manually into the component samples folder. Do this while fb2k is closed and then you can choose updated samples from the menu in the config window.
Reply #1233 https://hydrogenaud.io/index.php/topic,110516.msg1036525.html#msg1036525
Reply #1230 https://hydrogenaud.io/index.php/topic,110516.msg1036520.html#msg1036520
text.js, common.js and Last.fm Bio + Images.txt.
I tried with these 3 files.
------
Reply #1238
samples
Last.fm Bio + Images.txt
Flag is not displayed.
Can I set background color opacity in JSplaylist?
I want to peel off the mask of a beautiful girl in wallpaper.
But I'm ignorant. Could you please save the princess?
Thx!
sorry,
×background color
○selected background color
It was a different sentence...
Flag is not displayed.
Well it probably comes from applying that garbage fix from seongbin. Yes it was my fault for not attaching a required file in the first place but when you have no idea what the code is inside that function, you can't make stuff up and expect it to work.
It might have prevented the script error but it broke the html parsing. The results are cached so you need to delete those bad files.
To fix:
Close fb2k.
Open Explorer and go to
profile folder\js_data. Search for files named
lastfm.artist.extra.json and delete them all.
edit: but your screenshot in #1237 showed the font name and correctly extracted flag data. This definitely was because the .txt inside the panel had not been updated. How can anyone make any sense of this drivel. :/
Creating a new Panel and loading Last.fm Bio + Images.txt.
Is there anyone who can successfully display the flag?
@marc2k3 Sorry, my bad carelessly handling it.
And I found that "Korea, Republic of" cannt be parsed as expected, cuz it has one more comma.
For test you can use "The Black Skirts" as artist name.
Creating a new Panel and loading Last.fm Bio + Images.txt.
Is there anyone who can successfully display the flag?
It's working fine here.
I just remove the sample folder from the configuration folder first and then replace it with the extracted files from latest sample.zip provided by Marc above.
(https://i.imgur.com/PlrWLSD.png)
Perhaps the only visible minor issue is the genre tags Case.
@eurekagliese
Thanks.
> I just remove the sample folder from the configuration folder first and then replace it with the extracted files from latest sample.zip provided by Marc above.
I have it configured that way
I don't think you're doing anything unnecessary.
The tag is %country%, right?
(https://i.imgur.com/Pepxuru.png)
Thanks.
@eurekagliese
Thanks.
> I just remove the sample folder from the configuration folder first and then replace it with the extracted files from latest sample.zip provided by Marc above.
I have it configured that way
I don't think you're doing anything unnecessary.
The tag is %country%, right?
(https://i.imgur.com/Pepxuru.png)
Thanks.
No, the latest Last.fm Bio + Images script by marc automatically retrieves the flags. It seems that it scrapes the artist profile from the last.fm site, therefore artists who don't have the "Born in" or "Founded in" won't have their nation flag displayed, unlike the Text Display script which depends on the country tag.
Perhaps, as workaround If the country flag is missing on Bio, loading the flag from tag like on Text Display can be might be used.
No, the latest Last.fm Bio + Images script by marc automatically retrieves the flags. It seems that it scrapes the artist profile from the last.fm site, therefore artists who don't have the "Born in" or "Founded in" won't have their nation flag displayed, unlike the Text Display script which depends on the country tag.
Perhaps, as workaround If the country flag is missing on Bio, loading the flag from tag like on Text Display can be might be used.
@eurekagliese
Yes, I finally understand.
The genres of artists I listen to are mostly Indie and minor.
Thank you very much, that was helpful.
@marc2k3 Sorry for polluting the thread just for me.
(https://i.imgur.com/UizNcRO.png)
I've added title format support for country flags in the bio script. Extract the attached zip to the ROOT of the component folder. You should overwrite all files except the dll which is not bundled here.
The default is $country_flag(%country%) but if you need to edit it, hold Shift + Winkey>right click>Edit properties. Look for 2K3.TEXT.BIO.FLAG.TF.
Country tags always take precedence over what is found online.
Thanks for the update Marc, it's working nicely!
(https://i.imgur.com/A3gQgrX.png)
And I found that "Korea, Republic of" cannt be parsed as expected, cuz it has one more comma.
For test you can use "The Black Skirts" as artist name.
Yep the comma really messes things up. But even if it was extracted correctly it would still fail for not matching the contents of this file.
https://jscript-panel.github.io/files/countries.json
kr or
Republic Of South Korea are expected.
edit: this attached zip contains a one-off hack for
Korea, Republic of. It's ugly but should work.
Cached files need to be removed as per these instructions a few posts ago...
Open Explorer and go to profile folder\js_data. Search for files named lastfm.artist.extra.json and delete them all.
I apologize for the inconvenience caused by my problem.
Artist not displayed.
I think it's a problem with ().
(G)I-DLE
https://www.last.fm/music/(G)I-DLE?setlang=en
South Korea (kr)
(https://i.imgur.com/z75yFDK.png)
All of my panels have a text font size of 9, except your JScript Panel 3 Text Display. The minimal font size is 10. Please add 9.
Artist not displayed.
I think it's a problem with ().
A silly typo was the cause of this. Should be fixed in the attached zip.
Also, a bug where the panel didn't respond to country tags being modified has been fixed.
edit: this zip also contains updated track info + seekbar scripts. I finally got around to rounded rectangles which look a bit nicer
All of my panels have a text font size of 9, except your JScript Panel 3 Text Display. The minimal font size is 10.
That might be true for the default size set via the right click menu but you can use $font title formatting which supports 8 as the minimum value.
https://jscript-panel.github.io/docs/font-rgb/#font
Great!
I'm enjoying JScript Panel 3 now.
(https://i.imgur.com/tUwtUQ9.png)
Thank you for listening to such an ignorant request as mine.
That might be true for the default size set via the right click menu but you can use $font title formatting which supports 8 as the minimum value.
https://jscript-panel.github.io/docs/font-rgb/#font
But I can only add $font to the Custom title, not to the text.
So you meant Text Reader and not Text Display? :/
Yes, was confused. :-[
@marc2k3
Now Playing 2 (Log) + "Text Reader"
Now Playing 2 (foo_nowplaying2)
https://github.com/foxx1337/foo_nowplaying2/releases
I am using "Now Playing 2 (Log)" + "Text Reader" to display Playback History.
Can I select a History Track and display the Playlist View Context menu?
Then I can use Add to playback queue, Send to playback queue, QSearch, Send to playlist, Run service etc...
(https://i.imgur.com/bqRRbkD.png)
-----------
My request is to create a 64-bit version of Navigator.
Navigator (foo_navigator) 32bit
https://hydrogenaud.io/index.php/topic,45616.msg819089.html#msg819089
It was the wrong thread. sorry.
For some artist, intead of country flag, it displays 'KR'
(https://i.imgur.com/Q7yJPy3.png)
At first glance, it seems like a bug with the IDWriteTextLayout windows API I'm using. I'm supposed to be able throw different fonts at different ranges of text in the same string but it seems to break down with those korean characters in it.
I can hack around it by making separate calls for rendering the flag and the artist but then I'm in no better position that I would have been using images. Urgh. :/
Can I select a History Track and display the Playlist View Context menu?
Of course not. Artists/titles as strings can't be converted in to recognisable playlist items.
Use Playback Statistics with a recently played autoplaylist. Not tested because I don't have the component installed but something like...
%last_played% DURING LAST 1 DAY SORT DESCENDING BY %last_played%
I can hack around it by making separate calls for rendering the flag and the artist but then I'm in no better position that I would have been using images. Urgh. :/
Here's a quick and dirty workaround. On line 24 of original script. replace
var y = thumbs.properties.layout.value == 0 ? margin : this.y - margin;
DrawStyledText(gr, this.header_text(), panel.fonts.title, colourh, this.x, y, this.w, TM, DWRITE_TEXT_ALIGNMENT_LEADING, DWRITE_PARAGRAPH_ALIGNMENT_CENTER, DWRITE_WORD_WRAPPING_NO_WRAP, DWRITE_TRIMMING_GRANULARITY_CHARACTER);
with
var x = this.x;
var y = thumbs.properties.layout.value == 0 ? margin : this.y - margin;
if (this.twitter_font && this.flag.length) {
var font_size = _scale(panel.fonts.size.value);
var font = CreateFontString('Twitter Color Emoji', font_size);
var width = utils.CalcTextWidth(this.flag + ' ', 'Twitter Color Emoji', font_size);
gr.WriteText(this.flag, font, 0, x, y, width, TM, DWRITE_TEXT_ALIGNMENT_LEADING, DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
x += width
}
gr.WriteText(this.artist, panel.fonts.title, colourh, x, y, this.w, TM, DWRITE_TEXT_ALIGNMENT_LEADING, DWRITE_PARAGRAPH_ALIGNMENT_CENTER, DWRITE_WORD_WRAPPING_NO_WRAP, DWRITE_TRIMMING_GRANULARITY_CHARACTER);
var x = this.x;
var y = thumbs.properties.layout.value == 0 ? margin : this.y - margin;
if (this.twitter_font && this.flag.length) {
var font_size = _scale(panel.fonts.size.value);
var font = CreateFontString('Twitter Color Emoji', font_size);
var width = utils.CalcTextWidth(this.flag + ' ', 'Twitter Color Emoji', font_size);
gr.WriteText(this.flag, font, 0, x, y, width, TM, DWRITE_TEXT_ALIGNMENT_LEADING, DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
x += width
}
gr.WriteText(this.artist, panel.fonts.title, colourh, x, y, this.w, TM, DWRITE_TEXT_ALIGNMENT_LEADING, DWRITE_PARAGRAPH_ALIGNMENT_CENTER, DWRITE_WORD_WRAPPING_NO_WRAP, DWRITE_TRIMMING_GRANULARITY_CHARACTER);
I m totally fine with this one. Thanks for ur support!
I've posted an updated component and using a new font (Twemoji Mozilla) is required for the flag display in bio scripts. All existing users will need to update the content in their panels to be sure they're using the latest code.
https://github.com/mozilla/twemoji-colr/releases/tag/v0.7.0
I'm not going to pretend I understand how or why this fixes the Korean text/flag issue. It just does.
Thanks marc2k3 for the new component version! Works fine here:
1. Installed the Twemoji Mozilla font, restarted PC
2. Installed jscript panel 3.3.21
3. Updated both existing Thumbs and Last.fm Bio panels from the new samples
4. Restarted Foobar 2.1x64
Flags showing from radio streams when Last.FM entries support them. Have not needed to use the new "Last.fm Bio + Images" sample for my configuration.
I've said it recently and I'll say it again... there is no need to restart your PC after installing a font. That's bonkers.
If you install a font while fb2k is closed, do nothing. It will be fine when you open it.
If you install a font while fb2k is running, restart the app. That is all.
edit: while you don't "need" the combined bio + images script, it does look better without the splitter...
https://jscript-panel.github.io/gallery/lastfm-bio/#__tabbed_1_2
OK on the icons! Had just uninstalled the Twitter color emojis so was being overly cautious.
Yes the unified panel does look better. The one thing I miss is the ability to change the 4 image states from the right-click menu as before, but the manual method you posted for Air KEN works here and I appreciate it.
I've restored the right click options for the next release. It can be tested extracting the contents of the attached zip in to the ROOT of the component folder and updating the panel script from the Samples button.
Thank you!!
I am using the following script by marc2k3 to produce a line-limited text file log of recently played songs. Is there a way to modify it so that the most recent item appears first on the list instead of last? Thanks for any help!
// ==PREPROCESSOR==
// @name "Playback History"
// @author "marc2003"
// @import "%fb2k_component_path%samples\js\lodash.min.js"
// ==/PREPROCESSOR==
var limit = 70;
var tfo = fb.TitleFormat(" [%artist% - ]%title%");
var path = "C:\\foobar2000\\TrackHistory_v1.txt";
/////////////////////////////////////////////////////////////////////////////////////////////////////////
var last = '';
function on_playback_new_track() {
log_it();
}
function on_playback_dynamic_info_track(type) {
if (type == 0) {
log_it();
}
}
function now_as_string() {
var now = Math.floor(Date.now() / 1000);
return utils.TimestampToDateString(now);
}
function log_it() {
var current = tfo.Eval();
if (current != last) {
last = current;
var text = utils.ReadUTF8(path);
var arr = _(text.trim().split("\r\n"))
.filter(function (item) { return item.length > 0; })
.takeRight(limit - 1)
.value();
arr.push(now_as_string() + " " + current);
utils.WriteTextFile(path, arr.join("\r\n"));
}
}
Replace the log_it function with this...
function log_it() {
var current = tfo.Eval();
if (current != last) {
last = current;
var text = utils.ReadUTF8(path);
var arr = _(text.trim().split("\r\n"))
.filter(function (item) { return item.length > 0; })
.take(limit - 1)
.value();
arr.unshift(now_as_string() + " " + current);
utils.WriteTextFile(path, arr.join("\r\n"));
}
}
It does nothing for existing items. You should start with a new file.
Beautiful, thank you yet again.
Foobar 2.1 x64 and 1.6.17. Since updating to JScript Panel 3.3.25, and updating from Samples the Last.fm Bio + Images panel: I've noticed that when no image is available, the bold text for the band name shows the highlight color of my Foobar theme setting, but when a band image is loaded, the color of the band name text returns to white. I'm not sure if this script version is when it started, but is it default behavior (now)? See image examples.
That was on purpose since the first version of the combined text+images script. If you want white all the time for consistency, try this:
edit: I use white because when there's an image, I blur it and then a semi-transparent dark overlay is drawn over the top. Using UI colours would be unpredictable and might not always be readable.
edit2: the first attachment wasn't quite right. This updated one should be OK.
edit3: the next version will have support for displaying the stub image from the main album art preferences>Artist. I should have thought of that before.
Thanks for explaining, I just hadn't used that sample long enough obviously. I do like the background overlay and see why plain white is the best choice there. Cool on adding the stub image choice to load when no last.fm image exists!
Here's a test version with support for display the album art>artist stub image from the main preferences when no last.fm images are found.
The attachment need to be extracted to the root of the component folder. This for the combined last.fm bio+images script and the original Thumbs in last.fm mode only.
edit: original attachment removed. See below.
Here's a new attachment with a bug fix for certain artist images not being found. Urgh. :/
Like the instructions above, this needs to be extracted to the root of the component folder.
Original thumbs users also need to replace the code in their panels. No changes needed for last.fm bio+images users.
I think tab stacks are unrelated to JSP 3, but rather a basic UI element from foobar or a Windows element.
Marc did mention replacing the tabs with a single panel but only for JSP panels on this post, but it was too advance for me.
If each tab contained a single JScript Panel it would be easy enough. You could replace the tabs with a single panel and add this code...
// ==PREPROCESSOR==
// @author "marc2003"
// @name "Panel Receiver"
// ==/PREPROCESSOR==
var script = window.GetProperty('2K3.SCRIPT', 'user-components-x64\\foo_jscript_panel3\\samples\\JS Playlist.txt');
var pre = '';
var text = utils.ReadUTF8(fb.ProfilePath + script);
var lines = text.split('\r\n');
if (lines[0].indexOf('// ==PREPROCESSOR==') == 0) {
for (var i = 0; i < lines.length; i++) {
if (lines[i].indexOf('// @import') == 0) {
var fq = lines[i].indexOf('"') + 1;
var lq = lines[i].lastIndexOf('"') - fq;
var file = lines[i].substr(fq, lq).replace('%fb2k_profile_path%', fb.ProfilePath).replace('%fb2k_component_path%', fb.ComponentPath);
pre += utils.ReadUTF8(file) + '\n';
} else if (lines[i].indexOf('// ==/PREPROCESSOR==') == 0) {
break;
}
}
}
eval(pre + text);
(function (global) {
var original_callback = global.on_notify_data;
global.on_notify_data = function (name, info) {
if (name == 'load_script') {
window.SetProperty('2K3.SCRIPT', info);
window.Reload();
} else if (original_callback) {
original_callback(name, info);
}
}
})(this);
Now you need a secondary panel which contains a button/menu that would send notifications to this panel whenever it was clicked. You should just need to supply the full script path something like this...
// must be relative to fb.ProfilePath - do not make it absolute
window.NotifyOthers('load_script', 'user-components-x64\\foo_jscript_panel3\\samples\\smooth browser.txt');
edit: of course any current "state" would be lost each time new content is loaded.
This piece of code really helps!
(https://i.imgur.com/eJnAGSy.png)
i made a combine panel in jscript panel 3 of the bio and the thumbs from Marc2K3 of course.
(https://i.imgur.com/2vAaNDL.jpg)
the problem is like this : on right click on the text , you are suppose to have the panel menu of the text ( size and others )
but i have the panel of " reload "
after i click reload then the panel of the text appear on right click
How do i fix that ? . thanks a lot
Hi :) @Jul2323
Thanks for your script.
But...
JScript Panel 3.3.27 (Thumbs by marc2003)
JavaScript 実行時エラー
型が一致しません。
File: <main>
Line: 167, Col: 9
Type does not match.
Is it not enough to just panelize JSP3 and load "Bio_Thumbs.txt"?
Yes u can . If u can fix also what I write in the previous message .... Very annoying. Thanks ... AirKen
@Jul2323
JScript Panel 3 Properties > Export > *.wsp file
Could you please upload it?
Tomorrow I am at home ... I will send you
Hello,
@marc2k3 I have a small issue when using the on_playback_dynamic_info_track function in conjunction with External Tags or m-TAGS. This issue seems to be reciprocated between both of them and I feel like it might be with the way foobar2k is handling tag editing with streams.
Basically in short, when I click on the m-TAG containing a radio station or if there's any stream metadata update. I request an image to download from the Radio station's API page which also has other related data in the JSON field (for reference: https://gensokyoradio.net/api/station/playing/) issue is when I'm trying to populate these JSON fields using UpdateFileInfoFromJSON function to my m-TAGS file or External Tag file (which supports writing to APE tags/SQLite database) my foobar enters a state of write loop where it briefly pauses the stream, writes then plays then abruptly pauses the stream then write the same value again and so forth...
Any idea if there's a way to circumvent this? I can only think of writing it to another file that way it doesn't causes the write loop but not sure how m-TAGS or External Tag would possibly read from another file apart from the one it's using to play.
I'm using fb2k SDK methods for writing tags and I do not believe I can do anything differently. It's robust for local files and I have no interest in how it behaves with intermediary components like m-tags or whatever.
I would like to ask if it is possible to change the default font "FontAwesome"? What should I do, thanks a lot.
It's a requirement for the included samples. If you don't want to use them, write your own.
How to combine $directory_path(%path%)\Cover with $directory_path(%path%)\..\Cover commands in Custom Folder setting of Thumbs Sample?? Please forgive me for this stupid question, i have no knowledge of scripting whatsoever. Thank's in advance for your kindly help.
The dialog explains all :/
I will improve the custom folder dialog on the next release. It's still ridiculously easy to follow the current instruction of separating multiple folders with the pipe character | but it can be improved with a multi-line edit box where each folder goes on a new line. That will probably come tomorrow.
Thanks for your reply Marc2k3, i'm really not meticulous for something is already obvious in the dialog Panel :-* O:) Forgive me if it's bothering you.
If you have time please add custom path also for all music review panel, i save cache files of album review in my Eksternal HDD. Thank you for your very useful Jscript3 component, make my life is easier :D
To move the cache, you can add this as the first line of code in your allmusic panel...
folders.artists = "Z:\\path\\to\\artists\\";
Ok, thanks for the information. Let's see if i can make it ;D
Ok, thanks for the information. Let's see if i can make it ;D
FYI, this is my Eksternal HDD directories path, H:\Audio\%ARTIST%\#Artist Bio\Allmusic, so i just put folders.artists = H:\Audio\%ARTIST%\#Artist Bio\Allmusic; at the Code first line ?? Is this correct?
No, you cannot use title formatting there. It must be an absolute path to a base "artists" folder. Per artist folders will be generated inside based on the %album artist%*. The script will automatically handle characters that are illegal in windows folder/filenames like "\/*|:<>?. While possible in title formatting it would be tedious and it's why a utils.ReplaceIllegalChars method exists in the component.
https://jscript-panel.github.io/docs/namespaces/utils/#utilsreplaceillegalcharsstr-modern
* that's specific to allmusic review, other scripts like last.fm bio, similar artists, musicbrainz, thumbs all use $meta(artist,0).
edit: i know scripts like WilB's SMP bio offer more advanced customisation of how to configure folder structure but I'm not goinng down that route. If you don't like how this behaves, don't use it or modify it yourself.
Oh, It’s unfortunate, i've made it with Text Reader and Thumbs panel to access my Artists cache files so i don't have to download it again everytime i play the tracks. :-\ Thanks for your help and response anyway.
With the allmusic script, files are only downloaded once. If a cached file is detected, it will display it and will never lookup that artist/album again.
BTW, the most common file size is 2KB with the max in my collection being 6KB. For 1000 albums, that could be 6MB (more likely 2-3MB) and for 10000 albums 20-30MB. I really don't see the point in trying to customise the location.
Other scripts like last.fm bio, musicbrainz etc are different because online content can change so new lookups are performed if the cached data is over 24 hours old.
@eurekagliese I think there are some changes to be made to Custom Track 3.1 after updating to JSP 3.3.30.
Currently rolling back JSP 3 to the previous version.
^That might be a component bug I need to fix. There have been internal changes to how Repaint / RepaintRect work and everything seemed fine in my own testing and no one reported issues while the component was in beta for a few days. I can't do anything today but might have a fix tomorrow.
Thanks for the update and the quick info.
Fixed version posted just now.
Thanks for the quick update. That repaint issue seems working fine now.
Thanks for the quick update. That repaint issue seems working fine now.
JSP 3.3.31 fixes, ok Custom Track.
Reverting to JSP 3.3.29, due to audio stream execution issues, stops and freezes.
Edit: Maybe I have a problem with a disk.
It's unlikely changed in the latest version would cause this. Since JSP3 doesn't touch audio it could only prevent fb2k from playing normally by gobbling up all the resources it can and that would be noticeable in windows task manager.
Is it possible to create a search field in jscript panel 3 ? Like the picture link ? Global search . Artist song album ...
https://imgur.com/sJKP8Ex
Thanks you
Possible but not easy. I've never done it and I use utils.InputBox / utils.TextBox popup dialogs instead.
Smooth Browser has a search filter in the top left corner for filtering library items. Also, JSPlaylist has inline edit boxes for customising column title formatting, group headers etc. They will be using the inputbox.js files in their respective folders. I will not be helping with this.
Possible but not easy. I've never done it and I use utils.InputBox / utils.TextBox popup dialogs instead.
Smooth Browser has a search filter in the top left corner for filtering library items. Also, JSPlaylist has inline edit boxes for customising column title formatting, group headers etc. They will be using the inputbox.js files in their respective folders. I will not be helping with this.
Thanks you anyway for your support . I appreciate...👍👍👍
Is it possible to display the %date% field in Smooth Browser?
Is it possible to create a search field in jscript panel 3 ? Like the picture link ? Global search . Artist song album ...
https://imgur.com/sJKP8Ex
Thanks you
I have a mod version of SMOOTH PLAYLIST.
https://github.com/seongbin/Vibe2
Is it possible to create a search field in jscript panel 3 ? Like the picture link ? Global search . Artist song album ...
https://imgur.com/sJKP8Ex
Thanks you
I have a mod version of SMOOTH PLAYLIST.
https://github.com/seongbin/Vibe2
It looks very nice. How do I add a new panel to this?
3.3.35
https://github.com/jscript-panel/release/releases
https://jscript-panel.github.io/docs/changes/
This adds utils.RemoveFolderRecursive and $jsp3_since - a title formatting function for showing the difference between a given date string and now. Can be used playback statistics, last.fm last played dates etc.
edit: attached is an example using $jsp3_since(%lfm_last_played%) from Last.fm Playcount Sync
Woah, thank you very much the newly added function.
Question, where can I change the value? I'd like to change it to something like
0d > Today
1d > Yesterday
3d > 3d ago
7d > Last week
2wk > 2 weeks ago
4wk> Last month
52wk> Last year
104wk > 2 years ago
You can't. It's done in C++.
I was lazy using a built in SDK method which only returns weeks / days. Strictly speaking it also included hours/mins/seconds but I stripped that way.
I've now updated it so weeks/days are omitted for anything over one year like this new screenshot. I'm not breaking it down like your request though. You can do it in pure JS if you like.
Thanks, no wonder I couldn't find it.
Anyway, it appears there is a problem. The last played status will disappear when the music is played for 2/3 or registered/scrobbled, and also the last update seems showing an odd number but will also disappear upon restarting fb2k.
$jsp3_since(%lfm_last_played%)
(https://i.imgur.com/xppouQA.jpeg)
and this one with $jsp3_since(%last_played%)
(https://i.imgur.com/t8EPzXG.jpeg)
Oops, quite an obvious bug not handling anything less than one day with 0d like the previous version did.
Can you post the actual input for the borked years? I have no idea what's going on there.
Never mind, I see it. Fixed version coming soon.
Thanks for the quick reply
(https://i.imgur.com/avU2c68.jpeg)
Stopped at 3.3.29
From later versions, in my configuration, I have graphical slowdowns and micro freezes with the spin discs modules running radio streams.
With 3.3.29 no problems in the graphics plugins, with albuart.js, with thumbs.js and no problems with the rotation of the spin disc.
With the same configurations.
edit: pulled both recent releases. I'm utterly stupid. New fix coming soon. /sigh
edit2: here we go again...
3.3.37
https://github.com/jscript-panel/release/releases
Thank you, the updated version works well!
Stopped at 3.3.29
From later versions, in my configuration, I have graphical slowdowns and micro freezes with the spin discs modules running radio streams.
With 3.3.29 no problems in the graphics plugins, with albuart.js, with thumbs.js and no problems with the rotation of the spin disc.
With the same configurations.
With 3.3.37 there are no graphic slowdowns and spin disc rotation is also ok.
The problem of updating the albumart.js sample remains as per the video I posted previously.
Problem not present with version 3.3.29
Still can't reproduce. I tried copying your layout with a tab stack and spinning album art nonsense which I hate. I have no idea how anyone can use it for more than 10 seconds before getting sick of it.
FWIW, my pc is pushing 10 years old now. Not exactly cutting edge.
Sorry for the huge file. :/
Still can't reproduce. I tried copying your layout with a tab stack and spinning album art nonsense which I hate. I have no idea how anyone can use it for more than 10 seconds before getting sick of it.
FWIW, my pc is pushing 10 years old now. Not exactly cutting edge.
Sorry for the huge file. :/
De gustibus non est disputandum.
The spin disc has nothing to do with all this.
Just create two tabs in sequence and load the Album Art sample to replicate the problem that doesn't exist on 3.3.29 while it does on 3.3.37.
https://www.youtube.com/watch?v=H_ZkRSuJ_Bk
I can confirm
@ApacheReal report.
I'm not sure when it happened, but it was minor at first, but has recently gotten more noticeable.
I assumed it was just a file seeking issue, but I think my drive (ssd nvme) is capable of loading those images. I also compressed the images fetched by the latest fm Bio script, which typically result in large file sizes; there is a significant reduction after compression, which I believe will assist load faster, but the problem persist.
Unfortunately, there is no log in the console or with the advanced logging option to identify the issue.
(https://i.imgur.com/zMrlnKZ.gif)
So the problem seems isolated to tab switching. Is that right?
Can you put bad code in each panel to make it throw a script error. Does it render the error message on every tab switch?
Just an empty panel with
blah();
would do.
It occurs three times within 26 seconds.
(https://i.imgur.com/lYzsIoN.gif)
Here's a test version to try...
https://github.com/jscript-panel/jscript-panel.github.io/raw/dev/docs/files/foo_jscript_panel3-3.3.39-dev.fb2k-component
Probably does nothing to fix it. ;D
The latest version fixes the issue.
Thanks again for such a great support!
The latest version fixes the issue.
Thanks again for such a great support!
The problem remains has not been resolved with the dev version.
@ApacheReal correct, it seems that the problem remains.
I apologise for the hasty report.
@ApacheReal correct, it seems that the problem remains.
I apologise for the hasty report.
N.P.
It has also become more accentuated in the sense that the problem occurs when switching between tabs and if the tab has two adjacent samples, the problem occurs in both samples.
3.3.39 temporarily reverts recent rendering changes.
https://github.com/jscript-panel/release/releases
But this is the last version with:
Edge styles for CUI panels
window.CreateThemeManager / IThemeManager interface
CUI toolbars
The latest version works fine now.
Thanks for the update!
I've been searching around for things that can replicate some of the default status bar functionality, because I want some of the information it displays in a place that isn't the bottom of the layout. As far as I can tell, this plugin is really the only thing out there that can possibly do it.
Ideally, I'd like a basic horizontal bar that displays text derived from a string using the official Title Formatting Syntax (https://wiki.hydrogenaud.io/index.php?title=Foobar2000:Title_Formatting_Reference).
If this isn't possible, I'd at least like something that replicates the default status bar's current playback time and (if available) track duration, which is normally provided by this syntax:
%playback_time%[ / %length%]
I looked at the samples, but either the simple stuff doesn't have the playback time (e.g. "Text Display"), or it's part of something much more advanced that I had difficulty trimming down without things breaking (e.g. "Track Info + Seekbar + Buttons").
Text Display is simple. It's just a menu and and an edit dialog like any "proper" component. You don't have to edit any script.
After adding to a layout, right click and "Customise text". Replace the existing title formatting with anything you like.
You'll also want to enable "per-second updates" as that is off by default. And check all the other menu options for turning off the art and text alignment/etc.
.
Oops. I figured you had to do literally everything through the provided JavaScript, I didn't realize there was a way to set options by right-clicking them and selecting Edit Properties.
Thank you.
Alright, I was figuring I could tuck the duration next to the playlist tabs or something (still playing around with the layout) and I notice that it word wraps when I shrink it even when there's still plenty of padding on the left and right sides:

(This is within the scratchbox, but it behaves the same after applied too.)
Now you need to edit the script. Right click the panel>Configure. Find this at the end...
function on_size() {
panel.size();
text.size();
}
Replace with...
function on_size() {
panel.size();
text.size();
text.x = 0;
text.w = panel.w;
if (text.text_layout) text.text_height = text.text_layout.CalcTextHeight(text.w);
}
Now you need to edit the script. Right click the panel>Configure. Find this at the end...
function on_size() {
panel.size();
text.size();
}
Replace with...
function on_size() {
panel.size();
text.size();
text.x = 0;
text.w = panel.w;
if (text.text_layout) text.text_height = text.text_layout.CalcTextHeight(text.w);
}
Thanks, but it doesn't work quite right:
Static text touches the edge. Pause playback and see.
Yours is jumping around because the text width is constantly changing causing it to wrap because you're not giving it enough wiggle room.
Static text touches the edge. Pause playback and see.
Yours is jumping around because the text width is constantly changing causing it to wrap because you're not giving it enough wiggle room.
Well yeah, that's the issue, it seems like there would be plenty of wiggle room around the text, but it needs more than what you might expect from looking at it.
Here, look:
I see the cause now. It will take more effort to resolve it. I might have something later.
I see the cause now. It will take more effort to resolve it. I might have something later.
Awesome! I appreciate it.
I have a fix now but you have to follow a few steps. The next component will include it but I'm not sure when that will be.
1) Close fb2k.
2) Save this file...
https://raw.githubusercontent.com/jscript-panel/component/main/samples/js/text_display.js
inside your foobar2000 profile folder \ user-components (or user-components-x64) \ foo_jscript_panel3 \ samples \ js and overwrite the existing file.
3) open up fb2k and right click your panel>Configure and restore the original by clicking the samples button>Text Display
4) click OK to close the configuration window and hold the shift+win key together. Now right click the panel>Edit Properties. Set the value of
2K3.TEXT.MARGIN
to zero or other small number.
I have a fix now but you have to follow a few steps. The next component will include it but I'm not sure when that will be.
1) Close fb2k.
2) Save this file...
https://raw.githubusercontent.com/jscript-panel/component/main/samples/js/text_display.js
inside your foobar2000 profile folder \ user-components (or user-components-x64) \ foo_jscript_panel3 \ samples \ js and overwrite the existing file.
3) open up fb2k and right click your panel>Configure and restore the original by clicking the samples button>Text Display
4) click OK to close the configuration window and hold the shift+win key together. Now right click the panel>Edit Properties. Set the value of
2K3.TEXT.MARGIN
to zero or other small number.
That worked, thanks!
Hello again, Marc. Is there any plan to add Gradient to DrawEllipse and FillEllipse?
I only see the FillGradientRectangle and FillGradientRectangleAdvanced methods that accept the str object.
Thanks
By the way, regarding the jscript-panel.github.io site, perhaps the built-in search can be better. It seems it's only search the whole word.
When I searched for "Gradient," it simply returned "No matching documents."
I only just noticed this post from following a link to a post just above it. I think new FillEllipse methods with gradients should be easy enough.
As for docs search, I can't do anything about it. I know nothing about "the web" and I write bare markdown like this...
https://raw.githubusercontent.com/jscript-panel/jscript-panel.github.io/main/docs/docs/interfaces/IJSGraphics.md
And then I use the rather excellent Material for MkDocs package which turns it into lovely formatted html like this...
https://jscript-panel.github.io/docs/interfaces/IJSGraphics/
Any search limitations are part of that.
Thanks for the reply.
I was trying to recreate that gradient circle on play button but no luck as the gr.FillEllipse only accept single color. I think I even try masking but also no luck.
(https://i.imgur.com/i4BMYoY.jpeg)
Having thought about it, I'm probably going to nuke the existing gradient rectangle methods.
FillRectangle will then be updated to continue accepting a solid colour like it does currently but it will also accept a "gradient brush". I can then repeat that on all the Draw/Fill methods.
Here's an example:
Is it possible to create a search field in jscript panel 3 ? Like the picture link ? Global search . Artist song album ...
https://imgur.com/sJKP8Ex
Thanks you
I have a mod version of SMOOTH PLAYLIST.
https://github.com/seongbin/Vibe2
Hi there mate, is there any plan to make that search as stand alone panel script?
DUI and JSPlaylist are really missing out on this.
I've fixed it for JSP 3.4.3
Extract files to user profile. Put .txt in your panel.
Hi there mate, is there any plan to make that search as stand alone panel script?
DUI and JSPlaylist are really missing out on this.
I guess thats impossible. What I did is just restoring the feature from Br3tt's original script, thus it only applies to Smooth Playlist View. Best scenario is implmenting it to DUI by peter, maybe in the future.
I've fixed it for JSP 3.4.3
Extract files to user profile. Put .txt in your panel.
Thanks for this, I didn't realize we could redirect the import path of the script.
Hi there mate, is there any plan to make that search as stand alone panel script?
DUI and JSPlaylist are really missing out on this.
I guess thats impossible. What I did is just restoring the feature from Br3tt's original script, thus it only applies to Smooth Playlist View. Best scenario is implmenting it to DUI by peter, maybe in the future.
Sorry for the delay in replying and thanks for your response.
Here's a simplified Playback Buttons + Playback Order.
// ==PREPROCESSOR==
// @name "Playback Buttons + PBO"
// @author "marc2003"
// @import "%fb2k_component_path%helpers.txt"
// @import "%fb2k_component_path%samples\js\lodash.min.js"
// @import "%fb2k_component_path%samples\js\common.js"
// @import "%fb2k_component_path%samples\js\panel.js"
// ==/PREPROCESSOR==
// NOTE: This does not support Shuffle (albums) or Shuffle(folders)
var colours = {
buttons : RGB(255, 255, 255),
background : RGB(30, 30, 30),
contrast : RGB(196, 30, 35),
};
//////////////////////////////////////////////////////////////
var panel = new _panel();
var buttons = new _buttons();
var bs = _scale(24);
if (!chars.shuffle) chars.shuffle = '\ue8b1';
if (!chars.random) chars.random = '\ue897';
var pbo_chars = [chars.repeat_all, chars.repeat_all, chars.repeat_one, chars.random, chars.shuffle];
buttons.update = function () {
var x = ((panel.w - bs * 6) / 2);
var y = Math.round((panel.h - bs) / 2);
this.buttons.stop = new _button(x, y, bs, bs, { char : chars.stop, colour:fb.StopAfterCurrent ? colours.contrast : colours.buttons}, null, function () { fb.Stop(); }, 'Stop');
this.buttons.previous = new _button(x + bs, y, bs, bs, { char : chars.prev, colour:colours.buttons }, null, function () { fb.Prev(); }, 'Previous');
this.buttons.play = new _button(x + (bs * 2), y, bs, bs, { char : !fb.IsPlaying || fb.IsPaused ? chars.play : chars.pause, colour:colours.buttons}, null, function () { fb.PlayOrPause(); }, !fb.IsPlaying || fb.IsPaused ? 'Play' : 'Pause');
this.buttons.next = new _button(x + (bs * 3), y, bs, bs, { char : chars.next, colour:colours.buttons }, null, function () { fb.Next(); }, 'Next');
var pbo = plman.PlaybackOrder;
this.buttons.repeat = new _button(x + (bs * 5) - 2, y - 2, bs + 4, bs + 4, { char : pbo_chars[pbo], colour: pbo == 0 ? setAlpha(colours.buttons, 60) : colours.contrast }, null, function () { pbo >= pbo_chars.length - 1 ? plman.PlaybackOrder = 0 : plman.PlaybackOrder++ }, "Playback Order: " + plman.GetPlaybackOrders().toArray()[pbo]);
}
function on_mouse_lbtn_up(x, y) {
buttons.lbtn_up(x, y);
}
function on_mouse_leave() {
buttons.leave();
}
function on_mouse_move(x, y) {
buttons.move(x, y);
}
function on_mouse_rbtn_up(x, y) {
if (buttons.buttons.stop.containsXY(x, y)) {
fb.StopAfterCurrent = !fb.StopAfterCurrent;
} else {
var menu = window.CreatePopupMenu();
menu.AppendMenuItem(MF_STRING, 1, 'Configure');
var idx = menu.TrackPopupMenu(x, y);
menu.Dispose();
switch (idx ) {
case 1:
window.ShowConfigure();
break;
}
}
return true;
}
function on_paint(gr) {
gr.Clear(colours.background);
buttons.paint(gr);
}
function on_playback_order_changed() {
buttons.update();
window.Repaint();
}
function on_playback_pause() {
buttons.update();
window.Repaint();
}
function on_playback_starting() {
buttons.update();
window.Repaint();
}
function on_playback_stop() {
buttons.update();
window.Repaint();
}
function on_playlist_stop_after_current_changed() {
buttons.update();
window.Repaint();
}
function on_size() {
panel.size();
buttons.update();
}
It doesn't support shuffle (albums) or shuffle (folders). It cycles through the first 5 options. Edit the contrast colour if you don't like my default.
Right click the Stop button to toggle Stop After Current. All included button scripts support this.
Apparently adding playback buttons and seekbar to Text Display is enough for me :)
(https://i.imgur.com/qzGklJS.jpeg)
// ==PREPROCESSOR==
// @name "Text Display with Playback"
// @author "marc2003"
// @import "%fb2k_component_path%helpers.txt"
// @import "%fb2k_component_path%samples\js\lodash.min.js"
// @import "%fb2k_component_path%samples\js\common.js"
// @import "%fb2k_component_path%samples\js\panel.js"
// @import "%fb2k_component_path%samples\js\albumart.js"
// @import "%fb2k_component_path%samples\js\text_display.js"
// @import "%fb2k_component_path%samples\js\seekbar.js"
// ==/PREPROCESSOR==
// https://jscript-panel.github.io/gallery/text-display/
var panel = new _panel({ custom_background : true });
var albumart = new _albumart(0, 0, 0, 0);
var text = new _text_display(LM, 0, 0, 0);
panel.item_focus_change();
//////////////////////////////////////////////////////////////
var colours = {
buttons : RGB(255, 255, 255),
background : RGB(30, 30, 30),
title : RGB(255, 255, 255),
artist : RGB(240, 240, 240),
time : RGB(240, 240, 240),
seekbar_background : setAlpha(RGB(255, 255, 255), 50),
seekbar_progress : setAlpha(RGB(255, 255, 255), 150),
seekbar_knob : RGB(255, 255, 255),
sac : RGB(196, 30, 35),
};
var tfo = {
artist : fb.TitleFormat('%artist%'),
title : fb.TitleFormat('%title%'),
playback_time : fb.TitleFormat('[%playback_time%]'),
length : fb.TitleFormat('$if2(%length%,LIVE)'),
};
var seekbar = new _seekbar(0, 0, 0, 0);
var buttons = new _buttons();
var button_set_idx = 0;
var fluent_font = 'Segoe Fluent Icons';
var has_font = utils.CheckFont(fluent_font);
var img = null;
var bs = _scale(24);
var normal_font = CreateFontString('Segoe UI', 12);
var bold_font = CreateFontString('Segoe UI', 12, true);
if (has_font) {
button_set_idx = window.GetProperty('2K3.BUTTON.SET', 0);
}
buttons.update = function () {
var y = Math.round((panel.h - bs * 2));
var c = Math.round((panel.w - bs) / 2);
this.buttons.stop = new _button(c - (bs * 2), y, bs, bs, { char : chars.stop, colour:fb.StopAfterCurrent ? colours.sac : colours.buttons}, null, function () { fb.Stop(); }, 'Stop');
this.buttons.previous = new _button(c - (bs), y, bs, bs, { char : chars.prev, colour:colours.buttons }, null, function () { fb.Prev(); }, 'Previous');
this.buttons.play = new _button(c, y, bs, bs, { char : !fb.IsPlaying || fb.IsPaused ? chars.play : chars.pause, colour:colours.buttons}, null, function () { fb.PlayOrPause(); }, !fb.IsPlaying || fb.IsPaused ? 'Play' : 'Pause');
this.buttons.next = new _button(c + (bs), y, bs, bs, { char : chars.next, colour:colours.buttons }, null, function () { fb.Next(); }, 'Next');
this.buttons.queue = new _button(c + (bs * 2), y, bs, bs, { char : '\ue109', colour: colours.buttons}, null, function () {var handleList = plman.GetPlaylistSelectedItems(plman.ActivePlaylist); if (handleList && handleList.Count !== 0) { handleList.RunContextCommand("Add to playback queue");} }, 'Add to playback queue\nRight Click: Flush Queue');
this.buttons.preferences = new _button(c + (bs * 3), y, bs, bs, { char : chars.preferences, colour:colours.buttons}, null, function () { fb.ShowPreferences(); }, 'Preferences');
//this.buttons.console = new _button(panel.w - LM - (bs * 3), y, bs, bs, {char : chars.list, colour:colours.buttons }, null, function () { fb.ShowConsole(); }, 'Console');
//this.buttons.search = new _button(panel.w - LM - (bs * 2), y, bs, bs, { char : chars.search, colour:colours.buttons }, null, function () { fb.RunMainMenuCommand('Library/Search'); }, 'Library Search');
if (button_set_idx == 1) {
this.change_font(fluent_font);
}
}
function on_playback_starting() {
buttons.update();
window.Repaint();
}
function on_playlist_stop_after_current_changed() {
buttons.update();
window.Repaint();
}
function on_mouse_lbtn_down(x, y) {
seekbar.lbtn_down(x, y);
}
function on_playback_seek() {
seekbar.playback_seek();
}
function on_playback_edited() {
window.Repaint();
}
//////////////////////////////////////////////////////////////
function on_colours_changed() {
panel.colours_changed();
text.refresh(true);
}
function on_font_changed() {
panel.font_changed();
text.refresh(true);
}
function on_item_focus_change() {
if (panel.selection.value == 0 && fb.IsPlaying) return;
panel.item_focus_change();
}
function on_metadb_changed(handles, fromhook) {
if (!fromhook) {
albumart.metadb_changed();
}
text.metadb_changed();
}
function on_mouse_lbtn_up(x, y) {
text.lbtn_up(x, y);
if (buttons.lbtn_up(x, y)) {
return;
}
if (seekbar.lbtn_up(x, y)) {
return;
}
}
function on_mouse_move(x, y) {
text.move(x, y);
if (buttons.move(x, y)) {
return;
}
seekbar.move(x, y);
}
function on_mouse_rbtn_up(x, y) {
if (buttons.buttons.queue.containsXY(x, y)) {
fb.RunMainMenuCommand('Playback/Flush playback queue');
return true;
}
if (buttons.buttons.stop.containsXY(x, y)) {
fb.StopAfterCurrent = !fb.StopAfterCurrent;
} else {
panel.rbtn_up(x, y, text);
}
return true
}
function on_mouse_wheel(s) {
text.wheel(s);
if (seekbar.wheel(s)) {
return;
}
if (s == 1) {
fb.VolumeUp();
} else {
fb.VolumeDown();
}
}
function on_paint(gr) {
panel.paint(gr);
text.paint(gr);
buttons.paint(gr);
gr.FillRoundedRectangle(seekbar.x, seekbar.y, seekbar.w + _scale(6), seekbar.h, _scale(4), _scale(4), colours.seekbar_background);
if (fb.IsPlaying) {
var pos = seekbar.pos();
gr.WriteText(tfo.playback_time.Eval(), normal_font, colours.time, seekbar.x - _scale(72), panel.h /2 - bs * 0.6, _scale(60), panel.h, DWRITE_TEXT_ALIGNMENT_TRAILING, DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
gr.WriteText(tfo.length.Eval(), normal_font, colours.time, seekbar.x + seekbar.w + _scale(20), panel.h /2 - bs * 0.6, _scale(60), panel.h, DWRITE_TEXT_ALIGNMENT_LEADING, DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
if (fb.PlaybackLength > 0) {
//progress
gr.FillRoundedRectangle(seekbar.x, seekbar.y, pos, seekbar.h, _scale(4), _scale(4), colours.seekbar_progress);
//knob
gr.FillEllipse(seekbar.x + _scale(3) + seekbar.pos(), seekbar.y + _scale(3), _scale(6), _scale(6), colours.seekbar_knob);
}
}
}
function on_playback_dynamic_info_track(type) {
if (type == 0) text.metadb_changed();
else if (type == 1 && (text.properties.albumart.enabled || text.properties.layout.value > 0)) albumart.metadb_changed();
}
function on_playback_new_track() {
panel.item_focus_change();
}
function on_playback_pause() {
text.refresh();
buttons.update();
window.Repaint();
}
function on_playback_stop(reason) {
if (reason != 2) {
panel.item_focus_change();
}
buttons.update();
window.Repaint();
}
function on_playback_time() {
text.playback_time();
window.RepaintRect(panel.h, 0, seekbar.x - panel.h, panel.h);
}
function on_playlist_items_added() {
text.refresh();
}
function on_playlist_items_removed() {
text.refresh();
}
function on_playlist_items_reordered() {
text.refresh();
}
function on_playlist_switch() {
on_item_focus_change();
}
function on_mouse_lbtn_dblclk(x, y) {
// window.ShowConfigure();
fb.RunMainMenuCommand('View/Show now playing in playlist');
}
function on_size() {
panel.size();
text.size();
seekbar.x = _scale(96);
seekbar.w = panel.w - seekbar.x * 2;
seekbar.h = _scale(6);
seekbar.y = (panel.h - bs * 0.7);
buttons.update();
}
Text overlaps the buttons. I assume you've been super lazy and added a whole bunch of $crlf() instead of editing the javascript. :P
$crlf() 4 times, much easier.
As long as it works hehe.
So I stole the idea but not your code. The latest JSP3 released just now has it.
Thank you for the update, and I'm glad I could contribute an idea.
Hi guys . Did Jscript panel 3 can make a drop down menu ? The one with an arrow and multiple choose ? Or something similar ? Thanks ....
If you're talking about the Playlist: Metal in that screenshot above then no. That's a default UI toolbar. :/
Fully custom menus from mouse clicks are possible. Many included samples implement them.
If you're talking about the Playlist: Metal in that screenshot above then no. That's a default UI toolbar. :/
Fully custom menus from mouse clicks are possible. Many included samples implement them.
Thanks marc2k3 for your answer....
Hi marc,
is there a simple solution to add additional text into the menu like
new _button(0, 0, 36, 36, { char : chars.edit + 'CUE', colour : colours.buttons } ..
This has not been working since changing the font to Segoe Fluent Icons ..
many thanks for your help :)
Not tested but I think if you want to revert to FontAwesome, you need to:
1) Copy this in your panel...
var fa_chars = {
up : '\uF077',
down : '\uF078',
left : '\uF060',
right : '\uF061',
close : '\uF00D',
rating_on : '\uF005',
rating_off : '\uF006',
heart_on : '\uF004',
heart_off : '\uF08A',
prev : '\uF049',
next : '\uF050',
play : '\uF04B',
pause : '\uF04C',
stop : '\uF04D',
preferences : '\uF013',
search : '\uF002',
console : '\uF120',
info : '\uF05A',
audioscrobbler : '\uF202',
minus : '\uF068',
music : '\uF001',
menu : '\uF0C9',
hourglass : '\uF254',
lock : '\uF023',
list : '\uF0C9',
volume : '\uF028',
};
2) Update each button definition with fa_chars.BLAH
3) After defining your buttons inside buttons.update...
this.change_font("FontAwesome");
4) Check the button size. 36x36 doesn't seem big enough.
hi marc,
I've tested:
// ==PREPROCESSOR==
// @name "Menu Button"
// @author "marc2003"
// @import "%fb2k_component_path%helpers.txt"
// @import "%fb2k_component_path%samples\js\lodash.min.js"
// @import "%fb2k_component_path%samples\js\common.js"
// @import "%fb2k_component_path%samples\js\panel.js"
// ==/PREPROCESSOR==
var fa_chars = {
up : '\uF077',
down : '\uF078',
left : '\uF060',
right : '\uF061',
close : '\uF00D',
rating_on : '\uF005',
rating_off : '\uF006',
heart_on : '\uF004',
heart_off : '\uF08A',
prev : '\uF049',
next : '\uF050',
play : '\uF04B',
pause : '\uF04C',
stop : '\uF04D',
preferences : '\uF013',
search : '\uF002',
console : '\uF120',
info : '\uF05A',
audioscrobbler : '\uF202',
minus : '\uF068',
music : '\uF001',
menu : '\uF0C9',
hourglass : '\uF254',
lock : '\uF023',
list : '\uF0C9',
volume : '\uF028',
};
var colours = {
buttons : RGB(255, 255, 255),
background : RGB(196, 30, 35)
};
var panel = new _panel();
var buttons = new _buttons();
var bt=40;
buttons.update=function() {
this.buttons.buttons.menu = new _button(0, 0, bt, bt, { char : fa_chars.menu , colour : colours.buttons }, null, function () { _menu(0, 36); }, 'Menu');
this.buttons.buttons.console= new _button(bt, 0, bt, bt, { char : fa_chars.console + ' Test', colour : colours.buttons },null, function () { fb.ShowConsole(); }, 'Console Test');
this.change_font("FontAwesome");
}
function on_mouse_lbtn_up(x, y, mask) {
buttons.lbtn_up(x, y, mask);
}
function on_mouse_leave() {
buttons.leave();
}
function on_mouse_move(x, y) {
buttons.move(x, y);
}
function on_mouse_rbtn_up(x, y) {
if (buttons.buttons.menu.containsXY(x, y)) {
_help(0, 36);
return true;
}
return panel.rbtn_up(x, y);
}
function on_paint(gr) {
gr.Clear(colours.background);
buttons.paint(gr);
}
function on_size() {
panel.size();
}
Result: no button - any ideas - or am I wrong
this.buttons.buttons.BLAH is wrong. Should be this.buttons.BLAH
Also, you need to update the on_size function right at the bottom
function on_size() {
panel.size();
buttons.update();
}
And increase the width of any button with text like I said in the previous reply.
Thank you Marc,
you show the blind the way! ;)
When i switch Theme color , i need to stay in the same sort of Layout , but with a different color .
In ColumnUI / Layout , i need to check which layout is active or selected ? his name , i suppose ?
Example : switch Layout "Biography" to Layout "Biography_blue" . in jscript panel 3 of course . Hope it was clear.
If each layout has its own colour scheme, using on_colours_changed / window.GetColourCUI will pick it up. The default script inside the panel does that as do most of my own samples/JS Playlist/Smooth samples.
If each layout has its own colour scheme, using on_colours_changed / window.GetColourCUI will pick it up. The default script inside the panel does that as do most of my own samples/JS Playlist/Smooth samples.
I can make a color scheme for each layout . Ok
Can you explain how to use on_color_changed ?
Just add this line on the script ? Didn't use it ... Thanks
Even without seekbar and buttons the most useful of your samples to me :) Thank you Marc !
Hi Marc,
I ran into a little problem with your Text Display sample and I can't figure how to solve it.
I tried to put a drop shadow on the text in that I used gr.WriteTextLayout twice with a little offset to the right and down and colour black - that worked perfectly (Pic1) as long as I don't minimize the foobar window. When maximizing the window again, the drop shadow 'loses' the colour and the text is drawn twice in the foreground color (Pic2). I can't figure out how to catch this event to initiate a refresh or any other way to solve this. Maybe you got an idea - thanks.
I can't really tell what I'm supposed to be looking at in pic1?? :/
But I think I know the cause of the issue in pic2. The default code passes an array of colours (stringified) which the component then parses and applies to the text layout object. These colours are now permanent properties of that layout object until overwritten or the text layout is destroyed. Trying to call gr.WriteTextLayout with a solid colour isn't going to touch that layout object.
Maybe passing this as the colour will work instead...
var black = JSON.stringify([{
Colour: RGB(0, 0, 0),
Start: 0,
End: UINT_MAX
}]);
I can't really tell what I'm supposed to be looking at in pic1?? :/
Sorry, Pic1 was just there to show how it normally looks like.
Unfortunately, your suggested code didn't have any effect - thanks anyway, it's not a major problem, since I don't minimize the window that often anyway
Just realised there was a typo. Should be Length, not End.
var black = JSON.stringify([{
Colour: RGB(0, 0, 0),
Start: 0,
Length: UINT_MAX
}]);
It's doing what I expected it to....
Thanks, but that didn't solve the problem for me either - it only works when you put the focus on the Text Display panel before minimizing/maximizing the window. When the focus is on another panel, the colour is gone again :-\
But thanks to the explanations in your first answer, I managed to solve it by creating a second text layout for the shadow - so no need to dig into this anymore. Thanks a lot for your help!
So I've been messing around with a new menu bar script - mainly for CUI since you can't hide the menu in DUI.
This time I've not been so lazy and made a menu for customising the colours....
(https://i.imgur.com/ugiN5lW.png)
The buttons will always be black or white based on background colour.
It will be in the next component release but it can be tested now by pasting this in a panel...
https://raw.githubusercontent.com/jscript-panel/component/main/samples/Menu%20%2B%20Playback%20Buttons%20%2B%20Custom%20Colours.txt
Requires component version 3.4.7 or later (the release that ditched FontAwesome and uses Segoe Fluent Icons for all buttons)
Hey marc2k3 or anyone,
I've been modifying the 'Status Bar' sample to show both selection and playlist totals, and one thing I miss from the built-in status bars is the "Starting playback..." message, which appears in between the stopped and playing states. This is mostly only noticeable when playing a stream, since playback starts more or less immediately from local files.
I know there is
on_playback_starting callback (not in the original sample), and the
on_paint is using
if (fb.IsPlaying) {...} else {...}, but I seem to be missing how to get it to write text
only in between the two states when starting. I tried the inverse
if (!fb.IsPlaying) to see if that catches it which did not work either. Basically just trying to get the
var left_text_status to display "Starting..." when the track / stream is loading.
Look, I'm not competent at this stuff. :D
(No doubt something simple I'm missing - below is the mess I have so far but you may have to avert your eyes there, perhaps an update to the original sample to fix this small issue would clue me in? ;) )
Edit: Fixed code that saving a draft on the forum screwed up...// ==PREPROCESSOR==
// @name "Status Bar / Mod"
// @author "marc2003 / ghstchldrn"
// @import "%fb2k_component_path%helpers.txt"
// @import "%fb2k_component_path%samples\js\lodash.min.js"
// @import "%fb2k_component_path%samples\js\common.js"
// @import "%fb2k_component_path%samples\js\volume.js"
// ==/PREPROCESSOR==
var left_text_playing = fb.TitleFormat("$if(%ispaused%,Paused...,Playing $replace(%codec%,Musepack,MPC,Vorbis,OGG,Monkey$char(39)s Audio,APE,aac,AAC,opus,OPUS,Opus,OPUS)[ · %bitrate% kbps][ · %__bitspersample%-bit][ · %samplerate% Hz][ · $caps(%channels%)][ · %length%][ – Playing $if2($info(video_codec),$if($or(%fy_title%,$strstr($info(@),fy+)),$replace($trim($substr(%video_file_stats%,$strchr(%video_file_stats%,|),$if2($strstr(%video_file_stats%, | aac),99))),| ,, |,, , $char(183) ,vp,VP,h,H.,av,AV,fps, fps,kbps, kbps)))])");
var right_text_playing = fb.TitleFormat("$puts(path,$if2($info(@),%path%))$puts(s,$if($strstr($get(path),fy+),12,$if($strstr($get(path),https),9,$if($strcmp($left($get(path),3),www),0,8))))$puts(domain,$left($substr($get(path),$get(s),999),$sub($strchr($substr($get(path),$get(s),999),/),1)))$if($or($strstr($get(path),http),$strstr($get(path),www)),From $char(91)$get(domain)$char(93),From $left(%path%,3))[$if(%__hdcd%, · HDCD %__hdcd_gain% '('Peak: $caps(%__hdcd_peak_extend%)')',)][ · Album %replaygain_album_gain%][ · Track %replaygain_track_gain%]");
var left_text_stopped = '';
var right_text_stopped = '';
var left_text_status = 'Stopped. ';
var properties = {
sl_count : new _p('Show Selection Count', true),
sl_duration : new _p('Show Selection Duration', true),
sl_size : new _p('Show Selection Size', true),
pl_name : new _p('Show Playlist Name', true),
pl_count : new _p('Show Playlist Count', true),
pl_duration : new _p('Show Playlist Duration', true),
pl_size : new _p('Show Playlist Size', true),
background : new _p('Custom Colour Background', RGB(51, 51, 51)),
text : new _p('Custom Colour Text', RGB(240, 240, 240))
};
var ww = 0;
var wh = 0;
var font = CreateFontString('Segoe UI Symbol', 9);
get_selection();
get_playlist();
function get_selection() {
var tmp = [];
var sl_items = fb.GetSelection(0);
var sl_count = sl_items.Count;
if (properties.sl_count.enabled) {
tmp.push(sl_count == 0 ? 'None' : sl_count + (sl_count == 1 ? ' Track' : ' Tracks'));
}
if (properties.sl_duration.enabled) {
tmp.push(utils.FormatDuration(sl_items.CalcTotalDuration()));
}
if (properties.sl_size.enabled) {
tmp.push(utils.FormatFileSize(sl_items.CalcTotalSize()));
}
sl_items.Dispose();
left_text_stopped = (properties.sl_count.enabled || properties.sl_duration.enabled || properties.sl_size.enabled ? 'Selection: ' : '') + tmp.join(' · ');
window.Repaint();
}
function get_playlist() {
var tmp = [];
var ap = plman.ActivePlaylist;
if (ap >= 0 && ap < plman.PlaylistCount) {
var pl_items = plman.GetPlaylistItems(ap);
var pl_count = pl_items.Count;
if (properties.pl_count.enabled) {
tmp.push(pl_count + (pl_count == 1 ? ' Track' : ' Tracks'));
}
if (properties.pl_duration.enabled) {
tmp.push(utils.FormatDuration(pl_items.CalcTotalDuration()));
}
if (properties.pl_size.enabled) {
tmp.push(utils.FormatFileSize(pl_items.CalcTotalSize()));
}
if (properties.pl_name.enabled) {
var str = plman.IsPlaylistLocked(ap) ? '🔒 ' : '';
str += plman.GetPlaylistName(ap);
tmp.push(str);
}
pl_items.Dispose();
}
right_text_stopped = (properties.pl_count.enabled || properties.pl_duration.enabled || properties.pl_size.enabled || properties.pl_name.enabled ? 'Playlist: ' : '') + tmp.join(' · ');
window.Repaint();
}
function on_mouse_lbtn_dblclk() {
fb.RunMainMenuCommand('View/Show now playing in playlist');
}
function on_mouse_rbtn_up(x, y) {
var menu = window.CreatePopupMenu();
var sub = window.CreatePopupMenu();
var colour_menu = window.CreatePopupMenu();
var context = fb.CreateContextMenuManager();
if (fb.IsPlaying) {
context.InitNowPlaying();
context.BuildMenu(sub, 1);
sub.AppendTo(menu, MF_STRING, 'Now playing');
menu.AppendMenuSeparator();
}
menu.AppendMenuItem(MF_STRING, 9000, 'Show selection count');
menu.CheckMenuItem(9000, properties.sl_count.enabled);
menu.AppendMenuItem(MF_STRING, 9001, 'Show selection duration');
menu.CheckMenuItem(9001, properties.sl_duration.enabled);
menu.AppendMenuItem(MF_STRING, 9002, 'Show selection size');
menu.CheckMenuItem(9002, properties.sl_size.enabled);
menu.AppendMenuSeparator();
menu.AppendMenuItem(MF_STRING, 10000, 'Show playlist name');
menu.CheckMenuItem(10000, properties.pl_name.enabled);
menu.AppendMenuItem(MF_STRING, 10001, 'Show playlist count');
menu.CheckMenuItem(10001, properties.pl_count.enabled);
menu.AppendMenuItem(MF_STRING, 10002, 'Show playlist duration');
menu.CheckMenuItem(10002, properties.pl_duration.enabled);
menu.AppendMenuItem(MF_STRING, 10003, 'Show playlist size');
menu.CheckMenuItem(10003, properties.pl_size.enabled);
menu.AppendMenuSeparator();
colour_menu.AppendMenuItem(MF_STRING, 10004, 'Background...');
colour_menu.AppendMenuItem(MF_STRING, 10005, 'Text...');
colour_menu.AppendTo(menu, MF_STRING, 'Colours');
menu.AppendMenuSeparator();
menu.AppendMenuItem(MF_STRING, 10010, 'Configure...');
var idx = menu.TrackPopupMenu(x, y);
menu.Dispose();
switch (idx) {
case 0:
break;
case 9000:
properties.sl_count.toggle();
get_selection();
break;
case 9001:
properties.sl_duration.toggle();
get_selection();
break;
case 9002:
properties.sl_size.toggle();
get_selection();
break;
case 10000:
properties.pl_name.toggle();
get_playlist();
break;
case 10001:
properties.pl_count.toggle();
get_playlist();
break;
case 10002:
properties.pl_duration.toggle();
get_playlist();
break;
case 10003:
properties.pl_size.toggle();
get_playlist();
break;
case 10004:
properties.background.value = utils.ColourPicker(properties.background.value);
window.Repaint();
break;
case 10005:
properties.text.value = utils.ColourPicker(properties.text.value);
window.Repaint();
break;
case 10010:
window.ShowConfigure();
break;
default:
context.ExecuteByID(idx - 1);
break;
}
context.Dispose();
return true;
}
function on_mouse_wheel(s) {
if (s < 0) fb.VolumeDown();
else fb.VolumeUp();
}
function on_mouse_mbtn_up() {
fb.VolumeMute();
}
function on_volume_change() {
window.Repaint();
}
function on_paint(gr) {
gr.Clear(properties.background.value);
if (fb.IsPlaying) {
gr.WriteText(left_text_playing.Eval(), font, this.properties.text.value, 5, 0, ww - 200 - utils.CalcTextWidth(right_text_playing.Eval(), 'Segoe UI', 9), 21, DWRITE_TEXT_ALIGNMENT_LEADING, DWRITE_PARAGRAPH_ALIGNMENT_NEAR, DWRITE_WORD_WRAPPING_NO_WRAP, DWRITE_TRIMMING_GRANULARITY_CHARACTER);
}
else {
gr.WriteText(left_text_status + left_text_stopped, font, this.properties.text.value, 5, 0, ww - 200 - utils.CalcTextWidth(right_text_stopped, 'Segoe UI', 9), 21, DWRITE_TEXT_ALIGNMENT_LEADING, DWRITE_PARAGRAPH_ALIGNMENT_NEAR, DWRITE_WORD_WRAPPING_NO_WRAP, DWRITE_TRIMMING_GRANULARITY_CHARACTER);
}
if (fb.IsPlaying) {
gr.WriteText(right_text_playing.Eval(), font, this.properties.text.value, 0, 0, ww - 130, 21, DWRITE_TEXT_ALIGNMENT_TRAILING);
}
else if (plman.ActivePlaylist > -1 && plman.ActivePlaylist < plman.PlaylistCount) {
gr.WriteText(right_text_stopped, font, this.properties.text.value, 0, 0, ww - 130, 21, DWRITE_TEXT_ALIGNMENT_TRAILING);
}
gr.WriteText(fb.Volume.toFixed(2) < -60.00 ? 'Muted' : fb.Volume.toFixed(2) + ' dB', font, this.properties.text.value, 0, 0, ww - 5, 21, DWRITE_TEXT_ALIGNMENT_TRAILING);
}
function on_playback_new_track() {
window.Repaint();
}
function on_playback_starting() {
left_text_status = 'Starting... ';
window.Repaint();
}
function on_playback_stop() {
left_text_status = 'Stopped. ';
window.Repaint();
}
function on_playback_pause() {
window.Repaint();
}
function on_playback_time() {
window.Repaint();
}
function on_playlist_items_added(p) {
if (p == plman.ActivePlaylist) {
get_playlist();
}
}
function on_playlist_items_removed(p) {
if (p == plman.ActivePlaylist) {
get_playlist();
}
}
function on_playlist_switch() {
get_playlist();
}
function on_playlists_changed() {
if (properties.pl_name.enabled) {
get_playlist();
}
}
function on_selection_changed() {
if (properties.sl_count.enabled || properties.sl_duration.enabled || properties.sl_size.enabled) {
get_selection();
}
}
function on_size() {
ww = window.Width;
wh = window.Height;
}
So I've been messing around with a new menu bar script - mainly for CUI since you can't hide the menu in DUI.
This time I've not been so lazy and made a menu for customising the colours....
(https://i.imgur.com/ugiN5lW.png)
The buttons will always be black or white based on background colour.
It will be in the next component release but it can be tested now by pasting this in a panel...
https://raw.githubusercontent.com/jscript-panel/component/main/samples/Menu%20%2B%20Playback%20Buttons%20%2B%20Custom%20Colours.txt
Requires component version 3.4.7 or later (the release that ditched FontAwesome and uses Segoe Fluent Icons for all buttons)
Interesting. Would it be possible to have an alternative to Text Display with the menu and Playback buttons placed in this way ?
Updated status bar: https://raw.githubusercontent.com/jscript-panel/component/main/samples/Status%20Bar.txt
And nope, I'm not making any more changes to Text Display. Most of my scripts are flexible with regards to positioning/dimensions. This is not so easy and I can't be bothered.
How can I check if a certain pattern is in a string?
For instance:
var str = 'Speakers some more text [exclusive]'
How to check that the var str contains 'Speakers ' and/or contains ' [exclusive]'?
This Status Bar script has been updated: https://raw.githubusercontent.com/jscript-panel/component/main/samples/Status%20Bar.txt
You can now set title formatting via the right click menu and $rgb is supported.
Hi,
Is it possible to move the image (Cover Art) a little lower, by a few pixels?
Search this line in text_display.js
_drawImage(gr, albumart.img, albumart.x, albumart.y, albumart.w, albumart.h, image.centre);
add the number of pixels to albumart.y (e.g. + 5) and save the file, but remember, that with every update the file will get overwritten, so better save it somewhere else and replace the path in the config window with your new path (or change the file after every update, that's up to you)
Must be modded?? Margins are like this with the original script at 150%.
(https://i.imgur.com/4fOKjok.png)
No amount of panel resizing can get the image closer to the edges.
Yet another Status Bar update: https://raw.githubusercontent.com/jscript-panel/component/main/samples/Status%20Bar.txt
This fixes actual bugz. Ever since the first version, it didn't support the font size being changed so any manual change or DPI increase would have chopped it off. Sorry about that.
Now that it can take up the panel height, multi-line with wrapping is now possible. Use $crlf() in your title formatting.
^ I never would've figured that out myself. It'll take me some time to integrate the new changes, so I'll just assume it goes smoothly and say thanks now. Thanks :)
Search this line in text_display.js
_drawImage(gr, albumart.img, albumart.x, albumart.y, albumart.w, albumart.h, image.centre);
add the number of pixels to albumart.y (e.g. + 5) and save the file, but remember, that with every update the file will get overwritten, so better save it somewhere else and replace the path in the config window with your new path (or change the file after every update, that's up to you)
Thanks. I'll try It.
Nice one Marc2k3... I will try it too....
Hi,
I would like to use icons of the font 'Material Icons Round Regular'. How to do it ?
I tried, to use '\uE03D' with char_set[button_set_idx].playlist :
var button_set = {
preferences: '\uE8B8',
search: '\uE8B6',
console: '\uead3',
back: '\ue020',
forward: '\ue01f',
lyric: '\uec0b',
playlist: '\uE03D',
}
var button_set_idx = 0;
var material_font = 'Material Icons Round Regular'
var has_font = utils.CheckFont(material_font);
var char_set = [button_set, material_font];
if (has_font) {
button_set_idx = window.GetProperty('2K3.BUTTON.SET', 0);
}
But it does not work. :( :(
I would like to use icons of the font 'Material Icons Round Regular'. How to do it ?
I think, the font is just called 'Material Icons Round' without 'Regular', at least, that's what it's called here in my system
I would like to use icons of the font 'Material Icons Round Regular'. How to do it ?
I think, the font is just called 'Material Icons Round' without 'Regular', at least, that's what it's called here in my system
I tried, but It doesn't work.
I tried, but It doesn't work.
[/quote]
A little hard to tell you why without the corresponding code - you just defined some variables...
I tried, but It doesn't work.
A little hard to tell you why without the corresponding code - you just defined some variables...
[/quote]
var button_set_idx = 0;
var material_font = 'Material Icons'
var has_font = utils.CheckFont(material_font); // material_font
var button_set = {
preferences: '\uE8B8',
search: '\uE8B6',
console: '\uead3',
back: '\ue020',
forward: '\ue01f',
lyric: '\uec0b',
playlist: '\uE03D',
}
var char_set = [material_font, button_set]; // [chars, button_set];
if (has_font) {
button_set_idx = window.GetProperty('2K3.BUTTON.SET', 0);
var rg_plchars = button_set.playlist[button_set_idx]
}
Then I use rg_plchars to display the button :
bpos = btot - 4; this.buttons.plmanager = new _button(x + (bs * bpos), y, bs, bs, { char : rg_plchars, colour:colours.white}, null, function () { fb.RunMainMenuCommand('View/Playlist Manager'); }, 'PL Manager');
C'est ce que je veux afficher :
Supposing your standard font is Segoe Fluent Icons, why not just put this line into your code and forget about the rest:
this.buttons.plmanager = new _button(x + (bs * bpos), y, bs, bs, { char : '\ue90b', colour:colours.white}, null, function () { fb.RunMainMenuCommand('View/Playlist Manager'); }, 'PL Manager');
I tried, but It doesn't work.
A little hard to tell you why without the corresponding code - you just defined some variables...
var button_set_idx = 0;
var material_font = 'Material Icons'
var has_font = utils.CheckFont(material_font); // material_font
var button_set = {
preferences: '\uE8B8',
search: '\uE8B6',
console: '\uead3',
back: '\ue020',
forward: '\ue01f',
lyric: '\uec0b',
playlist: '\uE03D',
}
var char_set = [material_font, button_set]; // [chars, button_set];
if (has_font) {
button_set_idx = window.GetProperty('2K3.BUTTON.SET', 0);
var rg_plchars = button_set.playlist[button_set_idx]
}
Then I use rg_plchars to display the button :
bpos = btot - 4; this.buttons.plmanager = new _button(x + (bs * bpos), y, bs, bs, { char : rg_plchars, colour:colours.white}, null, function () { fb.RunMainMenuCommand('View/Playlist Manager'); }, 'PL Manager');
C'est ce que je veux afficher :

[/quote]
Like this?
RDIT: Try the attached script
That's the output of the code you provided - wouldn't look any different with Material Font
You will have to alter the size of the button by adjusting the second bs value:
this.buttons.plmanager = new _button(x + (bs * bpos), y, bs, bs + 5...
or whatever value suits your needs
homer backing in to a hedge.gif
Supposing your standard font is Segoe Fluent Icons, why not just put this line into your code and forget about the rest:
this.buttons.plmanager = new _button(x + (bs * bpos), y, bs, bs, { char : '\ue90b', colour:colours.white}, null, function () { fb.RunMainMenuCommand('View/Playlist Manager'); }, 'PL Manager');
Supposing your standard font is Segoe Fluent Icons, why not just put this line into your code and forget about the rest:
this.buttons.plmanager = new _button(x + (bs * bpos), y, bs, bs, { char : '\ue90b', colour:colours.white}, null, function () { fb.RunMainMenuCommand('View/Playlist Manager'); }, 'PL Manager');
Thanks for your help.
But if I want to use "Material Icons" for '\ue90b'. What should I write before ?
That's the output of the code you provided - wouldn't look any different with Material Font
You will have to alter the size of the button by adjusting the second bs value:
this.buttons.plmanager = new _button(x + (bs * bpos), y, bs, bs + 5...
or whatever value suits your needs
👍
I tried, but It doesn't work.
A little hard to tell you why without the corresponding code - you just defined some variables...
[attach type=image]29696[/attach]
Like this?
RDIT: Try the attached script
[/quote]
It works perfectly. Thanks. 👍👍
The _button_mir function allows, among other things, to assign the "Material Icons Round" font to the plmanager button. 👍
I tried, but It doesn't work.
A little hard to tell you why without the corresponding code - you just defined some variables...
[attach type=image]29696[/attach]
Like this?
RDIT: Try the attached script
It works perfectly. Thanks. 👍👍
The _button_mir function allows, among other things, to assign the "Material Icons Round" font to the plmanager button. 👍
[/quote]
Good!
Modifications were a bit sloppy so I've updated the script to make it more generic.
I dropped the '_button_mir' function and created a more generic function '_button_mod' that accepts an optional fontname (default Segoe Fluent Icons) and optional fontsize offset (defaults to 10). Basically you can any font for buttons you like.
All buttons use the same function now. And as a result the RG button is slightly larger and more in line with the other buttons.
I also implemented the last changes from the standard script so the seekbar aligns nicely.
Have a look ...
EDIT: Some last oops additions - Use script v7a
Modifications were a bit sloppy so I've updated the script to make it more generic.
I dropped the '_button_mir' function and created a more generic function '_button_mod' that accepts an optional fontname (default Segoe Fluent Icons) and optional fontsize offset (defaults to 10). Basically you can any font for buttons you like.
All buttons use the same function now. And as a result the RG button is slightly larger and more in line with the other buttons.
I also implemented the last changes from the standard script so the seekbar aligns nicely.
Have a look ...
EDIT: Some last oops additions - Use script v7a
Works perfectly. 👍👍 I've added somme buttons.
With _button_mod function, you can easily add what you want as char, in any font. 👍👍.Thanks a lot.

When there is no image display (this certainly concerns albumart.js), would it be possible to indicate this absence with an image, for example :
File>Preferences>Display>Album Art>Artist tab>Stub image.
edit: That was for the original album art script. Text display only supports Front so configure the stub image under that tab.
File>Preferences>Display>Album Art>Artist tab>Stub image.
edit: That was for the original album art script. Text display only supports Front so configure the stub image under that tab.
The following question is NOT about the modified Text Display + Album Art + Seekbar + Buttons.txt, but rather about the standard Album Art.txt where mousewheel is supported.
Since there is no way to enter a stub image for Icon can you please reconsider making a stub available for icon in your settings (something like 2K3.ARTREADER.ICON.STUB)?
NB. I was able to skip Icon on mousewheel altogether by adding one line to _albumart, but I rather have a decent solution since in rare cases there actually is an icon image added to the audiofile.
File>Preferences>Display>Album Art>Artist tab>Stub image.
edit: That was for the original album art script. Text display only supports Front so configure the stub image under that tab.
Is it possible to take into account the absence of certain images in albumart.js? (back.jpg, cd.jpg, artist.jpg, etc.)
@marc2k3 Following up from the External Tags post I decided to rework on the whole loading images from a radio station into memory
I've reached till this part
function on_download_image_done(url, image) {
if (!image) return;
// Do something here to update cover art
}
but I'm not sure how to call on_paint(gr) inside of on_download_image_done assuming that's the function responsible for updating the cover art? or how do I update the Album Art sample with a downloaded image?
@marck2k3
Related questions.
Album Art shows the Artist picture just fine playing a normal non streaming file probably using part this part of Preferences - Display - Artist:
C:\Users\User\AppData\Roaming\foobar2000-v2\yttm\art_img\$substr(%artist%,1,1)\%artist%\*.*
While streaming however the artist image is not retrieved/displayed, instead it displays the stub image.
When the artist changes in a stream the following code does update the cover and also changes the textdisplay just fine, but does not do the artist pic.
function on_metadb_changed(handles, fromhook) {
if (!fromhook) {
albumart.metadb_changed();
}
text.metadb_changed();
}
Can the script be changed so that it retrieves/displays the artist pic as well on realtime stream/artist change?
I like to display the streaming cover as well in my own code.
What is the realtime streaming tag that contains the url to the cover art? I can't find it in your Properties + Other Info.txt or in the standard Item properties which both only show the non-realtime tags?
@marc2k3 Following up from the External Tags post I decided to rework on the whole loading images from a radio station into memory
I've reached till this part
function on_download_image_done(url, image) {
if (!image) return;
// Do something here to update cover art
}
but I'm not sure how to call on_paint(gr) inside of on_download_image_done assuming that's the function responsible for updating the cover art? or how do I update the Album Art sample with a downloaded image?
Okay I guess this a bad approach, loading images in memory starts to break viewing the image using ShowAlbumArtViewer. Basically I need to manually patch up the image for my playlist and album panel and it would be much better to just download the image file and let m-TAGS/External Tags do the job of attaching the front cover art
If those components support attaching images via the normal properties dialog or tagging context menu, it should be transparent to 3rd party components using the same SDK methods. This can attach images but they have to be on disk so you'd have to save with utils.DownloadFileAsync first.
https://jscript-panel.github.io/docs/namespaces/utils/#utilsdownloadfileasyncwindow_id-url-path
https://jscript-panel.github.io/docs/interfaces/IMetadbHandleList/#attachimageimage_path-art_id
If those components support attaching images via the normal properties dialog or tagging context menu, it should be transparent to 3rd party components using the same SDK methods. This can attach images but they have to be on disk so you'd have to save with utils.DownloadFileAsync first.
https://jscript-panel.github.io/docs/namespaces/utils/#utilsdownloadfileasyncwindow_id-url-path
https://jscript-panel.github.io/docs/interfaces/IMetadbHandleList/#attachimageimage_path-art_id
That's currently how I was originally using but was under the assumption that downloading it in through the memory would be a much better approach until I tried it... so far utils.DownloadFileAsync does the job.
I suppose attaching from memory could be done but it wouldn't take in to account the original format. I would have to encode as jpg or maybe webp.
Hey,
I can not get the spectrum seekbar to work. I can seek and click on it but it does not show the spectrum of the song.
Can someone help me to get this to work? :)
I assume it has something to do with ffmpeg but I have no idea how to install this too.
Thanks for any help ♥
Yes you might say that. Check here for the whole deal:
https://jscript-panel.github.io/gallery/spectrogram-seekbar/ (https://jscript-panel.github.io/gallery/spectrogram-seekbar/)
Yes you might say that. Check here for the whole deal:
https://jscript-panel.github.io/gallery/spectrogram-seekbar/ (https://jscript-panel.github.io/gallery/spectrogram-seekbar/)
ah amazing, I did not see it when I was getting Jscrip. Gonna check it out :) Thanks! ♥
I did all I could. :/
Yes you might say that. Check here for the whole deal:
https://jscript-panel.github.io/gallery/spectrogram-seekbar/ (https://jscript-panel.github.io/gallery/spectrogram-seekbar/)
ah amazing, I did not see it when I was getting Jscrip. Gonna check it out :) Thanks! ♥
marc2k3's spectrogram doesn't need SoX, it goes right to ffmpeg. FAST. You can tell it to generate a lossless png for the image by adding an extension in the "FFmpeg showspectrumpic options" like in the screenshot. If you would prefer that the image cache be cleared automatically upon Foobar close, add these lines supplied by him to the very end of the "configure" script:
function on_script_unload() {
utils.ListFiles(spectrogram_cache).toArray().forEach(function (item) {
utils.RemovePath(item);
});
}
Changed the front cover in a FLAC file. However, the old cover is still displayed in the Smooth playlist. How do I get the playlist to re-read the title?
Thank you!
The solution is not very elegant. Close fb2k and browse your profile folder.
You can either delete the entire js_smooth_cache folder and this means all thumbnails will be generated again from scratch.
OR
Browse inside the folder and enable the extra large icons view in Explorer. Find and delete the offending files manually.
Hi,
I created some keyboard shortcuts 1) Randomize current selection 2) Queue (selected) files 3) Kill the queue. Works fine.
However I would this functionality in buttons.
The randomize button I created works fine with fb.RunMainMenuCommand('Edit/Selection/Sort/Randomize');
The queue button does not work. There is no main menu command to queue so I tried fb.RunContextCommand('Add to playback queue'); but this only adds a track within the selected tracks to the queue if it is playing.
How can I change this code so that all files in the selection are added to the queue?
Hi,
I created some keyboard shortcuts 1) Randomize current selection 2) Queue (selected) files 3) Kill the queue. Works fine.
However I would this functionality in buttons.
The randomize button I created works fine with fb.RunMainMenuCommand('Edit/Selection/Sort/Randomize');
The queue button does not work. There is no main menu command to queue so I tried fb.RunContextCommand('Add to playback queue'); but this only adds a track within the selected tracks to the queue if it is playing.
How can I change this code so that all files in the selection are added to the queue?
I just use this for my queue button.
this.buttons.queue = new _button(x + (bs * 5), y, bs, bs, { char : '\ue109', colour: colours.white}, null, function () {
var handleList = plman.GetPlaylistSelectedItems(plman.ActivePlaylist);
if (handleList && handleList.Count !== 0) {
handleList.RunContextCommand("Add to playback queue");
}
}, 'Add to playback queue');
I just use this for my queue button.
this.buttons.queue = new _button(x + (bs * 5), y, bs, bs, { char : '\ue109', colour: colours.white}, null, function () {
var handleList = plman.GetPlaylistSelectedItems(plman.ActivePlaylist);
if (handleList && handleList.Count !== 0) {
handleList.RunContextCommand("Add to playback queue");
}
}, 'Add to playback queue');
Thank you! Works very well.
I added rightmouse functionality for the button to remove queued items from selection but that is not really straightforward. If there is one item in the selection that is not queued the command will fail therefore I first had to add it to the queue before removing it.
if (buttons.buttons.queue.containsXY(x, y)) {
var handleList = plman.GetPlaylistSelectedItems(plman.ActivePlaylist);
if (handleList && handleList.Count !== 0) {
handleList.RunContextCommand("Add to playback queue");
handleList.RunContextCommand("Remove from playback queue");
}
return true;
}
In the end I want to add rightmouse functionality to the Randomize selection button, so that it starts playing the first track of the selection after randomizing that selection. I would prefer to set focus to the first element of the selection after randomizing that selection and start playing that element, but I don't know how to set the focus to the first element of the selection.
I tried plman.SetPlaylistFocusItem(plman.ActivePlaylist, 0) but that sets the focus to the first element of the whole playlist.
What variable should be used instead of the 0 to set focus to the first item of the selection?
Also I do not know how to issue a play command that starts playing the focused item. fb.Play() just starts playing the song that is already playing or where playback stopped last time.
So now I use a rather stupid workaround. First I make a handlelist for the whole playlist. Then I add all items to the queue and delete all items (to clear the queue. Is there a better way?). Then I create a handlelist for current selection and add all items to the queue. And finally I issue a fb.Next() command to start playing the first (queued) item), which is the first rack of the selection after it was randomized.
var handleList = plman.GetPlaylistItems(plman.ActivePlaylist)
if (handleList && handleList.Count !== 0) {
handleList.RunContextCommand("Add to playback queue");
handleList.RunContextCommand("Remove from playback queue");
}
fb.RunMainMenuCommand('Edit/Selection/Sort/Randomize');
var handleList = plman.GetPlaylistSelectedItems(plman.ActivePlaylist);
if (handleList && handleList.Count !== 0) {
handleList.RunContextCommand("Add to playback queue");
}
fb.Next();
It works and solves the ordering issue I encountered by creating functionality for on-the-fly "compilation" folders, but I wonder if there's not a better way to it.
Not really sure what you're doing but this removes all queue items.
fb.RunMainMenuCommand("Playback/Flush playback queue");
If you want to randomise handles for adding to the queue, you don't have to modify any playlist
var items = plman.GetPlaylistSelectedItems(plman.ActivePlaylist);
items.Randomise();
items.RunContextCommand("Add to playback queue");
Randomise and other handle list methods are documented here...
https://jscript-panel.github.io/docs/interfaces/IMetadbHandleList/
If you want to find the first selected item in a playlist.
function first_selected_item(playlistIndex) {
var count = plman.GetPlaylistItemCount(playlistIndex);
for (var i = 0; i < count; i++) {
if (plman.IsPlaylistItemSelected(playlistIndex, i)) {
return i;
}
}
return -1;
}
Always check the return value is not -1.
fb.RunMainMenuCommand("Playback/Flush playback queue");
Right! Make note to self not to use a space before and after the slash.
I use the code you sent, got it working and ended up with:
fb.RunMainMenuCommand("Playback/Flush playback queue");
fb.RunMainMenuCommand("Edit/Selection/Sort/Randomize") // Randomizes selection and displays selection in new order
var items = plman.GetPlaylistSelectedItems(plman.ActivePlaylist);
// items.Randomise(); // Randomizes selection but does not display selection in new order
items.RunContextCommand("Add to playback queue");
fb.Next();
I also managed to find and select the first item in the (randomised) selection
var sel_first = first_selected_item(plman.ActivePlaylist);
if ( sel_first > -1 ) {
plman.SetPlaylistFocusItem(plman.ActivePlaylist, sel_first);
}
I actually don't want to queue anything. So ideally I would just like to randomize the selection by using the Edit/Selection/Sort/Randomize command which also changes the order in the display like I want it. Then change the focus to the first item in the selection. And then play that item.
When I issue fb.Play however it just restarts the currently playing track and when I issue fb.Next foobar plays the next item below the currently playing file.
Is there a play command available to start playing the focused item?
I created rightclick functionality to my Add to queue button. It is supposed to clear any queued item from the current selection.
var items = plman.GetPlaylistSelectedItems(plman.ActivePlaylist);
items.RunContextCommand("Add to playback queue");
items.RunContextCommand("Remove from playback queue");
Works fine, but a bit weird first have to add all selected items to the queue, but otherwise the Remove command won't work for any of the items in the selection.
(Not any different from the context menu for Remove not being available if one of the items in the selection is not queued).
I read your documentation. In last post you pointed out plman.IsPlaylistItemSelected(playlistIndex, i).
Is there a similar plman.IsPlaylistItemQueued(playlistIndex, i) ?
I removed all advanced queue management stuff in JSP3. It exists in JSP2 and SMP.
However, you can get queued items in a dirty way by using title formatting...
var tfo = fb.TitleFormat("[%queue_index%]");
function get_queued_items(playlistIndex) {
var items = plman.GetPlaylistItems(playlistIndex);
var queued_items = fb.CreateHandleList();
for (var i = 0; i < items.Count; i++) {
if (tfo.EvalPlaylistItem(playlistIndex, i).length) {
queued_items.AddItem(items.GetItem(i));
}
}
return queued_items;
}
var queued_items = get_queued_items(plman.ActivePlaylist);
As for playing a given item, use this...
https://jscript-panel.github.io/docs/namespaces/plman/#plmanexecuteplaylistdefaultactionplaylistindex-playlistitemindex
https://jscript-panel.github.io/docs/namespaces/plman/#plmanexecuteplaylistdefaultactionplaylistindex-playlistitemindex
Thx. That did the trick. Nice clean randomize button now. Leftclick randomizes, rightclick randomizes and starts playing first item.
fb.RunMainMenuCommand("Playback/Flush playback queue"); // Flush queue in case foo_keep_queue is active
fb.RunMainMenuCommand("Edit/Selection/Sort/Randomize") // Randomize selection and display selection in new order
var FirstSelectedItem = _first_selected_item(plman.ActivePlaylist);
if ( FirstSelectedItem > -1 ) {
plman.ExecutePlaylistDefaultAction(plman.ActivePlaylist, FirstSelectedItem)
}
I keep my queue button rightclick code as is (it works) and start experimenting with the other piece of code you sent.
I created a DSP Preset button which works fine.
How can I optimize the following
case arr[active].name == 'Upmix to 3.0 (FL FR C)' || arr[active].name == 'Upmix to 4.0 (FL FR BL BR)' || arr[active].name == 'Upmix to 5.0 (FL FR C BL BR)':
which works to something like
case arr[active].name[1,5] == 'Upmix':
which does not work.
What is the syntax for matching the first 5 characters of arr[active].name ?
On a similar note ... how can I check for a pattern in a string (for instance) '[exclusive]' ?
Use indexOf.
//starts with
str.indexOf("Upmix") == 0;
//contains
str.indexOf("Upmix") > -1
Use indexOf.
//starts with
str.indexOf("Upmix") == 0;
//contains
str.indexOf("Upmix") > -1
Perfect. Thx.
How do I create a variable var global ?
By changing his value on panel A , it also changing on other panels ?
I need a function that include those variables inside a new .js file ?
Hope it's clear understanding. Thanks 😘
Not really sure what you're asking??
You can obviously put variables in your own .js files and import them as documented here...
https://jscript-panel.github.io/docs/preprocessors/
If you want an updated variable in one panel sent to another, use window.NotifyOthers and on_notify_data callback.
https://jscript-panel.github.io/docs/namespaces/window/#windownotifyothersname-info
https://jscript-panel.github.io/docs/callbacks/component/#on_notify_dataname-info
Not really sure what you're asking??
You can obviously put variables in your own .js files and import them as documented here...
https://jscript-panel.github.io/docs/preprocessors/
If you want an updated variable in one panel sent to another, use window.NotifyOthers and on_notify_data callback.
https://jscript-panel.github.io/docs/namespaces/window/#windownotifyothersname-info
https://jscript-panel.github.io/docs/callbacks/component/#on_notify_dataname-info
[/quote
Thanks you Marc . You are so reactive to us .
I made it work to change the background color from panel 1 and others panels with the function on notify like you said .
Now I need to change the background to the others layout as well.
Is it possible to send variable from layout to layout ?
Thanks 😘
good evening i am using the latest jsript panel 3.3.33 on smooth browser when I add a folder with 100 turns in it adds 200
many thanks in advance
when I add a folder with 100 turns in it adds 200
What? Did you mean to say tunes? Show an example screenshot and explain what you think is wrong with it.
Also. 3.3.33 is a long way from being the latest. Anyone using 3.3.30-3.3.39 really should update because there are some rendering bugs when panels are in tabs. 3.340 is the last release for Windows 7/8 users which fixes those bugs. The 3.4.x series requires at least Windows 8.1. The current version is 3.4.28.
okay thank you mark all sorted :)
Kind of esoteric question I guess. I had managed to get .jxl support up for the album art set up, by installing the corresponding WIC component. This was on my previous Windows install.
I followed the steps again. I installed a WIC for .jxl that allows the Windows file explorer to display .jxl thumbnails, and the Windows and other photo viewers to display .jxl images. I also know that the JScript Panel is playing well with the WIC, because I can select a .jxl image as a stub for "front cover", and it gets displayed. However, if in Display --> Album Art --> Front Cover --> Search patterns: I put "cover.jxl", something breaks and the album art doesn't get displayed (which is a valid .jxl file called cover.jxl in the folder of the currently playing file). Why could this be?
Look like a fb2k bug. I'll have to dig deeper before confirming/reporting it as such.
edit: reported here... https://hydrogenaud.io/index.php/topic,125996.0.html
fb2k 2.0 works as expected. Newer versions do not.
Look like a fb2k bug. I'll have to dig deeper before confirming/reporting it as such.
edit: reported here... https://hydrogenaud.io/index.php/topic,125996.0.html
fb2k 2.0 works as expected. Newer versions do not.
Thanks a lot buddy, I thought I was going crazy!
@marc2k3 Is there a way to change the default fontsize for tooltips (for instance in your Playback Buttons script)?
Inside the panel, right at the start...
window.SetTooltipFont('Segoe UI', NEW_SIZE);
@marc2k3
Is there a way to change the default fontsize for tooltips (for instance in your Playback Buttons script)?
https://jscript-panel.github.io/docs/namespaces/window/#windowsettooltipfontfont_name-font_size_px (https://jscript-panel.github.io/docs/namespaces/window/#windowsettooltipfontfont_name-font_size_px)
@marc2k3
Is there a way to change the default fontsize for tooltips (for instance in your Playback Buttons script)?
https://jscript-panel.github.io/docs/namespaces/window/#windowsettooltipfontfont_name-font_size_px (https://jscript-panel.github.io/docs/namespaces/window/#windowsettooltipfontfont_name-font_size_px)
Txh! Works.
A script included with JScript Panel 3 already does this...
(https://i.imgur.com/BPYHCVk.gif)
The obvious downside is that adding your own buttons is not easy.
FWIW, it works by drawing single font symbols so the colour/size can be anything. I use the Segoe Fluent Icons font for my own scripts but anyone writing their own can use whatever font they want.
https://learn.microsoft.com/en-us/windows/apps/design/style/segoe-fluent-icons-font
edit: the included script is called "Menu + Playback Buttons + Custom Colours" available from the Samples button in the Configuration window.
This gif makes it seem like the toolbar would look OK without the window bar. Is it ever thought to add the foo ui hacks functionality straight to the JScript Panel?
Is it ever thought to add the foo ui hacks functionality straight to the JScript Panel?
Nope.
a) It's not permitted...
https://github.com/marc2k3/foobar2000-sdk/blob/7f047cf2e541dd2f756c023195ef95285947d201/foobar2000/SDK/core_api.h#L13
//! Retrieves main app window. WARNING: this is provided for parent of dialog windows and such only; using it for anything else (such as hooking windowproc to alter app behaviors) is absolutely illegal. \n
b) Even if it was allowed, I wouldn't know how.
Thanks for the quick response.
I was unaware that the fb2k sdk warns against doing so.
However, I'm not sure how it's illegal since there are plenty of windows apps that are using custom window.
Maybe it's just the fb2k policy, which is fine with me. It makes sense why the outdated foo ui hacks aren't on the list of approved components. Simply said, I think that a lot of users still using it because of its functionality, primarily for custom skins or themes.
Hello
@marc2k3 I've backed up my system and restored foobar2k with all my plugins to my new install, it was all good till I updated from 3.4.17 to 3.5.1... This piece of code seems to be broken which I'm not sure why?
if (currentPlaylist === 1) { command = "File/Random pools/Assign keyboard shortcuts/GensokyoRadio Algorithm [Favourites]: All pools"; }
else { command = "File/Random pools/Assign keyboard shortcuts/GensokyoRadio Algorithm [All]: All pools"; }
fb.RunMainMenuCommand(command);
This exact piece of code worked before and the Random pools plugin hasn't changed at all. I've attached an image to show it's at the same location. I've even discussed this setup over here before as well https://hydrogenaud.io/index.php/topic,110516.msg1036207.html#msg1036207
Also I wanted to let you know that while I downgraded to an older version to check, I've lost all my tags set by JScript3... Luckily I have a backup of my old foobar2k but it would be better if you could put a huge red box to prevent users from downgrading... it looks like when I downgraded in Playback Statistics page you mentioned about how changing the title formatting will just erase the entire database, looks like downgrading did exactly that which caused this issue... Any idea what could be the reason behind this as well?
There were changes to how menu items were handled in 3.4.20...
https://jscript-panel.github.io/docs/changes/3-4-x/#3420
Although the changelog only explicitly mentions disabled menu items, it also refuses to run items that are never displayed. It seems like Random pools does exactly this making them for keyboard shortcuts only.
https://github.com/marc2k3/foobar2000-sdk/blob/7f047cf2e541dd2f756c023195ef95285947d201/foobar2000/SDK/menu.h#L53-L54
//! Retrieves display string and display flags to use when menu is about to be displayed. If returns false, menu item won't be displayed. You can create keyboard-shortcut-only commands by always returning false from get_display().
Running hidden items should be perfectly fine and is expected to work.
---
As for the data loss on downgrade, it's because I changed the SDK target version to fb2k v2. When you upgrade from a v1 compatible component that saved its config in
configuration\foo_jscript_panel3.dll.cfg, settings are migrated to config.sqlite and the old .cfg is deleted by fb2k itself. So if you downgrade, the existing configuration stored in config.sqlite is ignored because the component is compatible with v1 again so it relies on that .cfg file that no longer exists - it starts as if it's a fresh install.
3.5.2 should now execute menu commands that are never displayed.
3.5.2 should now execute menu commands that are never displayed.
Thanks a-lot for reverting the change!
Also regarding Playback Statistics backing up config.sqlite should be enough after the upgrade to 3.5.x if I want to carry over my settings from foobar install to another right?
The title format setting from the advanced preferences is contained within config.sqlite but the actual playback statistics data is stored inside metadb.sqlite.
@marc2k3
Lately I started experimenting a bit with external outputdevices like bluetooth headphones/jbl charge, which I can select with a (modified) JS3 output button.
Works fine.
When output is set to such a device and the external bluetooth output device is switched off the JS3 panel with the output device button did crash. So I wrote some extra lines to prevent the crashing by automatically setting the output device to the second found output (first one being Null Output).
This kinda works since the JS3 panel does not crash anymore, but upon such an event (switching off current output) foobar responds with stopping playback and opening it's preferences page to Preferences/Playback/Output already preset to the second output (as intended), but I still have to click OK and start playback manually.
buttons.update = function () {
...
var str = fb.GetOutputDevices();
var arr = JSON.parse(str);
var active = -1;
for (var i = 0; i < arr.length; i++) {
if (arr[i].active) active = i;
if (arr[i].name.indexOf("[exclusive]") > 0) last_exclusive = i;
}
if (active == -1) { // OutputDevice has been switched OFF
active = 1;
fb.RunMainMenuCommand('Playback/Device/' + arr[1].name); // Force second OutputDevice
}
switch (true) {
case active == 0:
var img_odev_normal = utils.LoadImage(imgPath + 'OutputDevice-NULL-normal.png');
var img_odev_hover = utils.LoadImage(imgPath + 'OutputDevice-NULL-hover.png');
break;
case active == 1:
var img_odev_normal = utils.LoadImage(imgPath + 'OutputDevice-Default-normal.png');
var img_odev_hover = utils.LoadImage(imgPath + 'OutputDevice-Default-hover.png');
break;
case arr[active].name.indexOf("[exclusive]") > 0:
var img_odev_normal = utils.LoadImage(imgPath + 'OutputDevice-Exclusive-normal.png');
var img_odev_hover = utils.LoadImage(imgPath + 'OutputDevice-Exclusive-hover.png');
break;
case active > last_exclusive:
var img_odev_normal = utils.LoadImage(imgPath + 'OutputDevice-External-normal.png');
var img_odev_hover = utils.LoadImage(imgPath + 'OutputDevice-External-hover.png');
break;
default:
var img_odev_normal = utils.LoadImage(imgPath + 'OutputDevice-Other-active.png');
var img_odev_hover = utils.LoadImage(imgPath + 'OutputDevice-Other-hover.png');
}
...
}
function on_output_device_changed() {
var str = fb.GetOutputDevices();
var arr = JSON.parse(str);
var active = -1;
var last_exclusive = -1;
for (var i = 0; i < arr.length; i++) {
if (arr[i].active) active = i;
if (arr[i].name.indexOf("[exclusive]") > 0) last_exclusive = i;
}
if (active == -1) {
active = 1;
fb.RunMainMenuCommand('Playback/Device/' + arr[1].name);
}
buttons.update();
window.Repaint();
}
I even copied this bit of code to the on_output_device_changed() function itself, but same behavior.
Is there a way to prevent opening of the preferences page when current output device is switched off?
NB. Preferably I'd like to detect the output not being available anymore, switching to second outputdevice and continue playing
I don't have removable devices to test but maybe you can use this Spider Monkey Panel script.
https://github.com/regorxxx/Device-Priority-SMP
I don't have removable devices to test but maybe you can use this Spider Monkey Panel script.
https://github.com/regorxxx/Device-Priority-SMP
Thx for the tip.
Made a testversion in which I removed all JS3 panels with my outputdevice code and installed the SMP code.
With some caveats the SMP code foobar switches to another output device when external output is switched off and continues playing.
Issue is that the Preferences/Playback/Output page does also pop up sometimes (not always) and needs an OK.
So in short the functionality I need exists within foobar.
I would prefer for uniformity (look& feel) to add the necessary code to my existing JS3 button, but a quick look at the underlying SMP code kind of freaked me out to try myself.
Well you probably can't suppress the preferences popup or close it automatically. You need to take steps to ensure that doesn't happen by switching devices or stopping playback before unplugging.
Well you probably can't suppress the preferences popup or close it automatically. You need to take steps to ensure that doesn't happen by switching devices or stopping playback before unplugging.
This only happens (in my JS3 code) when the active output device is switched off. Nothing crashes, but a bit silly to have to click OK in the popup and restart playback. Minor issue of course.
The SMP code is different from what I want. That code can be set to automatically switch to the external output device without popup when it comes online and switches back to a prioritized other device when the external device goes offline (half of the times without the popup). There is a lot of code to resume playback (and prevent the popup?) after switching when the active device goes offline.
I do not want to switch to the external device automatically since that device can come online when somebody else as an example wants to stream from his phone to that particular external device.
However the SMP code has all the bits and pieces of the functionality to create what I'm looking for.
I'll do a post about this in the Device-Priority-SMP thread.
@Marc2k3
Just asking ...
Until today everytime I made a minor change in my AudioControls button code I had to copy & apply this modified code to all 23 JS3 instances I have in my skin for AudioControls.
Today I moved the whole code (except for the two parameters I have to set per instance) to a single file that is now included per instance via the preprocessor.
So now only a reload via Shift-WinKey-Rightclick Reload per instance needs to be done when the central code is changed. Works like a charm and saves a lot of time.
Is there maybe also an (hidden/disabled?) option available to force all instances of JS3 panels to reload themselves upon one mouseclick? If not, would it be possible to implement that like for instance an extra option in Shift-WinKey-Rightclick menu or a separate special key/mouse command?
You can send notifications to other panels by triggering this from a button click or menu item...
https://jscript-panel.github.io/docs/namespaces/window/#windownotifyothersname-info
And listen in other panels with this...
https://jscript-panel.github.io/docs/callbacks/component/#on_notify_dataname-info
After checking the received message, used window.Reload()
https://jscript-panel.github.io/docs/namespaces/window/#windowreloadclear_properties
You can send notifications to other panels by triggering this from a button click or menu item...
And listen in other panels
After checking the received message, used window.Reload()
Thx! I have it working in the 23 AudioControl panels.
I'm struggling though where I issue the notify. I don't want to make a separate button for it since that would be part of the user interface or needs to be enabled separately if I have an update available for the audiocontrols.
For now I've "hidden" this command behind the middle mouse button.
It would make far more sense to add it to the SHIFT-WinKey-RightClick dropdown menu. Searched your code for it, but could not find where you define this dropdown menu.
Try
function on_script_unload() {
window.NotifyOthers("Test",1);
}
Try
function on_script_unload() {
window.NotifyOthers("Test",1);
}
Nope. That one hangs foobar. Probably because all the panels that receive the message will reload and send their own NotifyOthers resulting in deadlock.
Nope. That one hangs foobar. Probably because all the panels that receive the message will reload and send their own NotifyOthers resulting in deadlock.
If you notify the panel you changed of the changes of all other panels and force a reload of the already changed panel, this definitely will end in a deadlock. If you want to change scripts in different panels, you will have to send different notifications from each panel, e.g. "1" from panel 1, "2" from panel "2" and so on, and in the on_notify data you will have to check for all values except the one sent from the respective panel.
Edit: this will probably also end in a deadlock or take at least some time, because you will force 23 reloads of each panel. Probably not the best solution, if you would like to change different panels and notify others of the changes to force a reload - would be easy if you always change the same panel and just inform others to be redrawn
Edit2: What if you use the same panel for reloads each time? Then you just have to put the window.NotifyOthers in this panel and the others just get the On_Notify part and will be automatically reloaded.
Nope. That one hangs foobar. Probably because all the panels that receive the message will reload and send their own NotifyOthers resulting in deadlock.
I ran into "similar" problem on my Playlist Manager panel, where I had to force other panels to do something, but only a single time per call (no matter which panel threw the notification).
You can manage that with an extra txt file OR setting a date.now() timestamp at the properties panel and assume that any reload within X ms/secs should be skipped for ex. Save the date before reloading.
Let me explain a bit.
My AudioControl file had all code for 11 different buttons and thus had 600 lines of code. You can call this function with var b_single 0 and the panel will display all buttons. You can also choose a single button to display. In the user interface there is a setupmode in which you can either disable or enable (previously disabled) buttons. I have two full sets of separate buttons and 1 panel that shows them all (test/debug panel). The last one needs to be enabled by changing one line of PSS code, so is typically not accessible for a user.
Until now everytime I changed one tiny thing in the code I had to reload the whole thing 23x by copy/paste, changing one line per panel to say what button was to be displayed and apply.
So now I have changed the whole thing (except for the setting of two variables) to something I can include via the preprocessor.
The code that is placed in the panels itself is static (see attachment). It has the b_single variable which identifies the button I want to see and whether I want transparency (for now always 1). And now in order to be able to test this functionality also contains the on_notify_data. That's it.
I highly value the idea to have 1 set of code for all panels with only a single var defined at the top that changes functionality.
If I would want to apply what you mention before Edit 2 that means I have to include a new unique var in all of those panels and also have to keep track of which unique values I've used. That doesn't work for me.
Ad Edit 2 will work, but which one? Normally one full set of buttons and the test/debug full set are hidden. So the most obvious one would be the non-hidden menu button. I still don't like the idea of introducing an extra var to define which panel will be the publisher.
Choices for activating Reload for all panels with AudioControls available:
1) Leave it on mouse middle click; publish available on all AudioControl buttons (already tested & implemented)
2) Assigning the publish function based on on_script_unload to only one single AudioControl button (already tested & implemented)
3) Regor's method with txtfile or a timing check. Both beyond my JS3 capabilities
4) Adding an extra command to SHIFT-WinKey-Rightclick on all AudioControl buttons
For now and awaiting Marc2k3's answer on option 4 I've implemented both 1 & 2.
EDIT: Thanks for the on_script_unload tip.
// ==PREPROCESSOR==
// @name "Playback Buttons - Menu, Stop, Play/Pause, Previous, Next, PBO, RandomizeSelection, QueueSelection, ReplayGain, DSPpreset, OutputDevice - All with rightbutton extras"
// @author "marc2003, modified by Defender"
// @import "%fb2k_component_path%helpers.txt"
// @import "%fb2k_component_path%samples\js\lodash.min.js"
// @import "%fb2k_component_path%samples\js\common.js"
// @import "%fb2k_component_path%samples\js\panel.js"
// @import "%fb2k_profile_path%cui-configs\Defender\JS3\JS3_AudioControls.js"
// ==/PREPROCESSOR==
//////////////////////////////////////
var b_single = 1; // 0=Select multiple buttons Otherwise single button: 1=Menu 2=Stop 3=Play/Pause 4=Previous 5=Next 6=PBO 7=RandomizeSelection 8=QueueSelection 9=ReplayGain 10=DSPpreset 11=OutputDevice
if (b_single==0) {
// Select multiple buttons 0=OFF 1=ON. Make sure panel has enough width otherwise hover can stay activated with mouseovers
// Button Left click Right click
b_menu = 1; // 1 Main Menu - Help Menu
b_stop = 1; // 2 Stop - Stop After Current
b_play = 1; // 3 Play/Pause - Random - PBO will not be changed
b_prev = 1; // 4 Previous - Seek Back 10 sec
b_next = 1; // 5 Next - Seek Ahead 10 sec
b_pbo = 1; // 6 PBO Dropdown - Reset to Default
b_rsel = 1; // 7 Randomize Selection - Randomize Selection and Play
b_qsel = 1; // 8 Queue Selection - UnQueue Selection
b_rg = 1; // 9 ReplayGain Dropdown - Reset to Track
b_dsp = 1; // 10 DSP Preset Dropdown - Reset to first found DSP preset or Preferences
b_odev = 1; // 11 OutputDevice Dropdown - Reset to second outputdevice in list (should be standard Primary Sound Driver) or Preferences
}
var transparant = 1; // 0=OFF paint background 1=ON do not paint background
/////////////////////////////////////
var publisher = 0; // Only one instance of all AudioControl panels can have publisher set to 1
function on_script_unload() {
if (publisher == 1) window.NotifyOthers('AC.RELOAD', 'Reload all other AudioControl panels');
}
function on_notify_data(name, info) {
if (name === 'AC.RELOAD') window.Reload();
}
Another idea, if you could live with a keyboard shortcut. Put this code in any panel you like (can be a hidden one) and assign a keyboard shortcut to it:
function on_main_menu(index) {
switch (index) {
case 1: // triggered when File>JScript Panel 3>1 is run
window.NotifyOthers('AC.RELOAD',1);
break;
}
}
In all your 23 panels you just have to put the on_notify data and with the shortcut you can trigger the reload of all panels.
Another idea, if you could live with a keyboard shortcut. Put this code in any panel you like (can be a hidden one) and assign a keyboard shortcut to it:
function on_main_menu(index) {
switch (index) {
case 1: // triggered when File>JScript Panel 3>1 is run
window.NotifyOthers('AC.RELOAD',1);
break;
}
}
In all your 23 panels you just have to put the on_notify data and with the shortcut you can trigger the reload of all panels.
I don't like keyboard shortcuts, I have way too many already :-)
This however is a whole new concept for me and I don't understand how it works. How would you assign a keyboard shortcut to a panel?
Open Main Menu together with Shift - under File you will find 10 possible JScript entries you can use for whatever you want. You can address them via script as shown above.
It should also be possible to use fb.RunMainMenuCommand(command) if you want another option apart from shortcuts
Open Main Menu together with Shift - under File you will find 10 possible JScript entries you can use for whatever you want. You can address them via script as shown above.
It should also be possible to use fb.RunMainMenuCommand(command) if you want another option apart from shortcuts
Never too old to learn something new :-)
I will experiment a bit with this.
Thx.
And finally, since you don't like hotkeys, you can add an extra menu to panel.js:
After line 105:
this.m.AppendMenuItem(MF_STRING, 130, 'Reload Panels');
After line 137:
case idx == 130:
fb.RunMainMenuCommand("File/JScript Panel 3/1");
break;
With this, whenever you do a right click on a panel, you get a new command called "Reload Panels", where you can call the script mentioned above in the Main Menu
And finally, since you don't like hotkeys, you can add an extra menu to panel.js:
After line 105:
this.m.AppendMenuItem(MF_STRING, 130, 'Reload Panels');
After line 137:
case idx == 130:
fb.RunMainMenuCommand("File/JScript Panel 3/1");
break;
With this, whenever you do a right click on a panel, you get a new command called "Reload Panels", where you can call the script mentioned above in the Main Menu
I guess that doesn't work since all buttons have rightclick functionality and panel sizes are exactly the button size.
Only my debug/test buttonpanel with all the buttons has horizontal padding between the buttons where I can rightclick and get that menu.
You could use CTRL key or any other key to open the menu
In panels.js insert this after line 105
if (utils.IsKeyPressed(VK_CONTROL)) {
this.m.AppendMenuItem(MF_STRING, 130, 'Reload Panels');
}
After line 137 you add the following (stays the same as mentioned above):
case idx == 130:
fb.RunMainMenuCommand("File/JScript Panel 3/1");
break;
And you have to adapt your script accordingly and add one additional line in the on_mouse_rbtn function to avoid standard action when Right Click is done together with CTRL-key:
function on_mouse_rbtn_up(x, y) {
if (!utils.IsKeyPressed(VK_CONTROL)) { //This is an additional line to avoid standard action when Right Click is done with CTRL
YOUR CODE...
}
}
Of course you could use any other key to open the menu, e.g. VK_SHIFT. I tested CTRL as well as SHIFT and both work like a charm.
https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes (https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes)
fb.RunMainMenuCommand("File/JScript Panel 3/1");
This is nonsensical. The whole point of menu commands/callback is for running javascript from DUI/CUI toolbar buttons or global keyboard shortcuts. If you have a javascript button/menu, you'd run your own code directly without this added layer of complete and utter bollocks.
Please stop posting.
edit: I read up the page, it gets even worse Urgh.
edit2: I guess there is a component bug when using window.Reload from a custom right click menu. Because it executes immediately, the script doesn't get the chance to return true from the on_mouse_rbtn_up callback meaning the default menu is not suppressed and appears unexpectedly. I'll fix this in the next release.
edit2: I guess there is a component bug when using window.Reload from a custom right click menu. Because it executes immediately, the script doesn't get the chance to return true from the on_mouse_rbtn_up callback meaning the default menu is not suppressed and appears unexpectedly. I'll fix this in the next release.
I have ditched both methods for reloading all AC buttons (middle mouse button and on_script_unload special code for only one button).
Now using the following code which resides in my included preprocessed mainfile only, which is far more elegant imo:
function on_mouse_rbtn_up(x, y) {
if (utils.IsKeyPressed(VK_SHIFT)) {
window.NotifyOthers('AC.RELOAD', 'Reload all other AudioControl panels');
window.Reload();
return true;
}
...
I would make even more sense to have this functionality (only) available in the SHIFT-WinKey-Rightclick menu.
Can you point me to where I can find the code for that menu?
Can you point me to where I can find the code for that menu?
This is component code (pure C++) which you cannot override. I'm certainly not adding such a niche case for everyone.
This is component code (pure C++) which you cannot override. I'm certainly not adding such a niche case for everyone.
Nopro, kinda expected that.
I can live with SHIFT-RightClick.
Thx for pointing out the on_notify_others and windows.Reload. Certainly makes adjusting code a lot less cumbersome.
@marc2k3 I have a small doubt regarding context commands, is it possible to run context commands on another panel which isn't a JScript panel?
Probably should be a large doubt. These are context commands provided by the fb2k SDK which you also see by right clicking a playlist/library item/selection.
(https://i.imgur.com/xBtbf2b.png)
I cannot run menu commands from other panels. :/
I cannot run menu commands from other panels. :/
Oh thanks for clarifying, I've posted a request to a dev if he could expose it as a main menu command instead.
Bit of a hacky workaround but since that component is playlist based, how about forcing a refresh? To be useful, it must already respond to playlist callbacks such as items being added/removed so do that with a bit of JS. I assume it would read new art if this happens?
Bit of a hacky workaround but since that component is playlist based, how about forcing a refresh? To be useful, it must already respond to playlist callbacks such as items being added/removed so do that with a bit of JS. I assume it would read new art if this happens?
I'm not sure which component your talking about? is it foo_coverflow_mod? if so it looks like the only way to force refresh is through keybinds and that's only if you hit F5 when that panel is focused. I was looking into some coverflow discussion here as well, to be honest the JScript version of Album Art does the job but when it comes to displaying the image it doesn't fully cover the panel unless I drag the panel borders pixel perfect to the album art. I've attached an example with red highlighting the gap. The JScript album art is set to Center.
Hey, I have a problem with the fonts. The playlist organizer script shows blank squares where there shluld be symbols. I use the newest version of Jscript panel (3.5.3) and I also have the Segoe Fluent Icons installed. I also tried to change the default font for the playlist names to this new font but then everything just just those empty squares.
I tried to find a solution now for a few hours but all google tells me is that I need to install the font that is already installed :(
Any ideas? Thansk in advance ♥
Well that playlist organiser is a 3rd party script, not included with the component so whatever requirements I list do not apply.
I'm guessing you need font awesome.
https://github.com/FortAwesome/Font-Awesome/raw/4.x/fonts/fontawesome-webfont.ttf
Well that playlist organiser is a 3rd party script, not included with the component so whatever requirements I list do not apply.
I'm guessing you need font awesome.
https://github.com/FortAwesome/Font-Awesome/raw/4.x/fonts/fontawesome-webfont.ttf
Aahh well, that makes sense then, installing FontAwesome worked again! ♥
@marc2k3 you asked to please use this thread for requests, so here goes. Could I have something like the following image added to your "Track Info + Spectrogram Seekbar + Buttons" script? I'll also post the current settings I am using below:
(https://i.imgur.com/Fi0OZuh.jpeg)
// ==PREPROCESSOR==
// @name "Track Info + Spectrogram Seekbar + Buttons"
// @author "marc2003"
// @import "%fb2k_component_path%helpers.txt"
// @import "%fb2k_component_path%samples\js\lodash.min.js"
// @import "%fb2k_component_path%samples\js\common.js"
// @import "%fb2k_component_path%samples\js\panel.js"
// @import "%fb2k_component_path%samples\js\seekbar.js"
// ==/PREPROCESSOR==
/*
Most samples already require FontAwesome and it's used for the default buttons.
https://github.com/FortAwesome/Font-Awesome/blob/4.x/fonts/fontawesome-webfont.ttf?raw=true
The Segoe Fluent Icons font is already included with Windows 11. Windows 10 users can download it here:
https://download.microsoft.com/download/8/f/c/8fc7cbc3-177e-4a22-af48-2a85e1c5bffb/Segoe-Fluent-Icons.zip
If installed, you can right click the panel and change the button set.
---
Full ffmpeg setup instructions here: https://jscript-panel.github.io/gallery/spectrogram-seekbar/
If you edit the ffmeg_exe variable, directory separators must be escaped like "D:\\Audio\\Tools\\ffmpeg.exe"
If you edit the spectrogram_cache variable, you must make sure the folder already exists.
*/
var ffmpeg_exe = fb.ProfilePath + 'ffmpeg.exe';
var spectrogram_cache = folders.data + 'spectrogram_cache\\';
var colours = {
buttons : RGB(8, 255, 255),
background : RGB(30, 30, 30),
title : RGB(8, 255, 255),
artist : RGB(240, 240, 240),
time : RGB(240, 240, 240),
sac : RGB(196, 30, 35),
};
var tfo = {
artist : fb.TitleFormat('%artist%'),
title : fb.TitleFormat('%tracknumber% / %totaltracks% - %title%'),
playback_time : fb.TitleFormat('[%playback_time%]'),
length : fb.TitleFormat(' %length% $ifequal(%LASTFM_LOVED_DB%,1,❤️,)' ),
};
//////////////////////////////////////////////////////////////
var panel = new _panel();
var seekbar = new _seekbar(0, 0, 0, 0, true);
var buttons = new _buttons();
var button_set_idx = 0;
var fluent_font = 'Segoe Fluent Icons';
var has_font = utils.CheckFont(fluent_font);
var bs = _scale(24);
var normal_font = CreateFontString('Segoe UI', 12);
var bold_font = CreateFontString('Segoe UI', 12, true);
window.MaxHeight = _scale(150);
var char_set = [chars, fluent_chars];
if (has_font) {
button_set_idx = window.GetProperty('2K3.BUTTON.SET', 0);
}
if (fb.IsPlaying) on_playback_new_track(fb.GetNowPlaying());
else on_item_focus_change();
buttons.update = function () {
var y = Math.round((panel.h - bs) / 2);
this.buttons.stop = new _button(panel.w - LM - (bs * 8), y, bs, bs, { char : char_set[button_set_idx].stop, colour:fb.StopAfterCurrent ? colours.sac : colours.buttons}, null, function () { fb.Stop(); }, 'Stop');
this.buttons.previous = new _button(panel.w - LM - (bs * 7), y, bs, bs, { char : char_set[button_set_idx].prev, colour:colours.buttons }, null, function () { fb.Prev(); }, 'Previous');
this.buttons.play = new _button(panel.w - LM - (bs * 6), y, bs, bs, { char : !fb.IsPlaying || fb.IsPaused ? char_set[button_set_idx].play : char_set[button_set_idx].pause, colour:colours.buttons}, null, function () { fb.PlayOrPause(); }, !fb.IsPlaying || fb.IsPaused ? 'Play' : 'Pause');
this.buttons.next = new _button(panel.w - LM - (bs * 5), y, bs, bs, { char : char_set[button_set_idx].next, colour:colours.buttons }, null, function () { fb.Next(); }, 'Next');
this.buttons.console = new _button(panel.w - LM - (bs * 3), y, bs, bs, {char : char_set[button_set_idx].console, colour:colours.buttons }, null, function () { fb.ShowConsole(); }, 'Console');
this.buttons.search = new _button(panel.w - LM - (bs * 2), y, bs, bs, { char : char_set[button_set_idx].search, colour:colours.buttons }, null, function () { fb.RunMainMenuCommand('Library/Search'); }, 'Library Search');
this.buttons.preferences = new _button(panel.w - LM - bs, y, bs, bs, { char : char_set[button_set_idx].preferences, colour:colours.buttons}, null, function () { fb.ShowPreferences(); }, 'Preferences');
if (button_set_idx == 1) {
this.change_font(fluent_font);
}
}
function on_item_focus_change() {
seekbar.item_focus_change();
}
function on_mouse_lbtn_down(x, y) {
seekbar.lbtn_down(x, y);
}
function on_mouse_lbtn_up(x, y) {
if (buttons.lbtn_up(x, y)) {
return;
}
if (seekbar.lbtn_up(x, y)) {
return;
}
fb.RunMainMenuCommand('View/Show now playing in playlist');
}
function on_mouse_leave() {
buttons.leave();
}
function on_mouse_move(x, y) {
if (buttons.move(x, y)) {
return;
}
seekbar.move(x, y);
}
function on_mouse_rbtn_up(x, y) {
if (seekbar.containsXY(x, y)) {
return panel.rbtn_up(x, y, seekbar);
}
if (buttons.buttons.stop.containsXY(x, y)) {
fb.StopAfterCurrent = !fb.StopAfterCurrent;
return true;
}
var menu = window.CreatePopupMenu();
var sub = window.CreatePopupMenu();
sub.AppendMenuItem(MF_STRING, 1, 'Original');
sub.AppendMenuItem(EnableMenuIf(has_font), 2, 'Fluent');
sub.CheckMenuRadioItem(1, 2, button_set_idx + 1);
sub.AppendTo(menu, MF_STRING, 'Buttons');
menu.AppendMenuSeparator();
menu.AppendMenuItem(MF_STRING, 3, 'Configure');
var idx = menu.TrackPopupMenu(x, y);
menu.Dispose();
switch (idx ) {
case 1:
case 2:
button_set_idx = idx - 1;
window.SetProperty('2K3.BUTTON.SET', button_set_idx);
buttons.update();
window.Repaint();
break;
case 3:
window.ShowConfigure();
break;
}
return true;
}
function on_mouse_wheel(s) {
if (seekbar.wheel(s)) {
return;
}
if (s == 1) {
fb.VolumeUp();
} else {
fb.VolumeDown();
}
}
function on_paint(gr) {
gr.Clear(colours.background);
gr.FillRectangle(seekbar.x, seekbar.y, seekbar.w, seekbar.h, colours.seekbar_background);
seekbar.paint(gr);
DrawRectangle(gr, seekbar.x, seekbar.y, seekbar.w, seekbar.h, seekbar.properties.marker_colour.value);
buttons.paint(gr);
if (fb.IsPlaying) {
gr.WriteText(tfo.title.Eval(), bold_font, colours.title, 10, 0, seekbar.x - _scale(60), panel.h * 0.6, DWRITE_TEXT_ALIGNMENT_LEADING, DWRITE_PARAGRAPH_ALIGNMENT_CENTER, DWRITE_WORD_WRAPPING_NO_WRAP, DWRITE_TRIMMING_GRANULARITY_CHARACTER);
gr.WriteText(tfo.artist.Eval(), normal_font, colours.artist, 10, panel.h * 0.3, seekbar.x - _scale(60), panel.h * 0.7, DWRITE_TEXT_ALIGNMENT_LEADING, DWRITE_PARAGRAPH_ALIGNMENT_CENTER, DWRITE_WORD_WRAPPING_NO_WRAP, DWRITE_TRIMMING_GRANULARITY_CHARACTER);
gr.WriteText(tfo.playback_time.Eval(), normal_font, colours.time, seekbar.x - _scale(66), 0, _scale(60), panel.h, DWRITE_TEXT_ALIGNMENT_TRAILING, DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
gr.WriteText(tfo.length.Eval(), normal_font, colours.time, seekbar.x + seekbar.w + _scale(6), 0, _scale(60), panel.h, DWRITE_TEXT_ALIGNMENT_LEADING, DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
}
}
function on_playback_dynamic_info_track(type) {
if (type == 0) window.Repaint();
}
function on_playback_edited() {
window.Repaint();
}
function on_playback_new_track(metadb) {
seekbar.playback_new_track(metadb);
}
function on_playback_pause() {
buttons.update();
window.Repaint();
}
function on_playback_seek() {
seekbar.playback_seek();
}
function on_playback_starting() {
buttons.update();
window.Repaint();
}
function on_playback_stop(reason) {
seekbar.playback_stop(reason);
buttons.update();
window.Repaint();
}
function on_playback_time() {
window.RepaintRect(panel.h, 0, seekbar.x - panel.h, panel.h);
}
function on_playlist_stop_after_current_changed() {
buttons.update();
window.Repaint();
}
function on_playlist_switch() {
seekbar.item_focus_change();
}
function on_run_cmd_async_done(task_id) {
seekbar.run_cmd_async_done(task_id);
}
function on_size() {
panel.size();
seekbar.x = _scale(300);
seekbar.y = _scale(5);
seekbar.w = panel.w - seekbar.x - _scale(280);
seekbar.h = panel.h - (seekbar.y * 2);
buttons.update();
}
If you replace the 4 instances of this....
gr.WriteText(
with
DrawColouredText(gr,
You can now use $rgb in your title format strings.
thx. And another quick question, how do you actually show brackets (like the actual characters) in a format string
First update code like this...
fb.TitleFormat('%album%')
to use double quotes..
fb.TitleFormat("%album%")
Now you can use single quotes around [] or ()
fb.TitleFormat("%album% '('%date%')'")
I've added full $rgb support to the following samples, They can be tested by pasting the contents of these links in a panel.
Track Info + Seekbar + Buttons + Volume
https://raw.githubusercontent.com/jscript-panel/component/main/samples/Track%20Info%20%2B%20Seekbar%20%2B%20Buttons%20%2B%20Volume.txt
Track Info + Seekbar + Buttons
https://raw.githubusercontent.com/jscript-panel/component/main/samples/Track%20Info%20%2B%20Seekbar%20%2B%20Buttons.txt
Track Info + Spectrogram Seekbar + Buttons
https://raw.githubusercontent.com/jscript-panel/component/main/samples/Track%20Info%20%2B%20Spectrogram%20Seekbar%20%2B%20Buttons.txt
Something curious happens with the Text Display sample. If I play a track, then change the playlist and then press Stop, the text displayed changes to "NEIN". This happens either by selecting a different playlist or by changing the Library Viewer Selection playlist with Album List, Refacets etc.
Using JScript Panel 3.5.2 on foobar2000 v2.2 preview 2024-05-17 x64.
I know how that error can occur but I thought I had safeguards to prevent it.
Can you try saving this file inside your component folder\samples\js overwriting the existing file.
https://raw.githubusercontent.com/jscript-panel/component/main/samples/js/text_display.js
Restart fb2k if it's running.
@marc2k3 :
Yes, replacing the file has fixed the issue for me, thanks.
Message to marc2k3:
Until now I used cover-info to detect in a playlist the albums that I had forgotten to embed their cover.
First I would run the "Scan for cover info" option in the playlist
And then I ran in Re-Facets the filter %front_cover_width% MISSING that returned me the tracks that didn't have the cover embedded.
Everything worked perfectly.
I uninstalled
- foo_cover_info-1.0.4.fb2k-component
- foo_cover_resizer-1.0.8.fb2k-component
I have installed foo_cover_utils-1.0.fb2k-component
And it doesn't work anymore. The Re-Facets gives me back all the discs in the playlist when they all have their cover embedded.
I had to uninstall it and reinstall foo_cover_info and foo_cover_resizer.
I don't know if there's something I'm not doing right or if the new component is not fully adjusted.
This is entirely the wrong thread to ask about this. :/
Anyway... the download page did have a broken link which I've just fixed. Sorry to everyone about that.
It should have told you to read here...
https://marc2k3.github.io/component/cover-utils/
This is a combined replacement for foo_cover_info and foo_cover_resizer. If you have either/both installed, you must remove them first.
Note that this uses a separate database for front cover info storage so files would need scanning again. Also, different title format fields are used for display. See below.
specifically...
https://marc2k3.github.io/component/cover-utils/#scan-for-info
This is entirely the wrong thread to ask about this. :/
Anyway... the download page did have a broken link which I've just fixed. Sorry to everyone about that.
It should have told you to read here...
https://marc2k3.github.io/component/cover-utils/
This is a combined replacement for foo_cover_info and foo_cover_resizer. If you have either/both installed, you must remove them first.
Note that this uses a separate database for front cover info storage so files would need scanning again. Also, different title format fields are used for display. See below.
specifically...
https://marc2k3.github.io/component/cover-utils/#scan-for-info
Thanks Marc.
I just had to replace in Re-Facets the filter %front_cover_width% MISSING by %cover_utils_front_width% MISSING
Everything works perfect
Drag-and-drop for tracks in Smooth Playlist seems not to be working for me in 3.5.5. :'(
I'm sure it was OK in the last couple of versions...
Drag/drop in Smooth Playlist it extremely limited. You can drag/drop from other panels on to it and that is all. No matter where you let go of the mouse, the selection is always appended to the end. There is no placement. The current version is working fine in that regard.
JS Playlist is the one with full drag/drop support.
BTW, the mouse pointer should indicate if drag/drop is totally prohibited due to an autoplaylist or other playlist lock preventing the addition of new items.
Ah, of course! Sorry for wasting your time.
hi
I have a minor question about displaying Properties.
If the panel size is limited, long tag field names will make the field values almost invisible.


Is it possible to adjust the size as shown below or omit the part before keywords such as "MUSICBRAINZ_"?


Save this in your component folder\samples\js overwriting the existing file.
https://raw.githubusercontent.com/jscript-panel/component/main/samples/js/list.js
It will also be in the next component release whenever that is.
It's easier to see
Thank you!
Bummer. Deleted the original text while adding an EDIT.
This change introduces a problem will really long tagnames that have the significant part op the name at the end. For instance all TRUEPEAK_SCANNER_* tags. With the new adjustment the significant part of the tagname is not displayed anymore (see screenshot).
Would it be possible to adjust code:
1) Make tagname width vs tag values weighted to a selectable percentage (for instance 60% of width is reserved for tagname). I can see that you already use a fixed percentage of 50% in case width is limited.
2) Make the vertical boundary between tagnames and values movable by mouse.
3) If tagname is larger than available width, right align tagnames in the allocated width and use ... on the left.
4) Introduce abbreviations in the configure part of this script. For instance all occurences of 'TRUEPEAK_SCANNER' in tagnames become 'tps'. Lowercase signals it is an abbreviation and a mouseover shows the full name.
Or a combination of the above?
edit: link removed
This breaks a whole bunch of other scripts, I'll have to try something else.
It's better
great
@marc2k3 Hi,
I'm using a modified version of your thumbs sample. Works great, looks great.
What I would like (as an option in the rightclick menu perhaps?) is the possibility to show the to be displayed image full-sized and blurred as a background for the whole JSP3 thumbs panel excluding/including its grid.
Would that be possible? If not, can you point me to the place in the code and the syntax for the extra line to add?
I tried myself, but with no avail.
For reference I included a screenshot of the WillB BIO page with the effect I'd like to achieve and the slightly modified version of your thumbs I use.
The first image of multiple is always blurred by default and can be accessed with thumbs.blur_img so inside on_paint, add this BEFORE thumbs.paint(gr)
_drawImage(gr, thumbs.blur_img, 0, 0, panel.w, panel.h, image.crop);
edit: whenever an image is blurred, it has to be clone of the original so it uses twice as much memory which is why I do it on the first only. I don't really want to blur all images or do it on demand.
The first image of multiple is always blurred by default and can be accessed with thumbs.blur_img so inside on_paint, add this BEFORE thumbs.paint(gr)
_drawImage(gr, thumbs.blur_img, 0, 0, panel.w, panel.h, image.crop);
edit: whenever an image is blurred, it has to be clone of the original so it uses twice as much memory which is why I do it on the first only. I don't really want to blur all images or do it on demand.
Thank you.
I had to place the extra line to a different spot, because it interfered with my transparency support, which I have because I want to show a custom background in case no art is found (for instance streams).
The added blur looks very good imo, but rather static since the background is always the blurred first found image. SMP panels do change their background blurring when a different image is displayed.
I made it optional to use a blurred version of the current (to be displayed) image.
When monitoring memory usage of foobar with this way of blurring activated I noticed the following:
Starting fooBar and opening a folder with some 19 pics memory usage is 890MB.
Using the scrollwheel on art and thus changing the blur background it grows to a maximum of about 1.3GB (after a lot of mousewheeling) and then it resets itself back to 890MB.
If I let memory usage grow to a little under 1.3GB, the moment I select a different folder it also resets to ~890MB.
To me it looks as if fooBar or your component does a pretty good job of keeping memory usage in hand.
Seeing this memory behaviour ... can you please explain what the risk is of blurring the current image always?
Last question:
How can I lower the brightness of the displayed blurred image?
Instead of
_drawImage(gr, thumbs.blur_img, 0, 0, panel.w, panel.h, image.crop);
I tried to use
gr.DrawImage(thumbs.blur_img, 0, 0, panel.w, panel.h, 0, 0, this.blur_img.Width, this.blur_img.Height, 0.5, 0);
which lowers the brightness but does not show the exact same image.
Seems like blurring on demand could be OK. I've been messing around with it (see attachment)
edit: the artifacting is my gif recorder, not my blurring.
Seems like blurring on demand could be OK. I've been messing around with it (see attachment)
edit: the artifacting is my gif recorder, not my blurring.
Yes, looks quite the same as my implementation. Your memory usage doesn't increase at all.
I changed my code to dispose of the blurred image after displaying it and now my memory usage does not increase at all anymore.
this.paint = function (gr) {
var offset_px = this.offset * this.properties.px.value;
// Added
if ( this.images.length > 0 ) {
if ( transparent == 1 ) {
gr.FillRectangle(0, 0, panel.w, panel.h, colours.background); // paint full background to remove PSS background art
}
if ( blur == 2 ) {
this.blur_img = this.images[this.image].Clone();
this.blur_img.StackBlur(120);
}
if ( blur > 0 ) {
_drawImage(gr, thumbs.blur_img, 0, 0, panel.w, panel.h, image.crop, 0.7);
// gr.DrawImage(thumbs.blur_img, 0, 0, panel.w, panel.h, 0, 0, this.blur_img.Width, this.blur_img.Height, 0.7, 0);
// DrawImage(thumbs.blur_img, dstX, dstY, dstW, dstH, srcX, srcY, srcW, srcH[, opacity, angle])
if ( blur == 2 ) {
this.blur_img.Dispose();
this.blur_img = null;
}
}
}
...
Great stuff these adjustments.
I have a better fix for the properties script names being too wide. Same instructions/link as before.
Save this in your component folder\samples\js overwriting the existing file.
https://raw.githubusercontent.com/jscript-panel/component/main/samples/js/list.js
It will also be in the next component release whenever that is.
I have a better fix for the properties script names being too wide. Same instructions/link as before.
What are the changes?
It is still using a fixed 50%-50% between tags and values from a certain panel width.
I'm still seeing the relevant parts of tagnames disappearing in the end_ellipsis.
I already changed the fontsize to 8, but it doesn't help much.
Please consider implementing a solution like I suggested before ...
https://hydrogenaud.io/index.php/topic,110516.msg1046476.html#msg1046476
The last release version used the full width of the longest tag name regardless of panel size which was a major problem. 50/50 improves things but can't help if you have insanely long tag names in a narrow panel. The previous mod also broke other scripts that share common code, This version does not. If you're still not happy, don't use it or edit the javascript yourself.
The last release version used the full width of the longest tag name regardless of panel size which was a major problem. 50/50 improves things but can't help if you have insanely long tag names in a narrow panel. The previous mod also broke other scripts that share common code, This version does not. If you're still not happy, don't use it or edit the javascript yourself.
The problem mainly is the extremely long default tag names for truepeak scanner (for example TRUEPEAK_SCANNER_CLIPPED_SAMPLES_ALBUM).
If the 50/50 could be changed that would be helpful.
If that could be combined by displaying tagnames in lowercase the issue would be solved.
Can you point me to the lines that I need to change to do both things?
Download the same file again and make the changes to 0.5 on this line...
https://github.com/jscript-panel/component/blob/81561a7a46bf2820797d76c63477baf2cfd2befe/samples/js/list.js#L469
I am very satisfied
I've realized over the past few weeks how useful it would be to create an autoplaylist with a field value and have the web browser open the musicbrainz ID link.
Aren't the very long tag field names mostly unrelated to album or track credits?
For me, the musicbrainz id field name is the longest.
Even if all 8 musicbrainz id fields appear on the screen as "MUSICBRAINZ_...", it is not much of an inconvenience.
Because I can identify it by hovering my mouse cursor over that field.
Since I don't use components that create and use tag fields with long names, I may not have realized their importance.
Anyway, it became more useful to me.
thank you
general question, but testing on Text Reader sample:
what is the correct custom profile path reference?
eg. %fb2k_profile_path% %profile% ?
also is there a way to call/display multiple paths eg:
path\file1.txt ^^ path\file2.txt
I can add support for %fb2k_profile_path% in the next release.
And no, you cannot supply multiple file paths. But if you do supply a folder path, it will automatically use the first txt/log file it finds. The dialog tells you this.
Download the same file again and make the changes to 0.5 on this line...
https://github.com/jscript-panel/component/blob/81561a7a46bf2820797d76c63477baf2cfd2befe/samples/js/list.js#L469
Thx for pointing me to the right direction.
I ended up changing the font back to 9 instead of 8 and keeping the weighting at 0.5.
I did change something a couple of lines lower:
// this.draw_row(gr, this.data[i + this.offset].name, panel.colours.text, this.x, this.y + _scale(12) + (i * panel.row_height), this.clickable_text_x - 10, panel.row_height); // ORIGINAL
this.draw_row(gr, this.data[i + this.offset].name.replace(/TRUEPEAK_SCANNER/g,'tps').replace(/REPLAYGAIN/g,'rg').replace(/MUSICBRAINZ/g,'mb'), panel.colours.text, this.x, this.y + _scale(12) + (i * panel.row_height), this.clickable_text_x - 10, panel.row_height);
works great.
Thx
Hello,
How to make background blur in properties? This is what I marked in the screenshot
https://imgbox.com/serjCZpZ
Thank you in advance
Hello,
How to make background blur in properties? This is what I marked in the screenshot
https://imgbox.com/serjCZpZ
Thank you in advance
The properties and properties+other info samples do not support painting a blurred background in it's code until now.
What I did is just change one line of code in the sample script to support transparency.
I paint the background with a gradient and display some (selectable) art with low alpha/brightness before I load the JS3 panel with the Properties + Other info sample code on top of it.
It is not blurred, but achieves a similar effect imo.
Ideal:
Now Playing Screen (Text Display)
(https://i.imgur.com/4Rafg1w.png)
Quick request: Would it be possible to combine the Seekbar/Buttons from "Text Display + Album Art + Seekbar + Buttons" with the original "Text Display" sample, allowing the flexibility to toggle Album Art on/off and change position relative to text?
Ideal:
Now Playing Screen (Text Display)
(https://i.imgur.com/4Rafg1w.png)
Your modification looks cool, could you please post the script? Based on your script I will try to adapt it to my needs.
Hahaha, that's not it.
I want it. It's the perfect screen for Now Playing Screen.
Sorry.
@Air KEN Oh, I understand ;D
Can we get a sample of a png or svg image as buttons instead of font icons?
This is a composite image of an image from the foo_uie_webview thread, so I don't know. Sorry.
Can we get a sample of a png or svg image as buttons instead of font icons?
In 3.6.1, the _button object now supports images.
Replace
{ char : some_char, colour : some_colour }
with
{ img : some_image }
var some_image = utils.LoadImage(fb.ProfilePath + "images\\blah.png");
You only want to load images once on script init so don't put this inside any update function.
Thank you very much for the update and the guide
@marc2k3 ---
This is a composite image of an image from the foo_uie_webview thread, so I don't know. Sorry.
No worries, mate. With latest JSP update, we can also replicate it on a text display.
The script and image files with the PNG and SVG icons are available below.
In your foobar config folder, extract it to the images folder.
Just modify the link on script or the icons as needed.
(https://i.imgur.com/nnYUcGv.png)
// ==PREPROCESSOR==
// @name "Text Display + Album Art + Custom SVG and PNG Buttons"
// @author "marc2003"
// @import "%fb2k_component_path%helpers.txt"
// @import "%fb2k_component_path%samples\js\lodash.min.js"
// @import "%fb2k_component_path%samples\js\common.js"
// @import "%fb2k_component_path%samples\js\panel.js"
// @import "%fb2k_component_path%samples\js\albumart.js"
// @import "%fb2k_component_path%samples\js\text_display.js"
// @import "%fb2k_component_path%samples\js\seekbar.js"
// ==/PREPROCESSOR==
// https://jscript-panel.github.io/gallery/text-display/
//.svg files
var google = utils.LoadSVG(fb.ProfilePath + 'images\\google.svg');
var youtube = utils.LoadSVG(fb.ProfilePath + 'images\\youtube.svg');
var spotify = utils.LoadSVG(fb.ProfilePath + 'images\\spotify.svg');
var wikipedia = utils.LoadSVG(fb.ProfilePath + 'images\\wikipedia.svg');
var lastfm = utils.LoadSVG(fb.ProfilePath + 'images\\lastfm.svg');
var search = utils.LoadSVG(fb.ProfilePath + 'images\\search.svg');
var settings = utils.LoadSVG(fb.ProfilePath + 'images\\settings.svg');
//.png files
var discogs = utils.LoadImage(fb.ProfilePath + 'images\\discogs.png');
var tfo = {
artist: fb.TitleFormat('%artist%'),
title: fb.TitleFormat('%title%'),
// playback_time : fb.TitleFormat('[%playback_time%]'),
// length : fb.TitleFormat('$if2(%length%,LIVE)'),
}
var panel = new _panel({ custom_background : true });
var albumart = new _albumart(0, 0, 0, 0);
var text = new _text_display(LM, 0, 0, 0, true);
var seekbar = new _seekbar(0, 0, 0, 0);
var colours = {
slider_background : RGB(160, 160, 160),
white : RGB(255, 255, 255),
contrast : RGB(196, 30, 35),
};
var font = CreateFontString('Segoe UI', 12);
var buttons = new _buttons();
var bs = _scale(24);
var bottom_y = 0;
buttons.update = function () {
var x = (panel.w - (bs * 7)) / 2
var y = seekbar.y + _scale(12);
this.buttons.google = new _button(x, y, bs, bs, { img : google }, null, function () { utils.Run('https://www.google.com/search?tbm=isch&q=' + encodeURIComponent(tfo.artist.Eval() + " " + tfo.title.Eval())); }, 'Google');
this.buttons.youtube = new _button(x + bs, y, bs, bs, { img : youtube }, null, function () { utils.Run('http://www.youtube.com/results?search_query=' + encodeURIComponent(tfo.artist.Eval() + " " + tfo.title.Eval())); }, 'youtube');
this.buttons.spotify = new _button(x + (bs * 2), y, bs, bs, { img : spotify}, null, function () { utils.Run('https://open.spotify.com/search/' + encodeURIComponent(tfo.artist.Eval() + " " + tfo.title.Eval())); }, 'spotify');
this.buttons.wikipedia = new _button(x + (bs * 3), y, bs, bs, { img : wikipedia }, null, function () { utils.Run('http://en.wikipedia.org/wiki/Special:Search?search=' + encodeURIComponent(tfo.artist.Eval())); }, 'wikipedia');
this.buttons.lastfm = new _button(x + (bs * 4), y, bs, bs, { img : lastfm }, null, function () { utils.Run('https://www.last.fm/search?q=' + encodeURIComponent(tfo.artist.Eval())); }, 'lastfm');
this.buttons.discogs = new _button(x + (bs * 5), y, bs, bs, { img : discogs }, null, function () { utils.Run('http://www.discogs.com/search?q=' + encodeURIComponent(tfo.artist.Eval())); }, 'discogs');
this.buttons.search = new _button(x + (bs * 6), y, bs, bs, { img : search }, null, function () { fb.RunMainMenuCommand('Library/Search'); }, 'Library Search');
this.buttons.preferences = new _button(x + (bs * 7), y, bs, bs, { img : settings}, null, function () { fb.ShowPreferences(); }, 'Preferences');
}
panel.item_focus_change();
function on_colours_changed() {
panel.colours_changed();
text.refresh(true);
}
function on_font_changed() {
panel.font_changed();
text.refresh(true);
}
function on_item_focus_change() {
if (panel.selection.value == 0 && fb.IsPlaying) return;
panel.item_focus_change();
}
function on_metadb_changed(handles, fromhook) {
if (!fromhook) {
albumart.metadb_changed();
}
text.metadb_changed();
}
function on_mouse_lbtn_dblclk(x, y) {
if (albumart.img && albumart.containsXY(x, y)) {
panel.metadb.ShowAlbumArtViewer();
}
}
function on_mouse_lbtn_down(x, y) {
seekbar.lbtn_down(x, y);
}
function on_mouse_lbtn_up(x, y) {
if (seekbar.lbtn_up(x, y)) {
return;
}
if (buttons.lbtn_up(x, y)) {
return;
}
text.lbtn_up(x, y);
}
function on_mouse_leave() {
buttons.leave();
}
function on_mouse_move(x, y) {
window.SetCursor(buttons.buttons.google.containsXY(x, y) ? IDC_HAND
: buttons.buttons.youtube.containsXY(x, y) ? IDC_HAND
: buttons.buttons.spotify.containsXY(x, y) ? IDC_HAND
: buttons.buttons.wikipedia.containsXY(x, y) ? IDC_HAND
: buttons.buttons.lastfm.containsXY(x, y) ? IDC_HAND
: buttons.buttons.discogs.containsXY(x, y) ? IDC_HAND
: buttons.buttons.search.containsXY(x, y) ? IDC_HAND
: buttons.buttons.preferences.containsXY(x, y) ? IDC_HAND
: IDC_ARROW);
if (seekbar.move(x, y)) {
return;
}
if (buttons.move(x, y)) {
return;
}
text.move(x, y);
}
function on_mouse_rbtn_up(x, y) {
// if (buttons.buttons.stop.containsXY(x, y)) {
// fb.StopAfterCurrent = !fb.StopAfterCurrent;
// return true;
// }
return panel.rbtn_up(x, y, text);
}
function on_mouse_wheel(s) {
if (seekbar.wheel(s)) {
return;
}
text.wheel(s);
}
function on_paint(gr) {
panel.paint(gr);
text.paint(gr);
buttons.paint(gr);
// gr.FillRoundedRectangle(seekbar.x, seekbar.y, seekbar.w, seekbar.h, _scale(2), _scale(2), colours.slider_background);
// if (fb.IsPlaying) {
// var time_width = seekbar.x - _scale(12);
// gr.WriteText(tfo.playback_time.Eval(), font, colours.white, 0, bottom_y, time_width, _scale(12), 1, 2);
// gr.WriteText(tfo.length.Eval(), font, colours.white, seekbar.x + seekbar.w + _scale(12), bottom_y, time_width, _scale(12), 0, 2);
// if (fb.PlaybackLength > 0) {
// gr.FillEllipse(seekbar.x + seekbar.pos(), seekbar.y + _scale(3), _scale(6), _scale(6), colours.white);
// }
// }
}
function on_playback_order_changed() {
buttons.update();
window.Repaint();
}
function on_playback_dynamic_info_track(type) {
if (type == 0) text.metadb_changed();
else if (type == 1) albumart.metadb_changed();
}
function on_playback_new_track() {
panel.item_focus_change();
}
function on_playback_pause() {
text.refresh();
buttons.update();
window.Repaint();
}
function on_playback_seek() {
seekbar.playback_seek();
}
function on_playback_starting() {
buttons.update();
window.Repaint();
}
function on_playback_stop(reason) {
if (reason != 2) {
panel.item_focus_change();
}
buttons.update();
window.Repaint();
}
// function on_playback_time() {
// text.playback_time();
// window.RepaintRect(0, bottom_y, panel.w, panel.h - bottom_y);
// }
function on_playlist_items_added() {
text.refresh();
}
function on_playlist_items_removed() {
text.refresh();
}
function on_playlist_items_reordered() {
text.refresh();
}
function on_playlist_stop_after_current_changed() {
buttons.update();
window.Repaint();
}
function on_playlist_switch() {
on_item_focus_change();
}
function on_playlists_changed() {
text.refresh();
}
function on_size() {
panel.size();
text.size();
seekbar.x = _scale(60);
seekbar.y = panel.h - _scale(44);
seekbar.w = panel.w - (seekbar.x * 2);
seekbar.h = _scale(6);
bottom_y = seekbar.y - _scale(4);
buttons.update();
}
Great!!! Thanks eurekagliese ;D
var x = (panel.w - (bs * 7)) / 2
You have 8 buttons so that's why it is off centre. :D
And yay, the SVG parser which takes around 1.5MB (or 25%) of the overall DLL size is getting some use.
edit: you should not comment this out...
// function on_playback_time() {
// text.playback_time();
// window.RepaintRect(0, bottom_y, panel.w, panel.h - bottom_y);
// }
People customising their own text may want %playback_time% etc during playback. There is a toggle on the right click menu to turn per second updates on or off.
Thank you very much for the update and the guide @marc2k3
---
This is a composite image of an image from the foo_uie_webview thread, so I don't know. Sorry.
No worries, mate. With latest JSP update, we can also replicate it on a text display.
The script and image files with the PNG and SVG icons are available below.
In your foobar config folder, extract it to the images folder.
Just modify the link on script or the icons as needed.
(https://i.imgur.com/nnYUcGv.png)
// ==PREPROCESSOR==
// @name "Text Display + Album Art + Custom SVG and PNG Buttons"
// @author "marc2003"
// @import "%fb2k_component_path%helpers.txt"
// @import "%fb2k_component_path%samples\js\lodash.min.js"
// @import "%fb2k_component_path%samples\js\common.js"
// @import "%fb2k_component_path%samples\js\panel.js"
// @import "%fb2k_component_path%samples\js\albumart.js"
// @import "%fb2k_component_path%samples\js\text_display.js"
// @import "%fb2k_component_path%samples\js\seekbar.js"
// ==/PREPROCESSOR==
// https://jscript-panel.github.io/gallery/text-display/
//.svg files
var google = utils.LoadSVG(fb.ProfilePath + 'images\\google.svg');
var youtube = utils.LoadSVG(fb.ProfilePath + 'images\\youtube.svg');
var spotify = utils.LoadSVG(fb.ProfilePath + 'images\\spotify.svg');
var wikipedia = utils.LoadSVG(fb.ProfilePath + 'images\\wikipedia.svg');
var lastfm = utils.LoadSVG(fb.ProfilePath + 'images\\lastfm.svg');
var search = utils.LoadSVG(fb.ProfilePath + 'images\\search.svg');
var settings = utils.LoadSVG(fb.ProfilePath + 'images\\settings.svg');
//.png files
var discogs = utils.LoadImage(fb.ProfilePath + 'images\\discogs.png');
var tfo = {
artist: fb.TitleFormat('%artist%'),
title: fb.TitleFormat('%title%'),
// playback_time : fb.TitleFormat('[%playback_time%]'),
// length : fb.TitleFormat('$if2(%length%,LIVE)'),
}
var panel = new _panel({ custom_background : true });
var albumart = new _albumart(0, 0, 0, 0);
var text = new _text_display(LM, 0, 0, 0, true);
var seekbar = new _seekbar(0, 0, 0, 0);
var colours = {
slider_background : RGB(160, 160, 160),
white : RGB(255, 255, 255),
contrast : RGB(196, 30, 35),
};
var font = CreateFontString('Segoe UI', 12);
var buttons = new _buttons();
var bs = _scale(24);
var bottom_y = 0;
buttons.update = function () {
var x = (panel.w - (bs * 7)) / 2
var y = seekbar.y + _scale(12);
this.buttons.google = new _button(x, y, bs, bs, { img : google }, null, function () { utils.Run('https://www.google.com/search?tbm=isch&q=' + encodeURIComponent(tfo.artist.Eval() + " " + tfo.title.Eval())); }, 'Google');
this.buttons.youtube = new _button(x + bs, y, bs, bs, { img : youtube }, null, function () { utils.Run('http://www.youtube.com/results?search_query=' + encodeURIComponent(tfo.artist.Eval() + " " + tfo.title.Eval())); }, 'youtube');
this.buttons.spotify = new _button(x + (bs * 2), y, bs, bs, { img : spotify}, null, function () { utils.Run('https://open.spotify.com/search/' + encodeURIComponent(tfo.artist.Eval() + " " + tfo.title.Eval())); }, 'spotify');
this.buttons.wikipedia = new _button(x + (bs * 3), y, bs, bs, { img : wikipedia }, null, function () { utils.Run('http://en.wikipedia.org/wiki/Special:Search?search=' + encodeURIComponent(tfo.artist.Eval())); }, 'wikipedia');
this.buttons.lastfm = new _button(x + (bs * 4), y, bs, bs, { img : lastfm }, null, function () { utils.Run('https://www.last.fm/search?q=' + encodeURIComponent(tfo.artist.Eval())); }, 'lastfm');
this.buttons.discogs = new _button(x + (bs * 5), y, bs, bs, { img : discogs }, null, function () { utils.Run('http://www.discogs.com/search?q=' + encodeURIComponent(tfo.artist.Eval())); }, 'discogs');
this.buttons.search = new _button(x + (bs * 6), y, bs, bs, { img : search }, null, function () { fb.RunMainMenuCommand('Library/Search'); }, 'Library Search');
this.buttons.preferences = new _button(x + (bs * 7), y, bs, bs, { img : settings}, null, function () { fb.ShowPreferences(); }, 'Preferences');
}
panel.item_focus_change();
function on_colours_changed() {
panel.colours_changed();
text.refresh(true);
}
function on_font_changed() {
panel.font_changed();
text.refresh(true);
}
function on_item_focus_change() {
if (panel.selection.value == 0 && fb.IsPlaying) return;
panel.item_focus_change();
}
function on_metadb_changed(handles, fromhook) {
if (!fromhook) {
albumart.metadb_changed();
}
text.metadb_changed();
}
function on_mouse_lbtn_dblclk(x, y) {
if (albumart.img && albumart.containsXY(x, y)) {
panel.metadb.ShowAlbumArtViewer();
}
}
function on_mouse_lbtn_down(x, y) {
seekbar.lbtn_down(x, y);
}
function on_mouse_lbtn_up(x, y) {
if (seekbar.lbtn_up(x, y)) {
return;
}
if (buttons.lbtn_up(x, y)) {
return;
}
text.lbtn_up(x, y);
}
function on_mouse_leave() {
buttons.leave();
}
function on_mouse_move(x, y) {
window.SetCursor(buttons.buttons.google.containsXY(x, y) ? IDC_HAND
: buttons.buttons.youtube.containsXY(x, y) ? IDC_HAND
: buttons.buttons.spotify.containsXY(x, y) ? IDC_HAND
: buttons.buttons.wikipedia.containsXY(x, y) ? IDC_HAND
: buttons.buttons.lastfm.containsXY(x, y) ? IDC_HAND
: buttons.buttons.discogs.containsXY(x, y) ? IDC_HAND
: buttons.buttons.search.containsXY(x, y) ? IDC_HAND
: buttons.buttons.preferences.containsXY(x, y) ? IDC_HAND
: IDC_ARROW);
if (seekbar.move(x, y)) {
return;
}
if (buttons.move(x, y)) {
return;
}
text.move(x, y);
}
function on_mouse_rbtn_up(x, y) {
// if (buttons.buttons.stop.containsXY(x, y)) {
// fb.StopAfterCurrent = !fb.StopAfterCurrent;
// return true;
// }
return panel.rbtn_up(x, y, text);
}
function on_mouse_wheel(s) {
if (seekbar.wheel(s)) {
return;
}
text.wheel(s);
}
function on_paint(gr) {
panel.paint(gr);
text.paint(gr);
buttons.paint(gr);
// gr.FillRoundedRectangle(seekbar.x, seekbar.y, seekbar.w, seekbar.h, _scale(2), _scale(2), colours.slider_background);
// if (fb.IsPlaying) {
// var time_width = seekbar.x - _scale(12);
// gr.WriteText(tfo.playback_time.Eval(), font, colours.white, 0, bottom_y, time_width, _scale(12), 1, 2);
// gr.WriteText(tfo.length.Eval(), font, colours.white, seekbar.x + seekbar.w + _scale(12), bottom_y, time_width, _scale(12), 0, 2);
// if (fb.PlaybackLength > 0) {
// gr.FillEllipse(seekbar.x + seekbar.pos(), seekbar.y + _scale(3), _scale(6), _scale(6), colours.white);
// }
// }
}
function on_playback_order_changed() {
buttons.update();
window.Repaint();
}
function on_playback_dynamic_info_track(type) {
if (type == 0) text.metadb_changed();
else if (type == 1) albumart.metadb_changed();
}
function on_playback_new_track() {
panel.item_focus_change();
}
function on_playback_pause() {
text.refresh();
buttons.update();
window.Repaint();
}
function on_playback_seek() {
seekbar.playback_seek();
}
function on_playback_starting() {
buttons.update();
window.Repaint();
}
function on_playback_stop(reason) {
if (reason != 2) {
panel.item_focus_change();
}
buttons.update();
window.Repaint();
}
// function on_playback_time() {
// text.playback_time();
// window.RepaintRect(0, bottom_y, panel.w, panel.h - bottom_y);
// }
function on_playlist_items_added() {
text.refresh();
}
function on_playlist_items_removed() {
text.refresh();
}
function on_playlist_items_reordered() {
text.refresh();
}
function on_playlist_stop_after_current_changed() {
buttons.update();
window.Repaint();
}
function on_playlist_switch() {
on_item_focus_change();
}
function on_playlists_changed() {
text.refresh();
}
function on_size() {
panel.size();
text.size();
seekbar.x = _scale(60);
seekbar.y = panel.h - _scale(44);
seekbar.w = panel.w - (seekbar.x * 2);
seekbar.h = _scale(6);
bottom_y = seekbar.y - _scale(4);
buttons.update();
}
Logo discogs
https://postimg.cc/LJxJnRDQ
This removes a lot of dead code, fixes the button count and improves the search button to find all tracks by the current artist. I've also uncommented the code that broke per second updates.
// ==PREPROCESSOR==
// @name "Text Display + Album Art + Custom SVG and PNG Buttons"
// @author "marc2003 / eurekagliese"
// @import "%fb2k_component_path%helpers.txt"
// @import "%fb2k_component_path%samples\js\lodash.min.js"
// @import "%fb2k_component_path%samples\js\common.js"
// @import "%fb2k_component_path%samples\js\panel.js"
// @import "%fb2k_component_path%samples\js\albumart.js"
// @import "%fb2k_component_path%samples\js\text_display.js"
// ==/PREPROCESSOR==
// https://jscript-panel.github.io/gallery/text-display/
//.svg files
var google = utils.LoadSVG(fb.ProfilePath + 'images\\google.svg');
var youtube = utils.LoadSVG(fb.ProfilePath + 'images\\youtube.svg');
var spotify = utils.LoadSVG(fb.ProfilePath + 'images\\spotify.svg');
var wikipedia = utils.LoadSVG(fb.ProfilePath + 'images\\wikipedia.svg');
var lastfm = utils.LoadSVG(fb.ProfilePath + 'images\\lastfm.svg');
var search = utils.LoadSVG(fb.ProfilePath + 'images\\search.svg');
var settings = utils.LoadSVG(fb.ProfilePath + 'images\\settings.svg');
//.png files
var discogs = utils.LoadImage(fb.ProfilePath + 'images\\discogs.png');
var tfo = {
artist: fb.TitleFormat('%artist%'),
title: fb.TitleFormat('%title%'),
}
var panel = new _panel({ custom_background : true });
var albumart = new _albumart(0, 0, 0, 0);
var text = new _text_display(LM, 0, 0, 0, true);
var colours = {
white : RGB(255, 255, 255),
};
var font = CreateFontString('Segoe UI', 12);
var buttons = new _buttons();
var bs = _scale(24);
var bottom_y = 0;
buttons.update = function () {
var x = (panel.w - (bs * 8)) / 2
var y = bottom_y;
this.buttons.google = new _button(x, y, bs, bs, { img : google }, null, function () { utils.Run('https://www.google.com/search?tbm=isch&q=' + encodeURIComponent(tfo.artist.Eval() + " " + tfo.title.Eval())); }, 'Google');
this.buttons.youtube = new _button(x + bs, y, bs, bs, { img : youtube }, null, function () { utils.Run('http://www.youtube.com/results?search_query=' + encodeURIComponent(tfo.artist.Eval() + " " + tfo.title.Eval())); }, 'youtube');
this.buttons.spotify = new _button(x + (bs * 2), y, bs, bs, { img : spotify}, null, function () { utils.Run('https://open.spotify.com/search/' + encodeURIComponent(tfo.artist.Eval() + " " + tfo.title.Eval())); }, 'spotify');
this.buttons.wikipedia = new _button(x + (bs * 3), y, bs, bs, { img : wikipedia }, null, function () { utils.Run('http://en.wikipedia.org/wiki/Special:Search?search=' + encodeURIComponent(tfo.artist.Eval())); }, 'wikipedia');
this.buttons.lastfm = new _button(x + (bs * 4), y, bs, bs, { img : lastfm }, null, function () { utils.Run('https://www.last.fm/search?q=' + encodeURIComponent(tfo.artist.Eval())); }, 'lastfm');
this.buttons.discogs = new _button(x + (bs * 5), y, bs, bs, { img : discogs }, null, function () { utils.Run('http://www.discogs.com/search?q=' + encodeURIComponent(tfo.artist.Eval())); }, 'discogs');
this.buttons.search = new _button(x + (bs * 6), y, bs, bs, { img : search }, null, function () { fb.ShowLibrarySearchUI('artist IS ' + tfo.artist.Eval()); }, 'Search');
this.buttons.preferences = new _button(x + (bs * 7), y, bs, bs, { img : settings}, null, function () { fb.ShowPreferences(); }, 'Preferences');
}
panel.item_focus_change();
function on_colours_changed() {
panel.colours_changed();
text.refresh(true);
}
function on_font_changed() {
panel.font_changed();
text.refresh(true);
}
function on_item_focus_change() {
if (panel.selection.value == 0 && fb.IsPlaying) return;
panel.item_focus_change();
}
function on_metadb_changed(handles, fromhook) {
if (!fromhook) {
albumart.metadb_changed();
}
text.metadb_changed();
}
function on_mouse_lbtn_dblclk(x, y) {
if (albumart.img && albumart.containsXY(x, y)) {
panel.metadb.ShowAlbumArtViewer();
}
}
function on_mouse_lbtn_up(x, y) {
if (buttons.lbtn_up(x, y)) {
return;
}
text.lbtn_up(x, y);
}
function on_mouse_leave() {
buttons.leave();
}
function on_mouse_move(x, y) {
text.move(x, y);
buttons.move(x, y);
_.forEach(buttons.buttons, function (button) {
if (button.containsXY(x, y)) {
window.SetCursor(IDC_HAND);
return;
}
});
}
function on_mouse_rbtn_up(x, y) {
return panel.rbtn_up(x, y, text);
}
function on_mouse_wheel(s) {
if (seekbar.wheel(s)) {
return;
}
text.wheel(s);
}
function on_paint(gr) {
panel.paint(gr);
text.paint(gr);
buttons.paint(gr);
}
function on_playback_dynamic_info_track(type) {
if (type == 0) text.metadb_changed();
else if (type == 1) albumart.metadb_changed();
}
function on_playback_new_track() {
panel.item_focus_change();
}
function on_playback_pause() {
text.refresh();
buttons.update();
window.Repaint();
}
function on_playback_starting() {
buttons.update();
window.Repaint();
}
function on_playback_stop(reason) {
if (reason != 2) {
panel.item_focus_change();
}
buttons.update();
window.Repaint();
}
function on_playback_time() {
text.playback_time();
}
function on_playlist_items_added() {
text.refresh();
}
function on_playlist_items_removed() {
text.refresh();
}
function on_playlist_items_reordered() {
text.refresh();
}
function on_playlist_switch() {
on_item_focus_change();
}
function on_playlists_changed() {
text.refresh();
}
function on_size() {
panel.size();
text.size();
bottom_y = panel.h - _scale(36);
buttons.update();
}
edit: requires images from this post...
https://hydrogenaud.io/index.php/topic,110516.msg1048037.html#msg1048037
edit2: script edited to remove more dead callbacks
var x = (panel.w - (bs * 7)) / 2
You have 8 buttons so that's why it is off centre. :D
And yay, the SVG parser which takes around 1.5MB (or 25%) of the overall DLL size is getting some use.
edit: you should not comment this out...
// function on_playback_time() {
// text.playback_time();
// window.RepaintRect(0, bottom_y, panel.w, panel.h - bottom_y);
// }
People customising their own text may want %playback_time% etc during playback. There is a toggle on the right click menu to turn per second updates on or off.
Ah that's why it's off center.
I didn't know the SVG parser was that big.
Thanks again for the correction and updates Marc
(https://i.postimg.cc/Ffn93VY0/Immagine-2024-07-18-104742.png) (https://postimg.cc/Ffn93VY0)
If someone can add the url button, it's perfect, see the image on the left.
(https://i.postimg.cc/YL2KP4Lt/Immagine-2024-07-18-105229.png) (https://postimg.cc/YL2KP4Lt)
(https://i.postimg.cc/Ffn93VY0/Immagine-2024-07-18-104742.png) (https://postimg.cc/Ffn93VY0)
If someone can add the url button, it's perfect, see the image on the left.
(https://i.postimg.cc/YL2KP4Lt/Immagine-2024-07-18-105229.png) (https://postimg.cc/YL2KP4Lt)
Hi there, it seems your hosting image (postimg) flagged as Potential Security Issue, so the attached image are not shown.
However, I can see the image link when quoting your post, and paste it proxy sites to open it.
So, you are looking to open radio url link from the tag, perhaps you can try this.
var tfo = {
artist: fb.TitleFormat('%artist%'),
title: fb.TitleFormat('%title%'),
url: fb.TitleFormat('%url%'),
}
Add to the buttons.update
this.buttons.radio = new _button(x + (bs * 8), y, bs, bs, { img : settings}, null, function () { utils.Run(tfo.url.Eval()); }, tfo.url.Eval());
(https://i.postimg.cc/Ffn93VY0/Immagine-2024-07-18-104742.png) (https://postimg.cc/Ffn93VY0)
If someone can add the url button, it's perfect, see the image on the left.
(https://i.postimg.cc/YL2KP4Lt/Immagine-2024-07-18-105229.png) (https://postimg.cc/YL2KP4Lt)
Hi there, it seems your hosting image (postimg) flagged as Potential Security Issue, so the attached image are not shown.
However, I can see the image link when quoting your post, and paste it proxy sites to open it.
So, you are looking to open radio url link from the tag, perhaps you can try this.
var tfo = {
artist: fb.TitleFormat('%artist%'),
title: fb.TitleFormat('%title%'),
url: fb.TitleFormat('%url%'),
}
Add to the buttons.update
this.buttons.radio = new _button(x + (bs * 8), y, bs, bs, { img : settings}, null, function () { utils.Run(tfo.url.Eval()); }, tfo.url.Eval());
THX :D
(https://i.postimg.cc/0rq5gs6w/Immagine-2024-07-18-125838.png) (https://postimg.cc/0rq5gs6w)
@eurekagliese and @marc2k3
My desire became a reality. I had someone so knowledgeable help me.
I don't know how to thank them.
I'm so grateful.
(https://i.imgur.com/nrKWxK9.png)
@eurekagliese
To remove or add the blur effect?
Where can I download 3.5.7? Thanks.
@eurekagliese
To remove or add the blur effect?
Whoever does it himself does it for three:
albumart.js
Line 7
// blur_it = properties.albumart.enabled && properties.albumart_blur.enabled;
(https://i.postimg.cc/6yYL1ZVb/Immagine-2024-07-18-174441.png) (https://postimg.cc/6yYL1ZVb)
for Thumbs and Last.fm Bio + Images
thumbs.js
Line 112
// _drawImage(gr, this.blurred_images[this.image_index], 0, 0, panel.w, panel.h, image.crop, this.properties.blur_opacity.value);
Can we make thumbs with lyrics on top ?
Can we make thumbs with lyrics on top ?
Load lyrics and overlay it to the images? I don't think so.
Also, I don't think JSP is meant to be a lyric parser, but it would be wonderful addition if Marc had any plans for it.
As of now, perhaps Biography SMP plug-in or ESLyrics is what you looking for.
(https://i.imgur.com/lyUWdTk.jpeg)
(https://i.imgur.com/lZ2masR.jpeg)
Can we make thumbs with lyrics on top ?
Load lyrics and overlay it to the images? I don't think so.
Also, I don't think JSP is meant to be a lyric parser, but it would be wonderful addition if Marc had any plans for it.
As of now, perhaps Biography SMP plug-in or ESLyrics is what you looking for.
(https://i.imgur.com/lyUWdTk.jpeg)
(https://i.imgur.com/lZ2masR.jpeg)
Yes I know eslyrics and overs too . I made the LA NOIRE thème with it . Hope soon to share my new version of this theme .
Thanks anyway
Can we make thumbs with lyrics on top ?
Load lyrics and overlay it to the images? I don't think so.
Also, I don't think JSP is meant to be a lyric parser, but it would be wonderful addition if Marc had any plans for it.
As of now, perhaps Biography SMP plug-in or ESLyrics is what you looking for.
(https://i.imgur.com/lyUWdTk.jpeg)
(https://i.imgur.com/lZ2masR.jpeg)
could you share your UI js ? thanks
Can we make thumbs with lyrics on top ?
Load lyrics and overlay it to the images? I don't think so.
Also, I don't think JSP is meant to be a lyric parser, but it would be wonderful addition if Marc had any plans for it.
As of now, perhaps Biography SMP plug-in or ESLyrics is what you looking for.
(https://i.imgur.com/lyUWdTk.jpeg)
(https://i.imgur.com/lZ2masR.jpeg)
could you share your UI js ? thanks
Sure, here you go
Run Service Bar.
Text Display + Album Art + Run Service.
(https://i.postimg.cc/GHf7RtS3/Immagine-2024-07-19-112759.png) (https://postimg.cc/GHf7RtS3)
Where can I download 3.5.7? Thanks.
I only provide old versions when system requirements change. There is no change in 3.6.x
Did you read the warning on the download page. If you missed if, I'll link to it again,
https://github.com/jscript-panel/release/releases
It should only take a few seconds to fix any sript errors caused by the upgrade.
Where can I download 3.5.7? Thanks.
I only provide old versions when system requirements change. There is no change in 3.6.x
Did you read the warning on the download page. If you missed if, I'll link to it again,
https://github.com/jscript-panel/release/releases
It should only take a few seconds to fix any sript errors caused by the upgrade.
Thanks for the tips! I had undefinable problems with Last.fm Bio + Images on the first try with 3.6x - but it worked on the second try.
I particularly like the fact that the background adapts to the color of the images.
Thank you very much!
Thanks for the tips! I had undefinable problems with Last.fm Bio + Images on the first try with 3.6x - but it worked on the second try.
I particularly like the fact that the background adapts to the color of the images.
Thank you very much!
I just installed jscript panel 3.6.1; as far as I can see in Last.fm Bio+Images, the background remains black, there is no adaptation to the color of the images, and no changes when holding shift and scrolling the mouse wheel. Yes I did replace the sample.
I assume the change referred to in 3.5.7--"Update Thumbs sample so the brightness of the blurred background can be changed. Hold Shift and scroll your mouse wheel to adjust"--has been reverted in 3.6.1. Personally I'm fine with that; I assume MaFred must have been using a 3.6.0 version in the quote above.
The background colour effect in Last.fm Bio + Images is very subtle because a dark overlay is always drawn so the text is always readable. But if you can't see it, you might be blind. :/
And shift + scroll is only available in Thumbs and remains available in the latest version. Obviously that's only when Centre mode is enabled. All other modes cover the entire panel with the image so there is no blurred background to be seen.
Thanks for replying--I did some more "squinting" and you're right, the background tint effect is there, it is just as you say very subtle, not apparent at all on some, and I think my theme/spectrums distracted me. And OK that explains the mouse wheel too as I had confused "thumbs" and "images."
Updated with new services:
(https://i.postimg.cc/3kk8bBtw/Immagine-2024-07-21-123451.png) (https://postimg.cc/3kk8bBtw)
It's a great power-up. However, it would be helpful if you could change the name of the "image" folder. If other people also have the "image" folder, the same file name will be overwritten. You can do this by just editing the .txt file yourself, but please make it easy for everyone to understand. Thanks.
"image" → "ApacheReal" \profile\Apache
(https://i.imgur.com/bfBJE8J.png)
(https://i.imgur.com/tUz5jLp.png)
The sample Playback buttons + playback order are so great as always but how difficult would it be to add the random button to it also? having that would mean a lot to me and I assume others who use shuffle albums a lot as the random button essentially is the next album button
@DClaville
Is this different?
JScript Panel 3 3.6.1
"Playback buttons + playback order"
(https://i.imgur.com/soUgoLk.png)
Hi Ken yes thats the playback order set to random the random button I mean is the random button that's under playback in the menu
then the playback order is set to shuffle albums like this image then clicking the random button under playback controls jumps to the next album
this is what i mean sorry i could not take a screenshot of it as that closed the menu so.. phone pic lol
I tried adding this string after the other buttons.. but a piece of wet cardboard knows more about coding them I do and it didn't work
this.buttons.random = new _.button(panel.w - LM - (bs * 4.9), y, bs, bs, {normal : 'buttons\\shuffle_grey_min.png'}, function () { fb.Random(); }, 'Random');
this is what i mean sorry i could not take a screenshot of it as that closed the menu so.. phone pic lol
I tried adding this string after the other buttons.. but a piece of wet cardboard knows more about coding them I do and it didn't work
this.buttons.random = new _.button(panel.w - LM - (bs * 4.9), y, bs, bs, {normal : 'buttons\\shuffle_grey_min.png'}, function () { fb.Random(); }, 'Random');
Hi there,
Here's the code just modify the playback button order to just random button.
Just add your custom shuffle_grey_min.png file to the buttons folder in your foobar configuration folder.
// ==PREPROCESSOR==
// @name "Playback Buttons + Random"
// @author "marc2003"
// @import "%fb2k_component_path%helpers.txt"
// @import "%fb2k_component_path%samples\js\lodash.min.js"
// @import "%fb2k_component_path%samples\js\common.js"
// @import "%fb2k_component_path%samples\js\panel.js"
// ==/PREPROCESSOR==
var colours = {
buttons : RGB(255, 255, 255),
background : RGB(30, 30, 30),
contrast : RGB(196, 30, 35),
};
//////////////////////////////////////////////////////////////
var panel = new _panel();
var buttons = new _buttons();
var bs = _scale(24);
var random_img = utils.LoadImage(fb.ProfilePath + 'buttons\\shuffle_grey_min.png');
buttons.update = function () {
var x = ((panel.w - bs * 6) / 2);
var y = Math.round((panel.h - bs) / 2);
this.buttons.stop = new _button(x, y, bs, bs, { char : chars.stop, colour:fb.StopAfterCurrent ? colours.contrast : colours.buttons}, null, function () { fb.Stop(); }, 'Stop');
this.buttons.previous = new _button(x + bs, y, bs, bs, { char : chars.prev, colour:colours.buttons }, null, function () { fb.Prev(); }, 'Previous');
this.buttons.play = new _button(x + (bs * 2), y, bs, bs, { char : !fb.IsPlaying || fb.IsPaused ? chars.play : chars.pause, colour:colours.buttons}, null, function () { fb.PlayOrPause(); }, !fb.IsPlaying || fb.IsPaused ? 'Play' : 'Pause');
this.buttons.next = new _button(x + (bs * 3), y, bs, bs, { char : chars.next, colour:colours.buttons }, null, function () { fb.Next(); }, 'Next');
this.buttons.random = new _button(x + (bs * 5) - 2, y - 2, bs + 4, bs + 4, { img : random_img }, null, function () { fb.Random(); }, 'Random');
}
function on_mouse_lbtn_up(x, y) {
buttons.lbtn_up(x, y);
}
function on_mouse_leave() {
buttons.leave();
}
function on_mouse_move(x, y) {
buttons.move(x, y);
}
function on_mouse_rbtn_up(x, y) {
if (buttons.buttons.stop.containsXY(x, y)) {
fb.StopAfterCurrent = !fb.StopAfterCurrent;
return true;
}
return panel.rbtn_up(x, y);
}
function on_paint(gr) {
gr.Clear(colours.background);
buttons.paint(gr);
}
function on_playback_order_changed() {
buttons.update();
window.Repaint();
}
function on_playback_pause() {
buttons.update();
window.Repaint();
}
function on_playback_starting() {
buttons.update();
window.Repaint();
}
function on_playback_stop() {
buttons.update();
window.Repaint();
}
function on_playlist_stop_after_current_changed() {
buttons.update();
window.Repaint();
}
function on_size() {
panel.size();
buttons.update();
}
@eurekagliese that is fantastic thank you so much!
I don't actually have that image or any image yet (I copied that string from an old post on this forum lol) I am hoping to use an icon like the other buttons do
I got it working now tho with the next icon, only need to adjust the placement and find a new icon I guess I can find that in the font isn't that where the other icons come from?
Cheers
All the font chars I use are from this page...
https://learn.microsoft.com/en-us/windows/apps/design/style/segoe-fluent-icons-font
If you look at the very first one here...
https://learn.microsoft.com/en-us/windows/apps/design/style/segoe-fluent-icons-font#pua-e700-e900
e700
To use that in a script, you'd write...
{ char : '\ue700', colour : colours.buttons }
You can colour each button independently if you want to with
RGB(255, 0, 0) or whatever.
{ char : '\ue700', colour : RGB(255, 0, 0) }
@eurekagliese
that is fantastic thank you so much!
I don't actually have that image or any image yet (I copied that string from an old post on this forum lol) I am hoping to use an icon like the other buttons do
I got it working now tho with the next icon, only need to adjust the placement and find a new icon I guess I can find that in the font isn't that where the other icons come from?
Cheers
Ah I see, you can use the random button like the code below or choose new one from the list that Marc gave.
this.buttons.random = new _button(x + (bs * 5) - 2, y - 2, bs + 4, bs + 4, { char : chars.random, colour:colours.buttons }, null, function () { fb.Random(); }, 'Random');
Thank you Marc big help I was looking in Charactermap and that shit is not optimized for 4K monitors its so tiny Microsoft much not have updated that in decades much better view on that website
cheers guys big help as always, enjoy your sunday
Edit:
EYY! now I even figured out how to change the playback order icon to the same color as the others guess I've leveled up to the coding skills of dry cardboard now from wet
C
@eurekagliese
that is fantastic thank you so much!
I don't actually have that image or any image yet (I copied that string from an old post on this forum lol) I am hoping to use an icon like the other buttons do
I got it working now tho with the next icon, only need to adjust the placement and find a new icon I guess I can find that in the font isn't that where the other icons come from?
Cheers
Ah I see, you can use the random button like the code below or choose new one from the list that Marc gave.
this.buttons.random = new _button(x + (bs * 5) - 2, y - 2, bs + 4, bs + 4, { char : chars.random, colour:colours.buttons }, null, function () { fb.Random(); }, 'Random');
could you share your Track Info + Seekbar + Buttons + Volume.js style ? like your button style
C@eurekagliese
that is fantastic thank you so much!
I don't actually have that image or any image yet (I copied that string from an old post on this forum lol) I am hoping to use an icon like the other buttons do
I got it working now tho with the next icon, only need to adjust the placement and find a new icon I guess I can find that in the font isn't that where the other icons come from?
Cheers
Ah I see, you can use the random button like the code below or choose new one from the list that Marc gave.
this.buttons.random = new _button(x + (bs * 5) - 2, y - 2, bs + 4, bs + 4, { char : chars.random, colour:colours.buttons }, null, function () { fb.Random(); }, 'Random');
could you share your Track Info + Seekbar + Buttons + Volume.js style ? like your button style
I already replied to you in previous page mate ;)
https://hydrogenaud.io/index.php/topic,110516.msg1048069.html#msg1048069
Sure here you go Jack but i use only buttons and a separate volume panel
EDIT: Oh you didn't mean me? sorry.
Buttons
// ==PREPROCESSOR==
// @name "Playback Buttons + PBO"
// @author "marc2003"
// @import "%fb2k_component_path%helpers.txt"
// @import "%fb2k_component_path%samples\js\lodash.min.js"
// @import "%fb2k_component_path%samples\js\common.js"
// @import "%fb2k_component_path%samples\js\panel.js"
// ==/PREPROCESSOR==
var colours = {
buttons : RGB(255, 128, 0),
background : RGB(17, 17, 17),
contrast : RGB(255, 128, 0),
};
//////////////////////////////////////////////////////////////
var panel = new _panel();
var buttons = new _buttons();
var bs = _scale(48);
var pbo_chars = [chars.repeat_off, chars.repeat_all, chars.repeat_one, chars.random, chars.shuffle, chars.album, chars.folder];
var pbo_names = plman.GetPlaybackOrders().toArray();
buttons.update = function () {
var x = ((panel.w - bs * 6) / 2);
var y = Math.round((panel.h - bs) / 2);
this.buttons.stop = new _button(x, y, bs, bs, { char : chars.stop, colour:fb.StopAfterCurrent ? colours.contrast : colours.buttons}, null, function () { fb.Stop(); }, 'Stop');
this.buttons.previous = new _button(x + bs, y, bs, bs, { char : chars.prev, colour:colours.buttons }, null, function () { fb.Prev(); }, 'Previous');
this.buttons.play = new _button(x + (bs * 2), y, bs, bs, { char : !fb.IsPlaying || fb.IsPaused ? chars.play : chars.pause, colour:colours.buttons}, null, function () { fb.PlayOrPause(); }, !fb.IsPlaying || fb.IsPaused ? 'Play' : 'Pause');
this.buttons.next = new _button(x + (bs * 3), y, bs, bs, { char : chars.next, colour:colours.buttons }, null, function () { fb.Next(); }, 'Next');
this.buttons.random = new _button(x + (bs * 4) + 50, y - 2, bs + 4, bs + 4, { char : '\ue8b6', colour:colours.buttons }, null, function () { fb.Random(); }, 'Random');
var pbo = plman.PlaybackOrder;
this.buttons.pbo = new _button(x + (bs * 5) + 100, y - 2, bs + 4, bs + 4, { char : pbo_chars[pbo], colour: pbo == 0 ? setAlpha(colours.buttons, 60) : colours.contrast }, null, function () { pbo >= pbo_chars.length - 1 ? plman.PlaybackOrder = 0 : plman.PlaybackOrder++ }, 'Playback Order: ' + pbo_names[pbo]);
}
function on_mouse_lbtn_up(x, y) {
buttons.lbtn_up(x, y);
}
function on_mouse_leave() {
buttons.leave();
}
function on_mouse_move(x, y) {
buttons.move(x, y);
}
function on_mouse_rbtn_up(x, y) {
if (buttons.buttons.stop.containsXY(x, y)) {
fb.StopAfterCurrent = !fb.StopAfterCurrent;
return true;
}
return panel.rbtn_up(x, y);
}
function on_paint(gr) {
gr.Clear(colours.background);
buttons.paint(gr);
}
function on_playback_order_changed() {
buttons.update();
window.Repaint();
}
function on_playback_pause() {
buttons.update();
window.Repaint();
}
function on_playback_starting() {
buttons.update();
window.Repaint();
}
function on_playback_stop() {
buttons.update();
window.Repaint();
}
function on_playlist_stop_after_current_changed() {
buttons.update();
window.Repaint();
}
function on_size() {
panel.size();
buttons.update();
}
volume;
// ==PREPROCESSOR==
// @name "Volume + Text"
// @author "marc2003"
// @import "%fb2k_component_path%helpers.txt"
// ==/PREPROCESSOR==
// name, pixels, font_weight (400 = normal, 700 = bold)
var font_string = CreateFontString("Segoe UI", 42, 400);
var g_drag = 0;
var ww = 0, wh = 0;
function on_size() {
ww = window.Width;
wh = window.Height;
}
function on_paint(gr) {
var volume = fb.Volume;
var pos = ww * vol2pos(volume);
var txt = volume.toFixed(2) + 'dB';
FillGradientRectangle(gr, 0, 0, pos, wh, 0, RGB(17, 17, 17), RGB(255, 128, 0));
FillGradientRectangle(gr, pos, 0, ww - pos, wh, 0, RGB(17, 17, 17), RGB(17, 17, 17));
gr.WriteText(txt, font_string, RGB(201, 201, 201), -7, 0, ww, wh, 2, 2);
gr.DrawRectangle(0, 0, ww - 1, wh - 1, 1.0, RGB(150, 150, 150));
}
function on_mouse_lbtn_down(x, y) {
g_drag = 1;
}
function on_mouse_lbtn_up(x, y) {
on_mouse_move(x, y);
g_drag = 0;
}
function on_mouse_move(x, y) {
if (g_drag) {
var pos = x < 0 ? 0 : x > ww ? 1 : x / ww;
fb.Volume = pos2vol(pos);
}
}
function on_mouse_wheel(delta) {
if (delta > 0)
fb.VolumeUp();
else
fb.VolumeDown();
}
function on_volume_change(val) {
window.Repaint();
}
I removed the background for the beatport icon/button.
Whenever dealing with website logos, I'd look for SVG instead.
https://support.beatport.com/hc/en-us/articles/4412316336404-Beatport-Logos-and-Images
Updated with new services:
(https://i.postimg.cc/3kk8bBtw/Immagine-2024-07-21-123451.png) (https://postimg.cc/3kk8bBtw)
Thanks !
Sure here you go Jack but i use only buttons and a separate volume panel
EDIT: Oh you didn't mean me? sorry.
Buttons
// ==PREPROCESSOR==
// @name "Playback Buttons + PBO"
// @author "marc2003"
// @import "%fb2k_component_path%helpers.txt"
// @import "%fb2k_component_path%samples\js\lodash.min.js"
// @import "%fb2k_component_path%samples\js\common.js"
// @import "%fb2k_component_path%samples\js\panel.js"
// ==/PREPROCESSOR==
var colours = {
buttons : RGB(255, 128, 0),
background : RGB(17, 17, 17),
contrast : RGB(255, 128, 0),
};
//////////////////////////////////////////////////////////////
var panel = new _panel();
var buttons = new _buttons();
var bs = _scale(48);
var pbo_chars = [chars.repeat_off, chars.repeat_all, chars.repeat_one, chars.random, chars.shuffle, chars.album, chars.folder];
var pbo_names = plman.GetPlaybackOrders().toArray();
buttons.update = function () {
var x = ((panel.w - bs * 6) / 2);
var y = Math.round((panel.h - bs) / 2);
this.buttons.stop = new _button(x, y, bs, bs, { char : chars.stop, colour:fb.StopAfterCurrent ? colours.contrast : colours.buttons}, null, function () { fb.Stop(); }, 'Stop');
this.buttons.previous = new _button(x + bs, y, bs, bs, { char : chars.prev, colour:colours.buttons }, null, function () { fb.Prev(); }, 'Previous');
this.buttons.play = new _button(x + (bs * 2), y, bs, bs, { char : !fb.IsPlaying || fb.IsPaused ? chars.play : chars.pause, colour:colours.buttons}, null, function () { fb.PlayOrPause(); }, !fb.IsPlaying || fb.IsPaused ? 'Play' : 'Pause');
this.buttons.next = new _button(x + (bs * 3), y, bs, bs, { char : chars.next, colour:colours.buttons }, null, function () { fb.Next(); }, 'Next');
this.buttons.random = new _button(x + (bs * 4) + 50, y - 2, bs + 4, bs + 4, { char : '\ue8b6', colour:colours.buttons }, null, function () { fb.Random(); }, 'Random');
var pbo = plman.PlaybackOrder;
this.buttons.pbo = new _button(x + (bs * 5) + 100, y - 2, bs + 4, bs + 4, { char : pbo_chars[pbo], colour: pbo == 0 ? setAlpha(colours.buttons, 60) : colours.contrast }, null, function () { pbo >= pbo_chars.length - 1 ? plman.PlaybackOrder = 0 : plman.PlaybackOrder++ }, 'Playback Order: ' + pbo_names[pbo]);
}
function on_mouse_lbtn_up(x, y) {
buttons.lbtn_up(x, y);
}
function on_mouse_leave() {
buttons.leave();
}
function on_mouse_move(x, y) {
buttons.move(x, y);
}
function on_mouse_rbtn_up(x, y) {
if (buttons.buttons.stop.containsXY(x, y)) {
fb.StopAfterCurrent = !fb.StopAfterCurrent;
return true;
}
return panel.rbtn_up(x, y);
}
function on_paint(gr) {
gr.Clear(colours.background);
buttons.paint(gr);
}
function on_playback_order_changed() {
buttons.update();
window.Repaint();
}
function on_playback_pause() {
buttons.update();
window.Repaint();
}
function on_playback_starting() {
buttons.update();
window.Repaint();
}
function on_playback_stop() {
buttons.update();
window.Repaint();
}
function on_playlist_stop_after_current_changed() {
buttons.update();
window.Repaint();
}
function on_size() {
panel.size();
buttons.update();
}
volume;
// ==PREPROCESSOR==
// @name "Volume + Text"
// @author "marc2003"
// @import "%fb2k_component_path%helpers.txt"
// ==/PREPROCESSOR==
// name, pixels, font_weight (400 = normal, 700 = bold)
var font_string = CreateFontString("Segoe UI", 42, 400);
var g_drag = 0;
var ww = 0, wh = 0;
function on_size() {
ww = window.Width;
wh = window.Height;
}
function on_paint(gr) {
var volume = fb.Volume;
var pos = ww * vol2pos(volume);
var txt = volume.toFixed(2) + 'dB';
FillGradientRectangle(gr, 0, 0, pos, wh, 0, RGB(17, 17, 17), RGB(255, 128, 0));
FillGradientRectangle(gr, pos, 0, ww - pos, wh, 0, RGB(17, 17, 17), RGB(17, 17, 17));
gr.WriteText(txt, font_string, RGB(201, 201, 201), -7, 0, ww, wh, 2, 2);
gr.DrawRectangle(0, 0, ww - 1, wh - 1, 1.0, RGB(150, 150, 150));
}
function on_mouse_lbtn_down(x, y) {
g_drag = 1;
}
function on_mouse_lbtn_up(x, y) {
on_mouse_move(x, y);
g_drag = 0;
}
function on_mouse_move(x, y) {
if (g_drag) {
var pos = x < 0 ? 0 : x > ww ? 1 : x / ww;
fb.Volume = pos2vol(pos);
}
}
function on_mouse_wheel(delta) {
if (delta > 0)
fb.VolumeUp();
else
fb.VolumeDown();
}
function on_volume_change(val) {
window.Repaint();
}
great ,thanks
Sure here you go Jack but i use only buttons and a separate volume panel
EDIT: Oh you didn't mean me? sorry.
Apparently, it wasn't intended for me. :-[ :)
Hi all,
I have moved to foobar2000 64bit to extend the memory beyond 4GB, this leaves llot of plugins behind.
To overcome, i have to recourse to JScript Panel3 and, therefore, ported/modified some scripts from others.
It seems, someone may have the same things while struggling with 64bit, i would like to share these scripts as attached.
last but not least, sorry original authors, especially Marc2003, Br3tt among others for "destroying" their beauty full codes.
you are free to use and make any changes as long as retain original author names.
[due to limitation, i may have little resource to react to this post.]
/*------------ [JScript Panel 3] 64bit scripts -----------------*/
// date: 03PM25 22Jul24
// viking, vnav.vn
Credit to original authors' scripts: Marc2003, marc2k3, Iprad, Br3tt aka Falstaff, eurekagliese, TT, Jul23, Hunter.
//system test:
- Windows 11, screen : FullHD, scale 150%
- foobar2000 64bit, preview 7jul24
- foobar200 Default UI (CUI should be fine).
- font : as listed in folder [font], of which [Segoe Fluent Icons] maybe already installed under Windows 11.
//dependencies:
- latest 64bit components and exe files as in [user-components-x64] folder, including JScript Panel 3 [https://github.com/jscript-panel/release/releases] - latest version is 3.6.1
// note: files were deleted on purpose to mitigate risk, if any, during transfer over network
- to enable youtube view, download: yt-dl.exe from GitHub [https://github.com/yt-dlp/yt-dlp].
- to enable spectrum analysis, download : spek.exe [https://github.com/alexkay/spek]
//pre-install:
- download and install foobar2000 64bit, latest version as of Jul24 (2.1.5).
- unzip file into foobar2000 64bit root folder.
- download and install/copy components.
- download exe files (to enable youtube, spectrum checking)
- install fonts (if any).
//install JScript Panel 3 (@Marc2003) scripts:
- under DUI.
- enable edit mod
- insert [JScript Panel 3] panel.
- copy script from [foobar2000\skins\viking\scripts\jsp3] folder and paste into [JScript Panel 3] panel.
- copy script [foobar2000\skins\viking\scripts\jsp3_lib\vnav_mod\jsplaylist_main.js] and paste into [JScript Panel 3] panel.
- copy script [foobar2000\skins\viking\scripts\jsp3_lib\vnav_mod\jssb.js] and paste into [JScript Panel 3] panel.
- Apply.
/*------------------------*/
Script detail: (alphabet sort)
Script { name, original author (idea), original source, comment}
I. folder : foobar2000\skins\viking\scripts\jsp3_lib\vnav_mod
------------------------------------------------
//1- name : jssb.js,
original author (idea): Br3tt aka Falstaff [enhanced, tuned by Marc2003]
original source : Smooth Browser
comment: /* modification */
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artworks located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
# resize all artworks as thumbnails to speed up the whole.
# [folder structure] library browsing.
//2- name : jsplaylist_main.js,
original author (idea): Br3tt aka Falstaff [enhanced, tuned by Marc2003]
original source : JS Playlist.
comment: /* modification */
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artworks located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
II. folder : foobar2000\skins\viking\scripts\jsp3
------------------------------------
//1- name : {deployed} album_art [brute-force search],
original author (idea): Marc2003
original source : thumbs and artwork script
comment: /* modification */
+ main features added:
# get artworks from local and lastfm at the same time.
# brute-force searching for artworks located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file, and absolute folder (via panel property).
# resize and cache all artworks as thumbnailsto speed up the whole.
# resize and save BIG artworks under and per album.
# view origial artwoks (ensure quality)
# background : as default image all per [all/1st] artworks
# second artist artworks download (via [{deployed} artwork download by artist from lastfm.txt] script)
+ limit: loading images are not asynced.
//2- name : {deployed} album_art [properties],
original author (idea): Marc2003
original source : Text Display
comment: /* modification */
+ main features added:
# context menu : more functions
# buttons : 4 positions, user-defined coord x,y (via property)
# youtube: download
//3- name : {deployed} analog clock,
original author (idea): Hunter
original source :
comment: /* modification */
+ ported to JScript Panel 3
//4- name : {deployed} control bar,
original author (idea): marc2k3 coded, eurekagliese enhanced
original source :
comment: /* modification */
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artwork located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
//5- name : {deployed} cover flow,
original author (idea): Br3tt aka Falstaff
original source :
comment: /* modification */
+ ported to JScript Panel 3
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artwork located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
//6- name : {deployed} lyrics download manager,
original author (idea):
original source :
comment: /* coded */
+ main features:
# download lyrics via Google host.
# get lyrics translated online by Google site
+ limit: async lyrics only.
//7- name : {deployed} TechnicsRSBX_iprad,
original author (idea): Iprad
original source :
comment: /* coded */
+ ported to JScript Panel 3
+ main features added:
# pseudo - VU Analog Meter. (wish list: JScript Panel 3, fb.peakLeft, fb.pakRight . . . properties )
//8- name : {deployed} tree explorer,
original author (idea): Br3tt aka Falstaff
original source :
comment: /* coded */
+ ported to JScript Panel 3
//9- name : {deployed} tree explorer,
original author (idea): Br3tt aka Falstaff
original source :
comment: /* coded */
+ ported to JScript Panel 3
note: images cached are all located under [foobar2000\$recycle.bin] folder, per respective components, panels.
/*/ Music can bring happiness, let it on. /*/
// EOF
Changes:
More accurate searches where possible for artist+title.
Full support for Text Display.
Added variant for reduced layout.
Text Display + Album Art - Text Right + Run Service
(https://i.postimg.cc/N9NcVWp1/Immagine-2024-07-23-133905.png) (https://postimg.cc/N9NcVWp1)
Text Display + Album Art + Run Service
(https://i.postimg.cc/jC5KNSSv/Screenshot-2024-07-23-120324.png) (https://postimg.cc/jC5KNSSv)
(https://i.postimg.cc/5Q6VMnRD/Screenshot-2024-07-23-120408.png) (https://postimg.cc/5Q6VMnRD)
Run Service Bar
(https://i.postimg.cc/t7HvQrL6/Immagine-2024-07-23-134254.png) (https://postimg.cc/t7HvQrL6)
Text Display + Album Art + Run Service.txt 2024-07-23:
Text overlaps icon. This is not a problem in 07-21.
foobar2000 v2.1.5 64-bit
Thanks.
(https://i.imgur.com/TXNkzKT.png)
Text Display + Album Art + Run Service.txt 2024-07-23:
Text overlaps icon. This is not a problem in 07-21.
foobar2000 v2.1.5 64-bit
Thanks.
(https://i.imgur.com/TXNkzKT.png)
I don't know if automatic adaptation is possible depending on your panel.
To overcome the overlap between the text and the buttons, the simplest solution is to reduce the info to custom text and add more lines $crlf() :
$font(Segoe UI,24,700)
[%title%]
$crlf()
$font(Segoe UI,20)
[%artist%]
$crlf()
$font(Segoe UI,16)
[%album% '('%date%')']
$crlf()
$crlf()
> To overcome the overlap between the text and the buttons, the simplest solution is to reduce the info to custom text:
Right-clicking and entering text via Custom text... is no longer useful.
As mentioned above, there was no problem with 07-21.
Reply #1551
https://hydrogenaud.io/index.php/topic,110516.msg1048117.html#msg1048117
Hi all,
I have moved to foobar2000 64bit to extend the memory beyond 4GB, this leaves llot of plugins behind.
To overcome, i have to recourse to JScript Panel3 and, therefore, ported/modified some scripts from others.
It seems, someone may have the same things while struggling with 64bit, i would like to share these scripts as attached.
last but not least, sorry original authors, especially Marc2003, Br3tt among others for "destroying" their beauty full codes.
you are free to use and make any changes as long as retain original author names.
[due to limitation, i may have little resource to react to this post.]
/*------------ [JScript Panel 3] 64bit scripts -----------------*/
// date: 03PM25 22Jul24
// viking, vnav.vn
Credit to original authors' scripts: Marc2003, marc2k3, Iprad, Br3tt aka Falstaff, eurekagliese, TT, Jul23, Hunter.
//system test:
- Windows 11, screen : FullHD, scale 150%
- foobar2000 64bit, preview 7jul24
- foobar200 Default UI (CUI should be fine).
- font : as listed in folder [font], of which [Segoe Fluent Icons] maybe already installed under Windows 11.
//dependencies:
- latest 64bit components and exe files as in [user-components-x64] folder, including JScript Panel 3 [https://github.com/jscript-panel/release/releases] - latest version is 3.6.1
// note: files were deleted on purpose to mitigate risk, if any, during transfer over network
- to enable youtube view, download: yt-dl.exe from GitHub [https://github.com/yt-dlp/yt-dlp].
- to enable spectrum analysis, download : spek.exe [https://github.com/alexkay/spek]
//pre-install:
- download and install foobar2000 64bit, latest version as of Jul24 (2.1.5).
- unzip file into foobar2000 64bit root folder.
- download and install/copy components.
- download exe files (to enable youtube, spectrum checking)
- install fonts (if any).
//install JScript Panel 3 (@Marc2003) scripts:
- under DUI.
- enable edit mod
- insert [JScript Panel 3] panel.
- copy script from [foobar2000\skins\viking\scripts\jsp3] folder and paste into [JScript Panel 3] panel.
- copy script [foobar2000\skins\viking\scripts\jsp3_lib\vnav_mod\jsplaylist_main.js] and paste into [JScript Panel 3] panel.
- copy script [foobar2000\skins\viking\scripts\jsp3_lib\vnav_mod\jssb.js] and paste into [JScript Panel 3] panel.
- Apply.
/*------------------------*/
Script detail: (alphabet sort)
Script { name, original author (idea), original source, comment}
I. folder : foobar2000\skins\viking\scripts\jsp3_lib\vnav_mod
------------------------------------------------
//1- name : jssb.js,
original author (idea): Br3tt aka Falstaff [enhanced, tuned by Marc2003]
original source : Smooth Browser
comment: /* modification */
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artworks located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
# resize all artworks as thumbnails to speed up the whole.
# [folder structure] library browsing.
//2- name : jsplaylist_main.js,
original author (idea): Br3tt aka Falstaff [enhanced, tuned by Marc2003]
original source : JS Playlist.
comment: /* modification */
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artworks located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
II. folder : foobar2000\skins\viking\scripts\jsp3
------------------------------------
//1- name : {deployed} album_art [brute-force search],
original author (idea): Marc2003
original source : thumbs and artwork script
comment: /* modification */
+ main features added:
# get artworks from local and lastfm at the same time.
# brute-force searching for artworks located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file, and absolute folder (via panel property).
# resize and cache all artworks as thumbnailsto speed up the whole.
# resize and save BIG artworks under and per album.
# view origial artwoks (ensure quality)
# background : as default image all per [all/1st] artworks
# second artist artworks download (via [{deployed} artwork download by artist from lastfm.txt] script)
+ limit: loading images are not asynced.
//2- name : {deployed} album_art [properties],
original author (idea): Marc2003
original source : Text Display
comment: /* modification */
+ main features added:
# context menu : more functions
# buttons : 4 positions, user-defined coord x,y (via property)
# youtube: download
//3- name : {deployed} analog clock,
original author (idea): Hunter
original source :
comment: /* modification */
+ ported to JScript Panel 3
//4- name : {deployed} control bar,
original author (idea): marc2k3 coded, eurekagliese enhanced
original source :
comment: /* modification */
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artwork located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
//5- name : {deployed} cover flow,
original author (idea): Br3tt aka Falstaff
original source :
comment: /* modification */
+ ported to JScript Panel 3
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artwork located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
//6- name : {deployed} lyrics download manager,
original author (idea):
original source :
comment: /* coded */
+ main features:
# download lyrics via Google host.
# get lyrics translated online by Google site
+ limit: async lyrics only.
//7- name : {deployed} TechnicsRSBX_iprad,
original author (idea): Iprad
original source :
comment: /* coded */
+ ported to JScript Panel 3
+ main features added:
# pseudo - VU Analog Meter. (wish list: JScript Panel 3, fb.peakLeft, fb.pakRight . . . properties )
//8- name : {deployed} tree explorer,
original author (idea): Br3tt aka Falstaff
original source :
comment: /* coded */
+ ported to JScript Panel 3
//9- name : {deployed} tree explorer,
original author (idea): Br3tt aka Falstaff
original source :
comment: /* coded */
+ ported to JScript Panel 3
note: images cached are all located under [foobar2000\$recycle.bin] folder, per respective components, panels.
/*/ Music can bring happiness, let it on. /*/
// EOF
Nice post, just a suggestion, perhaps it would be better if you also include a screenshot.
> To overcome the overlap between the text and the buttons, the simplest solution is to reduce the info to custom text:
Right-clicking and entering text via Custom text... is no longer useful.
As mentioned above, there was no problem with 07-21.
Reply #1551
https://hydrogenaud.io/index.php/topic,110516.msg1048117.html#msg1048117
profile\Apache\Run Service\buttons
profile\Apache\Run Service\js
JS3 - Configure - Tools - Import profile\Apache\Run Service\js
Text Display + Album Art + Run Service
Text Display + Album Art - Text Right + Run Service
Run Service Bar
@ApacheReal
It doesn't solve my problem.
I prepared a new JSP3 Panel and tested it.
Custom text... : Default
(https://i.imgur.com/XPHbaIt.png)
@ApacheReal
It doesn't solve my problem.
Custom text... : Default
(https://i.imgur.com/XPHbaIt.png)
Custom text last lines:
$crlf()
$crlf()
$crlf()
$crlf()
(https://i.postimg.cc/p9t3v7J5/Immagine-2024-07-23-154817.png) (https://postimg.cc/p9t3v7J5)
$crlf()
$crlf()
(https://i.postimg.cc/CnFqVFzr/Immagine-2024-07-23-155243.png) (https://postimg.cc/CnFqVFzr)
$crlf()
$crlf()
$crlf()
$crlf()
$crlf()
$crlf()
$crlf()
$crlf()
(https://i.postimg.cc/S2LM5XNz/Immagine-2024-07-23-155316.png) (https://postimg.cc/S2LM5XNz)
@ApacheReal
Hahaha, I'll stick with this for now.
Thanks for changing the folder name.
@ilovefb2k
I appreciate your work
Reply #1570
https://hydrogenaud.io/index.php/topic,110516.msg1048177.html#msg1048177
However, there is a script that cannot be displayed and I am struggling with it.
{deployed} album_art [brute-force search].txt
JSP3 Cover Panel (64bit DUI)
Thumbs art mode > Circular
Edit properties > 2K3.THUMB.PX > 150
(https://i.imgur.com/Rz7LpLI.png)
Albumart and Thumbs Isn't the scroll upside down?
Hi Air Ken,
You mean script "{deployed} album_art [cd-vinyl].txt" !?
This script from and @Jul23 as stated, and we also need some images from TT (TT-ReBORN.Georgia-ReBORN) to apply CD/Vinyl mask.
As such, i was hesitant to enclose them with the early post.
Attached is these images in their folder structure. we can unzip and copy them into [foobar2000] root folder and the script should be compiled without error.
Credit goes to Jul23, TT for their hard work in creating beautiful CD/vinyl images.
Artwork is randomly tilted.
Cheer.
note: as i am not sure about IP in other countries, whether or not some artworks were under public domain or not, i can not make any screenshot. sorry.
I think of some pseudo screenshots.
It is weir that my web browser usually get stuck (banned) accessing this site.
@ilovefb2k
Thank you for your reply.
This is what I'm using.
{deployed} album_art [brute-force search].txt
\profile\skins\viking\scripts\jsp3\{deployed} album_art [brute-force search].txt
JSP3 Cover Panel (64bit DUI)
@ilovefb2k
Thank you for your reply.
This is what I'm using.
{deployed} album_art [brute-force search].txt
\profile\skins\viking\scripts\jsp3\{deployed} album_art [brute-force search].txt
JSP3 Cover Panel (64bit DUI)
Hi Air Ken,
Can you shed a light on what you are after ? as specific as possible cause i may not get your point.
Cheer.
Is there any error bugging or logic alcorithm benhind.
Thanks.
Hi all,
I have moved to foobar2000 64bit to extend the memory beyond 4GB, this leaves llot of plugins behind.
To overcome, i have to recourse to JScript Panel3 and, therefore, ported/modified some scripts from others.
It seems, someone may have the same things while struggling with 64bit, i would like to share these scripts as attached.
last but not least, sorry original authors, especially Marc2003, Br3tt among others for "destroying" their beauty full codes.
you are free to use and make any changes as long as retain original author names.
[due to limitation, i may have little resource to react to this post.]
/*------------ [JScript Panel 3] 64bit scripts -----------------*/
// date: 03PM25 22Jul24
// viking, vnav.vn
Credit to original authors' scripts: Marc2003, marc2k3, Iprad, Br3tt aka Falstaff, eurekagliese, TT, Jul23, Hunter.
//system test:
- Windows 11, screen : FullHD, scale 150%
- foobar2000 64bit, preview 7jul24
- foobar200 Default UI (CUI should be fine).
- font : as listed in folder [font], of which [Segoe Fluent Icons] maybe already installed under Windows 11.
//dependencies:
- latest 64bit components and exe files as in [user-components-x64] folder, including JScript Panel 3 [https://github.com/jscript-panel/release/releases] - latest version is 3.6.1
// note: files were deleted on purpose to mitigate risk, if any, during transfer over network
- to enable youtube view, download: yt-dl.exe from GitHub [https://github.com/yt-dlp/yt-dlp].
- to enable spectrum analysis, download : spek.exe [https://github.com/alexkay/spek]
//pre-install:
- download and install foobar2000 64bit, latest version as of Jul24 (2.1.5).
- unzip file into foobar2000 64bit root folder.
- download and install/copy components.
- download exe files (to enable youtube, spectrum checking)
- install fonts (if any).
//install JScript Panel 3 (@Marc2003) scripts:
- under DUI.
- enable edit mod
- insert [JScript Panel 3] panel.
- copy script from [foobar2000\skins\viking\scripts\jsp3] folder and paste into [JScript Panel 3] panel.
- copy script [foobar2000\skins\viking\scripts\jsp3_lib\vnav_mod\jsplaylist_main.js] and paste into [JScript Panel 3] panel.
- copy script [foobar2000\skins\viking\scripts\jsp3_lib\vnav_mod\jssb.js] and paste into [JScript Panel 3] panel.
- Apply.
/*------------------------*/
Script detail: (alphabet sort)
Script { name, original author (idea), original source, comment}
I. folder : foobar2000\skins\viking\scripts\jsp3_lib\vnav_mod
------------------------------------------------
//1- name : jssb.js,
original author (idea): Br3tt aka Falstaff [enhanced, tuned by Marc2003]
original source : Smooth Browser
comment: /* modification */
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artworks located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
# resize all artworks as thumbnails to speed up the whole.
# [folder structure] library browsing.
//2- name : jsplaylist_main.js,
original author (idea): Br3tt aka Falstaff [enhanced, tuned by Marc2003]
original source : JS Playlist.
comment: /* modification */
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artworks located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
II. folder : foobar2000\skins\viking\scripts\jsp3
------------------------------------
//1- name : {deployed} album_art [brute-force search],
original author (idea): Marc2003
original source : thumbs and artwork script
comment: /* modification */
+ main features added:
# get artworks from local and lastfm at the same time.
# brute-force searching for artworks located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file, and absolute folder (via panel property).
# resize and cache all artworks as thumbnailsto speed up the whole.
# resize and save BIG artworks under and per album.
# view origial artwoks (ensure quality)
# background : as default image all per [all/1st] artworks
# second artist artworks download (via [{deployed} artwork download by artist from lastfm.txt] script)
+ limit: loading images are not asynced.
//2- name : {deployed} album_art [properties],
original author (idea): Marc2003
original source : Text Display
comment: /* modification */
+ main features added:
# context menu : more functions
# buttons : 4 positions, user-defined coord x,y (via property)
# youtube: download
//3- name : {deployed} analog clock,
original author (idea): Hunter
original source :
comment: /* modification */
+ ported to JScript Panel 3
//4- name : {deployed} control bar,
original author (idea): marc2k3 coded, eurekagliese enhanced
original source :
comment: /* modification */
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artwork located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
//5- name : {deployed} cover flow,
original author (idea): Br3tt aka Falstaff
original source :
comment: /* modification */
+ ported to JScript Panel 3
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artwork located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
//6- name : {deployed} lyrics download manager,
original author (idea):
original source :
comment: /* coded */
+ main features:
# download lyrics via Google host.
# get lyrics translated online by Google site
+ limit: async lyrics only.
//7- name : {deployed} TechnicsRSBX_iprad,
original author (idea): Iprad
original source :
comment: /* coded */
+ ported to JScript Panel 3
+ main features added:
# pseudo - VU Analog Meter. (wish list: JScript Panel 3, fb.peakLeft, fb.pakRight . . . properties )
//8- name : {deployed} tree explorer,
original author (idea): Br3tt aka Falstaff
original source :
comment: /* coded */
+ ported to JScript Panel 3
//9- name : {deployed} tree explorer,
original author (idea): Br3tt aka Falstaff
original source :
comment: /* coded */
+ ported to JScript Panel 3
note: images cached are all located under [foobar2000\$recycle.bin] folder, per respective components, panels.
/*/ Music can bring happiness, let it on. /*/
// EOF
Nice post, just a suggestion, perhaps it would be better if you also include a screenshot.
Hi eurekagliese,
Thank you for your comment end, of course, rich- function button bar.
I learn a lot from your script.
I am thinking of some pseudo screenshots and get back later.
Cheer.
@ilovefb2k
Sorry.
"{deployed} album_art [cd-vinyl].txt" was displayed.
The only thing that can't be displayed is "{deployed} lastfm (no art).txt".
JScript Panel 3.6.1 (id:1772928)
JavaScript 実行時エラー
'folders' は定義されていません。
File: <main>
Line: 15, Col: 1
-----
{deployed} album_art [brute-force search].txt
JSP3 Cover Panel (64bit DUI)
Albumart and Thumbs Isn't the scroll upside down?
Thanks.
------------------
Hi all,
I have moved to foobar2000 64bit to extend the memory beyond 4GB, this leaves llot of plugins behind.
To overcome, i have to recourse to JScript Panel3 and, therefore, ported/modified some scripts from others.
It seems, someone may have the same things while struggling with 64bit, i would like to share these scripts as attached.
last but not least, sorry original authors, especially Marc2003, Br3tt among others for "destroying" their beauty full codes.
you are free to use and make any changes as long as retain original author names.
[due to limitation, i may have little resource to react to this post.]
/*------------ [JScript Panel 3] 64bit scripts -----------------*/
// date: 03PM25 22Jul24
// viking, vnav.vn
Credit to original authors' scripts: Marc2003, marc2k3, Iprad, Br3tt aka Falstaff, eurekagliese, TT, Jul23, Hunter.
//system test:
- Windows 11, screen : FullHD, scale 150%
- foobar2000 64bit, preview 7jul24
- foobar200 Default UI (CUI should be fine).
- font : as listed in folder [font], of which [Segoe Fluent Icons] maybe already installed under Windows 11.
//dependencies:
- latest 64bit components and exe files as in [user-components-x64] folder, including JScript Panel 3 [https://github.com/jscript-panel/release/releases] - latest version is 3.6.1
// note: files were deleted on purpose to mitigate risk, if any, during transfer over network
- to enable youtube view, download: yt-dl.exe from GitHub [https://github.com/yt-dlp/yt-dlp].
- to enable spectrum analysis, download : spek.exe [https://github.com/alexkay/spek]
//pre-install:
- download and install foobar2000 64bit, latest version as of Jul24 (2.1.5).
- unzip file into foobar2000 64bit root folder.
- download and install/copy components.
- download exe files (to enable youtube, spectrum checking)
- install fonts (if any).
//install JScript Panel 3 (@Marc2003) scripts:
- under DUI.
- enable edit mod
- insert [JScript Panel 3] panel.
- copy script from [foobar2000\skins\viking\scripts\jsp3] folder and paste into [JScript Panel 3] panel.
- copy script [foobar2000\skins\viking\scripts\jsp3_lib\vnav_mod\jsplaylist_main.js] and paste into [JScript Panel 3] panel.
- copy script [foobar2000\skins\viking\scripts\jsp3_lib\vnav_mod\jssb.js] and paste into [JScript Panel 3] panel.
- Apply.
/*------------------------*/
Script detail: (alphabet sort)
Script { name, original author (idea), original source, comment}
I. folder : foobar2000\skins\viking\scripts\jsp3_lib\vnav_mod
------------------------------------------------
//1- name : jssb.js,
original author (idea): Br3tt aka Falstaff [enhanced, tuned by Marc2003]
original source : Smooth Browser
comment: /* modification */
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artworks located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
# resize all artworks as thumbnails to speed up the whole.
# [folder structure] library browsing.
//2- name : jsplaylist_main.js,
original author (idea): Br3tt aka Falstaff [enhanced, tuned by Marc2003]
original source : JS Playlist.
comment: /* modification */
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artworks located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
II. folder : foobar2000\skins\viking\scripts\jsp3
------------------------------------
//1- name : {deployed} album_art [brute-force search],
original author (idea): Marc2003
original source : thumbs and artwork script
comment: /* modification */
+ main features added:
# get artworks from local and lastfm at the same time.
# brute-force searching for artworks located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file, and absolute folder (via panel property).
# resize and cache all artworks as thumbnailsto speed up the whole.
# resize and save BIG artworks under and per album.
# view origial artwoks (ensure quality)
# background : as default image all per [all/1st] artworks
# second artist artworks download (via [{deployed} artwork download by artist from lastfm.txt] script)
+ limit: loading images are not asynced.
//2- name : {deployed} album_art [properties],
original author (idea): Marc2003
original source : Text Display
comment: /* modification */
+ main features added:
# context menu : more functions
# buttons : 4 positions, user-defined coord x,y (via property)
# youtube: download
//3- name : {deployed} analog clock,
original author (idea): Hunter
original source :
comment: /* modification */
+ ported to JScript Panel 3
//4- name : {deployed} control bar,
original author (idea): marc2k3 coded, eurekagliese enhanced
original source :
comment: /* modification */
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artwork located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
//5- name : {deployed} cover flow,
original author (idea): Br3tt aka Falstaff
original source :
comment: /* modification */
+ ported to JScript Panel 3
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artwork located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
//6- name : {deployed} lyrics download manager,
original author (idea):
original source :
comment: /* coded */
+ main features:
# download lyrics via Google host.
# get lyrics translated online by Google site
+ limit: async lyrics only.
//7- name : {deployed} TechnicsRSBX_iprad,
original author (idea): Iprad
original source :
comment: /* coded */
+ ported to JScript Panel 3
+ main features added:
# pseudo - VU Analog Meter. (wish list: JScript Panel 3, fb.peakLeft, fb.pakRight . . . properties )
//8- name : {deployed} tree explorer,
original author (idea): Br3tt aka Falstaff
original source :
comment: /* coded */
+ ported to JScript Panel 3
//9- name : {deployed} tree explorer,
original author (idea): Br3tt aka Falstaff
original source :
comment: /* coded */
+ ported to JScript Panel 3
note: images cached are all located under [foobar2000\$recycle.bin] folder, per respective components, panels.
/*/ Music can bring happiness, let it on. /*/
// EOF
Nice post, just a suggestion, perhaps it would be better if you also include a screenshot.
Hi eurekagliese,
Thank you for your comment end, of course, rich- function button bar.
I learn a lot from your script.
I am thinking of some pseudo screenshots and get back later.
Cheer.
Could you please create a new thread for this "ilovefb2k's JScript Panel Sample script mod?"
Hi all,
I have moved to foobar2000 64bit to extend the memory beyond 4GB, this leaves llot of plugins behind.
To overcome, i have to recourse to JScript Panel3 and, therefore, ported/modified some scripts from others.
It seems, someone may have the same things while struggling with 64bit, i would like to share these scripts as attached.
last but not least, sorry original authors, especially Marc2003, Br3tt among others for "destroying" their beauty full codes.
you are free to use and make any changes as long as retain original author names.
[due to limitation, i may have little resource to react to this post.]
/*------------ [JScript Panel 3] 64bit scripts -----------------*/
// date: 03PM25 22Jul24
// viking, vnav.vn
Credit to original authors' scripts: Marc2003, marc2k3, Iprad, Br3tt aka Falstaff, eurekagliese, TT, Jul23, Hunter.
//system test:
- Windows 11, screen : FullHD, scale 150%
- foobar2000 64bit, preview 7jul24
- foobar200 Default UI (CUI should be fine).
- font : as listed in folder [font], of which [Segoe Fluent Icons] maybe already installed under Windows 11.
//dependencies:
- latest 64bit components and exe files as in [user-components-x64] folder, including JScript Panel 3 [https://github.com/jscript-panel/release/releases] - latest version is 3.6.1
// note: files were deleted on purpose to mitigate risk, if any, during transfer over network
- to enable youtube view, download: yt-dl.exe from GitHub [https://github.com/yt-dlp/yt-dlp].
- to enable spectrum analysis, download : spek.exe [https://github.com/alexkay/spek]
//pre-install:
- download and install foobar2000 64bit, latest version as of Jul24 (2.1.5).
- unzip file into foobar2000 64bit root folder.
- download and install/copy components.
- download exe files (to enable youtube, spectrum checking)
- install fonts (if any).
//install JScript Panel 3 (@Marc2003) scripts:
- under DUI.
- enable edit mod
- insert [JScript Panel 3] panel.
- copy script from [foobar2000\skins\viking\scripts\jsp3] folder and paste into [JScript Panel 3] panel.
- copy script [foobar2000\skins\viking\scripts\jsp3_lib\vnav_mod\jsplaylist_main.js] and paste into [JScript Panel 3] panel.
- copy script [foobar2000\skins\viking\scripts\jsp3_lib\vnav_mod\jssb.js] and paste into [JScript Panel 3] panel.
- Apply.
/*------------------------*/
Script detail: (alphabet sort)
Script { name, original author (idea), original source, comment}
I. folder : foobar2000\skins\viking\scripts\jsp3_lib\vnav_mod
------------------------------------------------
//1- name : jssb.js,
original author (idea): Br3tt aka Falstaff [enhanced, tuned by Marc2003]
original source : Smooth Browser
comment: /* modification */
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artworks located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
# resize all artworks as thumbnails to speed up the whole.
# [folder structure] library browsing.
//2- name : jsplaylist_main.js,
original author (idea): Br3tt aka Falstaff [enhanced, tuned by Marc2003]
original source : JS Playlist.
comment: /* modification */
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artworks located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
II. folder : foobar2000\skins\viking\scripts\jsp3
------------------------------------
//1- name : {deployed} album_art [brute-force search],
original author (idea): Marc2003
original source : thumbs and artwork script
comment: /* modification */
+ main features added:
# get artworks from local and lastfm at the same time.
# brute-force searching for artworks located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file, and absolute folder (via panel property).
# resize and cache all artworks as thumbnailsto speed up the whole.
# resize and save BIG artworks under and per album.
# view origial artwoks (ensure quality)
# background : as default image all per [all/1st] artworks
# second artist artworks download (via [{deployed} artwork download by artist from lastfm.txt] script)
+ limit: loading images are not asynced.
//2- name : {deployed} album_art [properties],
original author (idea): Marc2003
original source : Text Display
comment: /* modification */
+ main features added:
# context menu : more functions
# buttons : 4 positions, user-defined coord x,y (via property)
# youtube: download
//3- name : {deployed} analog clock,
original author (idea): Hunter
original source :
comment: /* modification */
+ ported to JScript Panel 3
//4- name : {deployed} control bar,
original author (idea): marc2k3 coded, eurekagliese enhanced
original source :
comment: /* modification */
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artwork located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
//5- name : {deployed} cover flow,
original author (idea): Br3tt aka Falstaff
original source :
comment: /* modification */
+ ported to JScript Panel 3
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artwork located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
//6- name : {deployed} lyrics download manager,
original author (idea):
original source :
comment: /* coded */
+ main features:
# download lyrics via Google host.
# get lyrics translated online by Google site
+ limit: async lyrics only.
//7- name : {deployed} TechnicsRSBX_iprad,
original author (idea): Iprad
original source :
comment: /* coded */
+ ported to JScript Panel 3
+ main features added:
# pseudo - VU Analog Meter. (wish list: JScript Panel 3, fb.peakLeft, fb.pakRight . . . properties )
//8- name : {deployed} tree explorer,
original author (idea): Br3tt aka Falstaff
original source :
comment: /* coded */
+ ported to JScript Panel 3
//9- name : {deployed} tree explorer,
original author (idea): Br3tt aka Falstaff
original source :
comment: /* coded */
+ ported to JScript Panel 3
note: images cached are all located under [foobar2000\$recycle.bin] folder, per respective components, panels.
/*/ Music can bring happiness, let it on. /*/
// EOF
Nice post, just a suggestion, perhaps it would be better if you also include a screenshot.
Hi eurekagliese,
Thank you for your comment end, of course, rich- function button bar.
I learn a lot from your script.
I am thinking of some pseudo screenshots and get back later.
Cheer.
If you don't post the theme.fth no one will be able to use the image.
The image should be like this:
https://vnav.vn/threads/foobar2000-0-8-3-custom-by-draikin.44728/page-6
https://www.virustotal.com/gui/file/b153c2084bae88e5f94e960fade78cd61528ea26240eada265d442ef7d1c55d8?nocache=1
(https://i.postimg.cc/CnM7TBP2/Immagine-2024-07-24-073537.png) (https://postimg.cc/CnM7TBP2)
(https://i.postimg.cc/ygyjbXP9/Immagine-2024-07-24-073553.png) (https://postimg.cc/ygyjbXP9)
(https://i.postimg.cc/kV8fxdRT/Immagine-2024-07-24-073610.png) (https://postimg.cc/kV8fxdRT)
(https://i.postimg.cc/ftN5CgxD/Immagine-2024-07-24-073628.png) (https://postimg.cc/ftN5CgxD)
(https://i.postimg.cc/0zhVMNj6/Immagine-2024-07-24-073643.png) (https://postimg.cc/0zhVMNj6)
URL name fix.
(https://i.postimg.cc/LhcQNpPK/Immagine-2024-07-24-105407.png) (https://postimg.cc/LhcQNpPK)
(https://i.postimg.cc/4n7F6dmQ/Immagine-2024-07-24-105610.png) (https://postimg.cc/4n7F6dmQ)
(https://i.postimg.cc/bDMVXXFn/Immagine-2024-07-24-105736.png) (https://postimg.cc/bDMVXXFn)
(https://i.postimg.cc/pmZ0W56R/Immagine-2024-07-24-105809.png) (https://postimg.cc/pmZ0W56R)
(https://i.postimg.cc/tZ7vmRDy/Immagine-2024-07-24-105849.png) (https://postimg.cc/tZ7vmRDy)
(https://i.postimg.cc/BjsYfBNm/Screenshot-2024-07-24-105022.png) (https://postimg.cc/BjsYfBNm)
(https://i.postimg.cc/CzbP2QCZ/Screenshot-2024-07-24-105232.png) (https://postimg.cc/CzbP2QCZ)
(https://i.postimg.cc/CnqPSvWQ/Screenshot-2024-07-24-105646.png) (https://postimg.cc/CnqPSvWQ)
@eurekagliese could you share your fb fth files ? thanks for top.
@ilovefb2k
Sorry.
"{deployed} album_art [cd-vinyl].txt" was displayed.
The only thing that can't be displayed is "{deployed} lastfm (no art).txt".
JScript Panel 3.6.1 (id:1772928)
JavaScript 実行時エラー
'folders' は定義されていません。
File: <main>
Line: 15, Col: 1
-----
{deployed} album_art [brute-force search].txt
JSP3 Cover Panel (64bit DUI)
Albumart and Thumbs Isn't the scroll upside down?
Thanks.
------------------
Hi all,
I have moved to foobar2000 64bit to extend the memory beyond 4GB, this leaves llot of plugins behind.
To overcome, i have to recourse to JScript Panel3 and, therefore, ported/modified some scripts from others.
It seems, someone may have the same things while struggling with 64bit, i would like to share these scripts as attached.
last but not least, sorry original authors, especially Marc2003, Br3tt among others for "destroying" their beauty full codes.
you are free to use and make any changes as long as retain original author names.
[due to limitation, i may have little resource to react to this post.]
/*------------ [JScript Panel 3] 64bit scripts -----------------*/
// date: 03PM25 22Jul24
// viking, vnav.vn
Credit to original authors' scripts: Marc2003, marc2k3, Iprad, Br3tt aka Falstaff, eurekagliese, TT, Jul23, Hunter.
//system test:
- Windows 11, screen : FullHD, scale 150%
- foobar2000 64bit, preview 7jul24
- foobar200 Default UI (CUI should be fine).
- font : as listed in folder [font], of which [Segoe Fluent Icons] maybe already installed under Windows 11.
//dependencies:
- latest 64bit components and exe files as in [user-components-x64] folder, including JScript Panel 3 [https://github.com/jscript-panel/release/releases] - latest version is 3.6.1
// note: files were deleted on purpose to mitigate risk, if any, during transfer over network
- to enable youtube view, download: yt-dl.exe from GitHub [https://github.com/yt-dlp/yt-dlp].
- to enable spectrum analysis, download : spek.exe [https://github.com/alexkay/spek]
//pre-install:
- download and install foobar2000 64bit, latest version as of Jul24 (2.1.5).
- unzip file into foobar2000 64bit root folder.
- download and install/copy components.
- download exe files (to enable youtube, spectrum checking)
- install fonts (if any).
//install JScript Panel 3 (@Marc2003) scripts:
- under DUI.
- enable edit mod
- insert [JScript Panel 3] panel.
- copy script from [foobar2000\skins\viking\scripts\jsp3] folder and paste into [JScript Panel 3] panel.
- copy script [foobar2000\skins\viking\scripts\jsp3_lib\vnav_mod\jsplaylist_main.js] and paste into [JScript Panel 3] panel.
- copy script [foobar2000\skins\viking\scripts\jsp3_lib\vnav_mod\jssb.js] and paste into [JScript Panel 3] panel.
- Apply.
/*------------------------*/
Script detail: (alphabet sort)
Script { name, original author (idea), original source, comment}
I. folder : foobar2000\skins\viking\scripts\jsp3_lib\vnav_mod
------------------------------------------------
//1- name : jssb.js,
original author (idea): Br3tt aka Falstaff [enhanced, tuned by Marc2003]
original source : Smooth Browser
comment: /* modification */
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artworks located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
# resize all artworks as thumbnails to speed up the whole.
# [folder structure] library browsing.
//2- name : jsplaylist_main.js,
original author (idea): Br3tt aka Falstaff [enhanced, tuned by Marc2003]
original source : JS Playlist.
comment: /* modification */
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artworks located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
II. folder : foobar2000\skins\viking\scripts\jsp3
------------------------------------
//1- name : {deployed} album_art [brute-force search],
original author (idea): Marc2003
original source : thumbs and artwork script
comment: /* modification */
+ main features added:
# get artworks from local and lastfm at the same time.
# brute-force searching for artworks located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file, and absolute folder (via panel property).
# resize and cache all artworks as thumbnailsto speed up the whole.
# resize and save BIG artworks under and per album.
# view origial artwoks (ensure quality)
# background : as default image all per [all/1st] artworks
# second artist artworks download (via [{deployed} artwork download by artist from lastfm.txt] script)
+ limit: loading images are not asynced.
//2- name : {deployed} album_art [properties],
original author (idea): Marc2003
original source : Text Display
comment: /* modification */
+ main features added:
# context menu : more functions
# buttons : 4 positions, user-defined coord x,y (via property)
# youtube: download
//3- name : {deployed} analog clock,
original author (idea): Hunter
original source :
comment: /* modification */
+ ported to JScript Panel 3
//4- name : {deployed} control bar,
original author (idea): marc2k3 coded, eurekagliese enhanced
original source :
comment: /* modification */
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artwork located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
//5- name : {deployed} cover flow,
original author (idea): Br3tt aka Falstaff
original source :
comment: /* modification */
+ ported to JScript Panel 3
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artwork located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
//6- name : {deployed} lyrics download manager,
original author (idea):
original source :
comment: /* coded */
+ main features:
# download lyrics via Google host.
# get lyrics translated online by Google site
+ limit: async lyrics only.
//7- name : {deployed} TechnicsRSBX_iprad,
original author (idea): Iprad
original source :
comment: /* coded */
+ ported to JScript Panel 3
+ main features added:
# pseudo - VU Analog Meter. (wish list: JScript Panel 3, fb.peakLeft, fb.pakRight . . . properties )
//8- name : {deployed} tree explorer,
original author (idea): Br3tt aka Falstaff
original source :
comment: /* coded */
+ ported to JScript Panel 3
//9- name : {deployed} tree explorer,
original author (idea): Br3tt aka Falstaff
original source :
comment: /* coded */
+ ported to JScript Panel 3
note: images cached are all located under [foobar2000\$recycle.bin] folder, per respective components, panels.
/*/ Music can bring happiness, let it on. /*/
// EOF
Nice post, just a suggestion, perhaps it would be better if you also include a screenshot.
Hi eurekagliese,
Thank you for your comment end, of course, rich- function button bar.
I learn a lot from your script.
I am thinking of some pseudo screenshots and get back later.
Cheer.
Could you please create a new thread for this "ilovefb2k's JScript Panel Sample script mod?"
Hi Air KEN,
Sorry to be late to get back to you as i have go to a specific cafe to get site connected.
In saying so, as i said, only at sometimes and at that cafe could i login to this site. Otherwise, i may bypass firewall (of this site) via VPN but be left behind the door. Most of the times, site rejects my accessing.
JScript Panel 3.6.1 (id:1772928)
JavaScript Runtime Error
'folders' is not defined.
File: <main]
Line: 15, Col: 1
It is weir that this could trigger an error. 'folders' is an object already be declared in 'common.js' lib, that is imported at the very beginning.
Otherwise, you can add 1 line before line 15, as follows: if (folders == null ) var folders = {};
This code check whether a variable is not defined (term is 'undefined': typeof folders === 'undefined') or not be assigned a value.
{deployed} album_art [brute-force search].txt
JSP3 Cover Panel (64bit DUI)
Albumart and Thumbs Isn't the scroll upside down?
i could not catch your idea. you mean there are no vertical thumbs along the left side of the panel ?
if so, i did remove other thumbs' postion other than the bottom's. these thumbs are actually just 1 image only and Marc2k3 monitor mouse position (coord x,y) over these thumbs (this image) to trigger a view.
i also add a callback (on_mouse_wheel), this is an event-listen for mouse wheel. artwork takes turn on show following mouse wheel.
artwork is tilted randomly on purpose.
Could you please create a new thread for this "ilovefb2k's JScript Panel Sample script mod?"
i usually get troublesome (limit resource) accessing this site. Therefore, late to react to others' comments.
This should not the way we interact with each other in the right manner.
As such, I considered these scripts as 1-time posted, and thank you for your suggestion.
i noted that ApacheReal had created that thread, i will upload some screenshots and 'theme' file there.
pls clarify, rephrase "Albumart and Thumbs Isn't the scroll upside down?".
Cheers.
Hi all,
I have moved to foobar2000 64bit to extend the memory beyond 4GB, this leaves llot of plugins behind.
To overcome, i have to recourse to JScript Panel3 and, therefore, ported/modified some scripts from others.
It seems, someone may have the same things while struggling with 64bit, i would like to share these scripts as attached.
last but not least, sorry original authors, especially Marc2003, Br3tt among others for "destroying" their beauty full codes.
you are free to use and make any changes as long as retain original author names.
[due to limitation, i may have little resource to react to this post.]
/*------------ [JScript Panel 3] 64bit scripts -----------------*/
// date: 03PM25 22Jul24
// viking, vnav.vn
Credit to original authors' scripts: Marc2003, marc2k3, Iprad, Br3tt aka Falstaff, eurekagliese, TT, Jul23, Hunter.
//system test:
- Windows 11, screen : FullHD, scale 150%
- foobar2000 64bit, preview 7jul24
- foobar200 Default UI (CUI should be fine).
- font : as listed in folder [font], of which [Segoe Fluent Icons] maybe already installed under Windows 11.
//dependencies:
- latest 64bit components and exe files as in [user-components-x64] folder, including JScript Panel 3 [https://github.com/jscript-panel/release/releases] - latest version is 3.6.1
// note: files were deleted on purpose to mitigate risk, if any, during transfer over network
- to enable youtube view, download: yt-dl.exe from GitHub [https://github.com/yt-dlp/yt-dlp].
- to enable spectrum analysis, download : spek.exe [https://github.com/alexkay/spek]
//pre-install:
- download and install foobar2000 64bit, latest version as of Jul24 (2.1.5).
- unzip file into foobar2000 64bit root folder.
- download and install/copy components.
- download exe files (to enable youtube, spectrum checking)
- install fonts (if any).
//install JScript Panel 3 (@Marc2003) scripts:
- under DUI.
- enable edit mod
- insert [JScript Panel 3] panel.
- copy script from [foobar2000\skins\viking\scripts\jsp3] folder and paste into [JScript Panel 3] panel.
- copy script [foobar2000\skins\viking\scripts\jsp3_lib\vnav_mod\jsplaylist_main.js] and paste into [JScript Panel 3] panel.
- copy script [foobar2000\skins\viking\scripts\jsp3_lib\vnav_mod\jssb.js] and paste into [JScript Panel 3] panel.
- Apply.
/*------------------------*/
Script detail: (alphabet sort)
Script { name, original author (idea), original source, comment}
I. folder : foobar2000\skins\viking\scripts\jsp3_lib\vnav_mod
------------------------------------------------
//1- name : jssb.js,
original author (idea): Br3tt aka Falstaff [enhanced, tuned by Marc2003]
original source : Smooth Browser
comment: /* modification */
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artworks located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
# resize all artworks as thumbnails to speed up the whole.
# [folder structure] library browsing.
//2- name : jsplaylist_main.js,
original author (idea): Br3tt aka Falstaff [enhanced, tuned by Marc2003]
original source : JS Playlist.
comment: /* modification */
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artworks located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
II. folder : foobar2000\skins\viking\scripts\jsp3
------------------------------------
//1- name : {deployed} album_art [brute-force search],
original author (idea): Marc2003
original source : thumbs and artwork script
comment: /* modification */
+ main features added:
# get artworks from local and lastfm at the same time.
# brute-force searching for artworks located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file, and absolute folder (via panel property).
# resize and cache all artworks as thumbnailsto speed up the whole.
# resize and save BIG artworks under and per album.
# view origial artwoks (ensure quality)
# background : as default image all per [all/1st] artworks
# second artist artworks download (via [{deployed} artwork download by artist from lastfm.txt] script)
+ limit: loading images are not asynced.
//2- name : {deployed} album_art [properties],
original author (idea): Marc2003
original source : Text Display
comment: /* modification */
+ main features added:
# context menu : more functions
# buttons : 4 positions, user-defined coord x,y (via property)
# youtube: download
//3- name : {deployed} analog clock,
original author (idea): Hunter
original source :
comment: /* modification */
+ ported to JScript Panel 3
//4- name : {deployed} control bar,
original author (idea): marc2k3 coded, eurekagliese enhanced
original source :
comment: /* modification */
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artwork located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
//5- name : {deployed} cover flow,
original author (idea): Br3tt aka Falstaff
original source :
comment: /* modification */
+ ported to JScript Panel 3
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artwork located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
//6- name : {deployed} lyrics download manager,
original author (idea):
original source :
comment: /* coded */
+ main features:
# download lyrics via Google host.
# get lyrics translated online by Google site
+ limit: async lyrics only.
//7- name : {deployed} TechnicsRSBX_iprad,
original author (idea): Iprad
original source :
comment: /* */
+ ported to JScript Panel 3
+ main features added:
# pseudo - VU Analog Meter. (wish list: JScript Panel 3, fb.peakLeft, fb.pakRight . . . properties )
//8- name : {deployed} tree explorer,
original author (idea): Br3tt aka Falstaff
original source :
comment: /* */
+ ported to JScript Panel 3
note: images cached are all located under [foobar2000\$recycle.bin] folder, per respective components, panels.
/*/ Music can bring happiness, let it on. /*/
// EOF
Nice post, just a suggestion, perhaps it would be better if you also include a screenshot.
Hi eurekagliese,
Thank you for your comment end, of course, rich- function button bar.
I learn a lot from your script.
I am thinking of some pseudo screenshots and get back later.
Cheer.
If you don't post the theme.fth no one will be able to use the image.
Hi ApacheReal,
Thank you for your creating this thread and, this would be a place for more JSP3 scripts too.
Pls find the theme file attached.
Otherwise, a full-configured zip file can be found here at mediafire host:
https://www.mediafire.com/file/2uvkzvihflvllyh/fb2k_vnav_1.0.0_64_22jul24.rar/file
Cheers.
Hi ApacheReal,
I re-attach scripts for easy reference.
Cheer.
and images to enables album-art [cd-vinyl].txt scripts.
Hi all,
@ApacheReal
@eurekagliese,
As per
@eurekagliese suggestion, I enclose some screenshots with this post, hope this does not break any rule or bring any troublesome to site's admin.
I names these screenshot files after their main feature.
regarding '{deployed} lyrics download manager.txt', this script supports lyrics translated via Google site to other language.
by default, i set 'Vietnamese' (my mother tongue) as destination language. pls following steps to switch to others language:
- 'open' '{deployed} lyrics download manager.txt' by any text editor.
- get to row 418. there should be a text line as follows
url = "https://translate.google.com/?sl=auto&tl=vi&text=" //sl: source language, tl=translated lang, tex=text to be translated
- replace [tl=vi] by [tl=en] for English, [tl=de] for Germany, . . . [you can figure out this term by switching around languages and note changes of URL on web browser address bar]
- get to row 352: _menu.AppendMenuItem(lyrics.length <=2 ? MF_GRAYED : MF_STRING, 102, 'Web browser > Google Lyrics translated to Vietnamese');
- change context menu prompt accordingly.
- save script file.
- restart foobar2000.
Cheer.
@all,
As my web browser usually be banned from accessing this site, and on luck at some cafes to login, it maybe late for me to get back to this post.
Wish you all a nice day.
Cheer.
@ilovefb2k
> {deployed} album_art [brute-force search].txt
> JSP3 Cover Panel (64bit DUI)
> Albumart and Thumbs Isn't the scroll upside down?
This happens when you scroll the panel.
Scrolling over a thumbnail changes the album art.
---------
> i usually get troublesome (limit resource) accessing this site. Therefore, late to react to others' comments.
> This should not the way we interact with each other in the right manner.
> As such, I considered these scripts as 1-time posted, and thank you for your suggestion.
I understand. I'm sorry for asking too much.
Hello everyone.
Is a screen like this possible?
I'd like to increase the options for Now Playing Screen.
(https://i.imgur.com/01PdqbA.png)
Album art will be on the CD.
It would be easier to use if the option had Spin, Slow Speed, Stop, etc.
It would be nice to have an option to blur the background
https://github.com/jscript-panel/release/releases
"Text Display and Text Display + Album Art + Seekbar + Buttons have been updated so the album art is no longer locked to the front cover."
(https://i.postimg.cc/qhqmShz7/Screenshot-2024-07-25-105844.png) (https://postimg.cc/qhqmShz7)
Hello everyone.
Is a screen like this possible?
I'd like to increase the options for Now Playing Screen.
(https://i.imgur.com/01PdqbA.png)
Album art will be on the CD.
It would be easier to use if the option had Spin, Slow Speed, Stop, etc.
It would be nice to have an option to blur the background
It became standard in JScript Panel 3 v3.6.2.
Use the web view component for spinning images. It's much better suited for it.
There was a script in ilovefb2k"s Script ({deployed} album_art [cd-vinyl].txt) script to rotate the CD, so...
https://hydrogenaud.io/index.php/topic,110516.msg1048177.html#msg1048177
Additional Images Folder: https://mega.nz/file/peNnUZ5T#6ih7Wjm9g3e4Sq2LvBhRMfGWEvm-qSjFCO-rvMIU8uE
so...
what?
I said web view was "better suited" which it still is. I didn't say JSP3 couldn't do it. I posted a proof of concept years ago....
https://gist.github.com/marc2k3/1d449cc5bbb2fcfdb51157e49d679ad6
I never distribute it along with the component because it's totally crap. The novelty wears thin after about 3 or 4 seconds.
There was a script in ilovefb2k"s Script ({deployed} album_art [cd-vinyl].txt) script to rotate the CD, so...
https://hydrogenaud.io/index.php/topic,110516.msg1048177.html#msg1048177
Additional Images Folder: https://mega.nz/file/peNnUZ5T#6ih7Wjm9g3e4Sq2LvBhRMfGWEvm-qSjFCO-rvMIU8uE
The version posted by @yeyo in the web view thread is the best ever.
I hope to post future updates, in particular the internal image management currently manages the images in the folder they belong to.
While for the button bar in text display it would be interesting to manage the bar at the top, bottom right and left. I saw @ilovefb2k did something like this in his skin.
I also saw other interesting things here:
https://www.esnpc.com/foorab-for-foobar2000-theme/
@marc2k3
> "Spinny Album Art Nonsense"
Ahaha...
I got it. Thank you.
@ApacheReal
> The version posted by @yeyo in the web view thread is the best ever.
> I hope to post future updates, in particular the internal image management currently manages the images in the folder they belong to.
Yes I know, I tested it.
------
> I also saw other interesting things here:
> https://www.esnpc.com/foorab-for-foobar2000-theme/
Thank you for the information.
You have a lot of information.
@eurekagliese
could you share your fb fth files ? thanks for top.
Sure, here you go.
@ilovefb2k
> {deployed} album_art [brute-force search].txt
> JSP3 Cover Panel (64bit DUI)
> Albumart and Thumbs Isn't the scroll upside down?
This happens when you scroll the panel.
Scrolling over a thumbnail changes the album art.
Hi Air KEN,
Thank you for your feedback, i now see your point.
i did reserve artwork panel's mouse-wheel eventlistener for blurring/transparency background tuning on-the-fly.
Then, i preferred to leave that for window property cause that configuration should be 1-time setting to not interfere user experience.
I have noted your suggestion.
Regards.
@ApacheReal
> The version posted by @yeyo in the web view thread is the best ever.
> I hope to post future updates, in particular the internal image management currently manages the images in the folder they belong to.
Yes I know, I tested it.
------
> I also saw other interesting things here:
> https://www.esnpc.com/foorab-for-foobar2000-theme/
Thank you for the information.
You have a lot of information.
Very nice skin. How to download it?
@ApacheReal
> The version posted by @yeyo in the web view thread is the best ever.
> I hope to post future updates, in particular the internal image management currently manages the images in the folder they belong to.
Yes I know, I tested it.
------
> I also saw other interesting things here:
> https://www.esnpc.com/foorab-for-foobar2000-theme/
Thank you for the information.
You have a lot of information.
Very nice skin. How to download it?
I have no idea.
I have some difficulty with the Chinese language.
@ApacheReal
> The version posted by @yeyo in the web view thread is the best ever.
> I hope to post future updates, in particular the internal image management currently manages the images in the folder they belong to.
Yes I know, I tested it.
------
> I also saw other interesting things here:
> https://www.esnpc.com/foorab-for-foobar2000-theme/
Thank you for the information.
You have a lot of information.
Very nice skin. How to download it?
On 118pan.com :
https://www.118pan.com/wap.php?action=space&folder_id=21311 (https://www.118pan.com/wap.php?action=space&folder_id=21311)
(https://i.imgur.com/XzCPrhg.jpeg)
The installation is done in Chinese!
@ApacheReal
> The version posted by @yeyo in the web view thread is the best ever.
> I hope to post future updates, in particular the internal image management currently manages the images in the folder they belong to.
Yes I know, I tested it.
------
> I also saw other interesting things here:
> https://www.esnpc.com/foorab-for-foobar2000-theme/
Thank you for the information.
You have a lot of information.
Very nice skin. How to download it?
On 118pan.com :
https://www.118pan.com/wap.php?action=space&folder_id=21311 (https://www.118pan.com/wap.php?action=space&folder_id=21311)
(https://i.imgur.com/XzCPrhg.jpeg)
The installation is done in Chinese!
Thanks. I can't install it because Windows detects some threats related to this file..
Hi all,
I have moved to foobar2000 64bit to extend the memory beyond 4GB, this leaves llot of plugins behind.
To overcome, i have to recourse to JScript Panel3 and, therefore, ported/modified some scripts from others.
It seems, someone may have the same things while struggling with 64bit, i would like to share these scripts as attached.
last but not least, sorry original authors, especially Marc2003, Br3tt among others for "destroying" their beauty full codes.
you are free to use and make any changes as long as retain original author names.
[due to limitation, i may have little resource to react to this post.]
/*------------ [JScript Panel 3] 64bit scripts -----------------*/
// date: 03PM25 22Jul24
// viking, vnav.vn
Credit to original authors' scripts: Marc2003, marc2k3, Iprad, Br3tt aka Falstaff, eurekagliese, TT, Jul23, Hunter.
//system test:
- Windows 11, screen : FullHD, scale 150%
- foobar2000 64bit, preview 7jul24
- foobar200 Default UI (CUI should be fine).
- font : as listed in folder [font], of which [Segoe Fluent Icons] maybe already installed under Windows 11.
//dependencies:
- latest 64bit components and exe files as in [user-components-x64] folder, including JScript Panel 3 [https://github.com/jscript-panel/release/releases] - latest version is 3.6.1
// note: files were deleted on purpose to mitigate risk, if any, during transfer over network
- to enable youtube view, download: yt-dl.exe from GitHub [https://github.com/yt-dlp/yt-dlp].
- to enable spectrum analysis, download : spek.exe [https://github.com/alexkay/spek]
//pre-install:
- download and install foobar2000 64bit, latest version as of Jul24 (2.1.5).
- unzip file into foobar2000 64bit root folder.
- download and install/copy components.
- download exe files (to enable youtube, spectrum checking)
- install fonts (if any).
//install JScript Panel 3 (@Marc2003) scripts:
- under DUI.
- enable edit mod
- insert [JScript Panel 3] panel.
- copy script from [foobar2000\skins\viking\scripts\jsp3] folder and paste into [JScript Panel 3] panel.
- copy script [foobar2000\skins\viking\scripts\jsp3_lib\vnav_mod\jsplaylist_main.js] and paste into [JScript Panel 3] panel.
- copy script [foobar2000\skins\viking\scripts\jsp3_lib\vnav_mod\jssb.js] and paste into [JScript Panel 3] panel.
- Apply.
/*------------------------*/
Script detail: (alphabet sort)
Script { name, original author (idea), original source, comment}
I. folder : foobar2000\skins\viking\scripts\jsp3_lib\vnav_mod
------------------------------------------------
//1- name : jssb.js,
original author (idea): Br3tt aka Falstaff [enhanced, tuned by Marc2003]
original source : Smooth Browser
comment: /* modification */
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artworks located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
# resize all artworks as thumbnails to speed up the whole.
# [folder structure] library browsing.
//2- name : jsplaylist_main.js,
original author (idea): Br3tt aka Falstaff [enhanced, tuned by Marc2003]
original source : JS Playlist.
comment: /* modification */
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artworks located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
II. folder : foobar2000\skins\viking\scripts\jsp3
------------------------------------
//1- name : {deployed} album_art [brute-force search],
original author (idea): Marc2003
original source : thumbs and artwork script
comment: /* modification */
+ main features added:
# get artworks from local and lastfm at the same time.
# brute-force searching for artworks located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file, and absolute folder (via panel property).
# resize and cache all artworks as thumbnailsto speed up the whole.
# resize and save BIG artworks under and per album.
# view origial artwoks (ensure quality)
# background : as default image all per [all/1st] artworks
# second artist artworks download (via [{deployed} artwork download by artist from lastfm.txt] script)
+ limit: loading images are not asynced.
//2- name : {deployed} album_art [properties],
original author (idea): Marc2003
original source : Text Display
comment: /* modification */
+ main features added:
# context menu : more functions
# buttons : 4 positions, user-defined coord x,y (via property)
# youtube: download
//3- name : {deployed} analog clock,
original author (idea): Hunter
original source :
comment: /* modification */
+ ported to JScript Panel 3
//4- name : {deployed} control bar,
original author (idea): marc2k3 coded, eurekagliese enhanced
original source :
comment: /* modification */
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artwork located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
//5- name : {deployed} cover flow,
original author (idea): Br3tt aka Falstaff
original source :
comment: /* modification */
+ ported to JScript Panel 3
+ main features added:
# get artwork from local, lastfm.
# brute-force searching for artwork located in every-customised relative folders as specifying in
[foobar2000\skins\viking\misc\art_sub_folder.ini] file.
//6- name : {deployed} lyrics download manager,
original author (idea):
original source :
comment: /* coded */
+ main features:
# download lyrics via Google host.
# get lyrics translated online by Google site
+ limit: async lyrics only.
//7- name : {deployed} TechnicsRSBX_iprad,
original author (idea): Iprad
original source :
comment: /* coded */
+ ported to JScript Panel 3
+ main features added:
# pseudo - VU Analog Meter. (wish list: JScript Panel 3, fb.peakLeft, fb.pakRight . . . properties )
//8- name : {deployed} tree explorer,
original author (idea): Br3tt aka Falstaff
original source :
comment: /* coded */
+ ported to JScript Panel 3
//9- name : {deployed} tree explorer,
original author (idea): Br3tt aka Falstaff
original source :
comment: /* coded */
+ ported to JScript Panel 3
note: images cached are all located under [foobar2000\$recycle.bin] folder, per respective components, panels.
/*/ Music can bring happiness, let it on. /*/
// EOF
Is the downloaded folder empty?
@eurekagliese
could you share your fb fth files ? thanks for top.
Sure, here you go.
thank you.
@sq68
Reply #1592 By: ilovefb2k
JSPP3_fb2k0 (64 bit Windows11 - screen fullHD 150pct)_22Jul24.rar
https://hydrogenaud.io/index.php/topic,110516.msg1048254.html#msg1048254
Reply #1593 - Additional Images Folder
{deployed} album_art [cd-vinyl].rar
https://hydrogenaud.io/index.php/topic,110516.msg1048255.html#msg1048255
\profile\user-components-x64
The user-components-x64 folder is empty.
Please assemble it yourself.
Not all components are required.
I cannot correctly configure the module to open the conversion window from the button/icon:
(https://i.postimg.cc/MnPPndMk/Immagine-2024-07-30-073417.png) (https://postimg.cc/MnPPndMk)
this.buttons.mp3 = new _button(x, y, bs+10, bs, { img : mp3 } , null, function () { fb.RunContextCommand('Convert\Quick convert', plman.GetPlaylistSelectedItems(plman.ActivePlaylist));}, "mp3");
I cannot correctly configure the module to open the conversion window from the button/icon:
(https://i.postimg.cc/MnPPndMk/Immagine-2024-07-30-073417.png) (https://postimg.cc/MnPPndMk)
this.buttons.mp3 = new _button(x, y, bs+10, bs, { img : mp3 } , null, function () { fb.RunContextCommand('Convert\Quick convert', plman.GetPlaylistSelectedItems(plman.ActivePlaylist));}, "mp3");
Try this
var handleList = plman.GetPlaylistSelectedItems(plman.ActivePlaylist);
this.buttons.mp3 = new _button(x, y, bs+10, bs, { img : mp3 } , null, function () { handleList.RunContextCommand("Convert/Quick convert"); }, "mp3");
I cannot correctly configure the module to open the conversion window from the button/icon:
(https://i.postimg.cc/MnPPndMk/Immagine-2024-07-30-073417.png) (https://postimg.cc/MnPPndMk)
this.buttons.mp3 = new _button(x, y, bs+10, bs, { img : mp3 } , null, function () { fb.RunContextCommand('Convert\Quick convert', plman.GetPlaylistSelectedItems(plman.ActivePlaylist));}, "mp3");
Try this
var handleList = plman.GetPlaylistSelectedItems(plman.ActivePlaylist);
this.buttons.mp3 = new _button(x, y, bs+10, bs, { img : mp3 } , null, function () { handleList.RunContextCommand("Convert/Quick convert"); }, "mp3");
yes. thx
(https://i.postimg.cc/CzjdMQ21/Screenshot-2024-07-30-080536.png) (https://postimg.cc/CzjdMQ21)
var handleList = plman.GetPlaylistSelectedItems(plman.ActivePlaylist);
this.buttons.mp3 = new _button(x, y, bs+10, bs, { img : mp3 } , null, function () { handleList.RunContextCommand("Convert/MP3 320kbps CBR"); }, "mp3");
(https://i.postimg.cc/t1KgFsBX/Immagine-2024-07-30-105638.png) (https://postimg.cc/t1KgFsBX)
I'll tell you where I got to.
Everything must be customized according to your layout.
In foobar2000 there is no possibility to export the configuration of the convert panel unlike the dsp panel where you can export / save / load the presets.
Hey mate
@ApacheReal do the blank JSP panel issue still occuring on your setup?
(https://i.imgur.com/NSOcbZ4.gif)
Sorry to bump this again Marc, i know you are consider this fixed per post https://hydrogenaud.io/index.php/topic,110499.msg1038819.html#msg1038819.
It's just a minor issue but i'd like to know if anybody else having this issue.
Yes, always.
With 3-3.3.29 the problem doesn't exist.
(https://i.postimg.cc/bsYqD7QV/Immagine-2024-07-30-132139.png) (https://postimg.cc/bsYqD7QV)
Logo fix.
It's just a minor issue but i'd like to know if anybody else having this issue.
I'd say it qualifies as a major issue but I still can't reproduce it. If I can't reproduce it, I can't fix it. :/
The fact you're getting a nice dark mode compliant background means it's not totally failing. I expect pure white or pure black screens on bugs in my code. But how the background gets rendered and not the code inside on_paint is a mystery.... well to me it is.
I've attached a test version which spams the console a bit. To use this, any scripts with timers should be removed otherwise the console logging will be overwhelming. Ideally, the only JSP instances should be the ones in tabs and nothing else.
Post the output when a panel goes blank.
(https://i.imgur.com/n395Vmy.gif)
Sorry for the delay in replying, I was attempting to trigger the blank panel on a portable installation, also tried with older and legacy jsp version, as well as testing it with and without other components, but was unable to reproduce the issue. Unlike the installed version that got the issue like the gif above.
So hardware acceleration in default UI visualisers breaks my component in tabs. I was finally able to reproduce a blank panel because it's disabled by default.
Ah, so that's the source of the issue. Turning off hardware acceleration fixed the issue.
Can't seem to reproduce this issue in Columns UI tabs. So it doesn't make much sense but at least I can say it's not my fault. :D
edit: default UI visualisers are available in CUI for those who don't know
(https://i.postimg.cc/2q9M8M2B/Immagine-2024-07-31-053817.png) (https://postimg.cc/2q9M8M2B)
Text Display + Album Art + Convert Bar Codec & App
Fix logo Mp3tag + folder xml
Import Run Service Preset.xml in Preference / Run Service.
Save your configuration first.
Ah, so that's the source of the issue. Turning off hardware acceleration fixed the issue.
The problem seems to have disappeared by selecting
Turning on hardware acceleration.(https://i.postimg.cc/d7QRS0R8/Immagine-2024-07-31-070344.png) (https://postimg.cc/d7QRS0R8)
Edit:
Forget it.
The problem is always present.
That setting is disabled by default which is why I was unable to reproduce the issue. With it enabled, I can reproduce the issue.
So if you disable it and still have issues, you're in a world of your own.
I need information about the command : UpdateFileInfoSimple
I would like to insert with jsp3 value in the artist and artist album automatiquely.
Maybe it's the command to use ?
Also I would like to make a button in jsp3 to open the right click menu of tagging / edit tagging from masstagger ? Is it possible ?
Thanks a lot guys?
Also I would like to make a button in jsp3 to open the right click menu of tagging / edit tagging from masstagger ? Is it possible ?
Thanks a lot guys?
https://jscript-panel.github.io/docs/interfaces/IMetadbHandleList/#runcontextcommandcommand
There is something to improve in the script.
For the button/icon to work, I have to stop and then play on the active playlist and then the relevant button/icon works.
But the first time you play the chosen playlist, the button/icon is not activated.
Also I would like to make a button in jsp3 to open the right click menu of tagging / edit tagging from masstagger ? Is it possible ?
Thanks a lot guys?
https://jscript-panel.github.io/docs/interfaces/IMetadbHandleList/#runcontextcommandcommand
Thanks you I will try it ....
Hi @all,
This is a 64bit JScript Panel3, named "JSP3 64bit VU Meter" after 32bit "Analog VU Meter" component.
Feature:
# pseudo-"Analog Vu Meter" 64bit component.
(get RMS_Level and Peak_level of 2 channels).
# VU Meter colors can be changed on-the-fly (as sample attached).
limitation:
# local media files only.
# latency (at first run due to raw-data processing).
# files cached (deleted per foorbar2000 session by default).
An implementation sample script is attached for your quick reference.
You all are free to use and make any changes.
Cheer,
#viking aka ilovefb2k @vnav 01Aug24.
.
/*/ -------< P/S >-------------
-Inspired by
i> regorxxx's SMP script: Not a Waveform Seekbar
https://regorxxx.github.io/foobar2000-SMP.github.io/scripts/not-a-waveform-seekbar-smp/
and;
ii> Marc2003: Spectrogram Seekbar
https://jscript-panel.github.io/gallery/spectrogram-seekbar/
- dependency: 'ffprobe.exe' copied to as this folder: fb.ProfilePath + 'skins\\external_helper\\ffprobe.exe'
link : https://www.ffmpeg.org/
version test: https://www.gyan.dev/ffmpeg/builds/ , 2024-07-01 v46
- A little bit about algorithm:
+ get ffprobe.exe exported log file, including RMS_Level, Pek_Level value/data
+ transforming these raw_data into read-to-use:
- cleaning data.
- converting dB [-100,0] into number [0,1].
- adjusting frame number to increase refresh rate if any (varied between 26-92 ms/frame as quick observation)
- caching data to disk for next use (if any).
- delete all data files once foobar2000 "on" exit. (can be variable setting).
- A little bit about ffprobe (FFmpeg) filter:
+ example: for reference only.
https://stackoverflow.com/questions/38056970/ffmpeg-txt-from-audio-levels
https://stackoverflow.com/questions/32254818/generating-a-waveform-using-ffmpeg
+ more update:
https://ffmpeg.org/ffmpeg-filters.html#astats-1
https://trac.ffmpeg.org/wiki/FilteringGuide
+ "pkt_pts_time" parameter: was ignored from late 2021. We still keep this para along with the command or will get nothing out of log file(!!!).
OTW, it had been looked like: (source: Internet, @Gyan, commented Jun 27, 2016 at 19:4, stackoverflow.com as above link)
hit command [ffprobe -f lavfi -i
amovie=audio.aac,
astats=metadata=1:reset=1
-show_entries
frame=pkt_pts_time:frame_tags=lavfi.astats.Overall.RMS_level,lavfi.astats.1.RMS_level,lavfi.astats.2.RMS_level
-of csv=p=0]
=> got resuslt: (1st column is pkt_pts_time in sec, followed by overall RMS_level, 1 (Left channel ?) RMS_level and lastly 2(right channel ?) RMS_level).
Duration: N/A, start: 0.023220, bitrate: N/A
Stream #0:0: Audio: pcm_f64le, 44100 Hz, stereo, dbl, 5644 kb/s
0.023220,-inf,-inf,-inf
0.046440,-inf,-inf,-inf
0.069660,-inf,-inf,-inf
0.092880,-27.330401,-22.685612,-24.414572
0.116100,-21.141091,-18.986082,-19.931269
0.139320,-20.955719,-18.549085,-19.587788
0.162540,-20.938002,-18.198237,-19.355561
0.185760,-19.852306,-20.032553,-19.941494
0.208980,-20.495281,-21.684953,-21.049508
/*/
// Music can bring happiness, let it on.
Looks cool! :) I assume you used ffprobe instead of audiowaveform (easier) to support both RMS and peaks, dont you? Did you find anything useful on the process I should port back?
Maybe
@TT is interested on doing something similar for Georgia. I have no interest on doing new things for SMP if it never gets ported to x64.
Stop using ActiveX filth like WshShell.Run. :P
https://jscript-panel.github.io/docs/namespaces/utils/#utilsruncmdasyncwindow_id-app-params
Hi @all,
This is a 64bit JScript Panel3, named "JSP3 64bit VU Meter" after 32bit "Analog VU Meter" component.
Feature:
# pseudo-"Analog Vu Meter" 64bit component.
(get RMS_Level and Peak_level of 2 channels).
# VU Meter colors can be changed on-the-fly (as sample attached).
limitation:
# local media files only.
# latency (at first run due to raw-data processing).
# files cached (deleted per foorbar2000 session by default).
An implementation sample script is attached for your quick reference.
You all are free to use and make any changes.
Cheer,
#viking aka ilovefb2k @vnav 01Aug24.
.
/*/ -------< P/S >-------------
-Inspired by
i> regorxxx's SMP script: Not a Waveform Seekbar
https://regorxxx.github.io/foobar2000-SMP.github.io/scripts/not-a-waveform-seekbar-smp/
and;
ii> Marc2003: Spectrogram Seekbar
https://jscript-panel.github.io/gallery/spectrogram-seekbar/
- dependency: 'ffprobe.exe' copied to as this folder: fb.ProfilePath + 'skins\\external_helper\\ffprobe.exe'
link : https://www.ffmpeg.org/
version test: https://www.gyan.dev/ffmpeg/builds/ , 2024-07-01 v46
- A little bit about algorithm:
+ get ffprobe.exe exported log file, including RMS_Level, Pek_Level value/data
+ transforming these raw_data into read-to-use:
- cleaning data.
- converting dB [-100,0] into number [0,1].
- adjusting frame number to increase refresh rate if any (varied between 26-92 ms/frame as quick observation)
- caching data to disk for next use (if any).
- delete all data files once foobar2000 "on" exit. (can be variable setting).
- A little bit about ffprobe (FFmpeg) filter:
+ example: for reference only.
https://stackoverflow.com/questions/38056970/ffmpeg-txt-from-audio-levels
https://stackoverflow.com/questions/32254818/generating-a-waveform-using-ffmpeg
+ more update:
https://ffmpeg.org/ffmpeg-filters.html#astats-1
https://trac.ffmpeg.org/wiki/FilteringGuide
+ "pkt_pts_time" parameter: was ignored from late 2021. We still keep this para along with the command or will get nothing out of log file(!!!).
OTW, it had been looked like: (source: Internet, @Gyan, commented Jun 27, 2016 at 19:4, stackoverflow.com as above link)
hit command [ffprobe -f lavfi -i
amovie=audio.aac,
astats=metadata=1:reset=1
-show_entries
frame=pkt_pts_time:frame_tags=lavfi.astats.Overall.RMS_level,lavfi.astats.1.RMS_level,lavfi.astats.2.RMS_level
-of csv=p=0]
=> got resuslt: (1st column is pkt_pts_time in sec, followed by overall RMS_level, 1 (Left channel ?) RMS_level and lastly 2(right channel ?) RMS_level).
Duration: N/A, start: 0.023220, bitrate: N/A
Stream #0:0: Audio: pcm_f64le, 44100 Hz, stereo, dbl, 5644 kb/s
0.023220,-inf,-inf,-inf
0.046440,-inf,-inf,-inf
0.069660,-inf,-inf,-inf
0.092880,-27.330401,-22.685612,-24.414572
0.116100,-21.141091,-18.986082,-19.931269
0.139320,-20.955719,-18.549085,-19.587788
0.162540,-20.938002,-18.198237,-19.355561
0.185760,-19.852306,-20.032553,-19.941494
0.208980,-20.495281,-21.684953,-21.049508
/*/
// Music can bring happiness, let it on.
Post installation prompt
chech ffprobe.exe file
fobar2000-v2\skins\external_helper\ffprobe.exe
Looks cool! :) I assume you used ffprobe instead of audiowaveform (easier) to support both RMS and peaks, dont you? Did you find anything useful on the process I should port back?
Maybe @TT is interested on doing something similar for Georgia. I have no interest on doing new things for SMP if it never gets ported to x64.
Hi regor,
You are totally right.
I had been struggling with FFmpeg (ffprobe) filter untill i realized that you deployed a rich-function seekbar under SMP.
Stick with ES19 may bring you advantages while i prefer 64bit of JScript Panel 3, not just because Marc2003 is very active in updating new features.
I am thinking of getting FFmpeg filter exported log data into memory (stdout) on-the-fly to deal with online media.
FFmpeg is a good fundamental media processing, foobar2000 is based on that platform among others.
this ensures that, getting along with FFmpeg is a right choice, not to mention they speak the same l'anguage'.
this 'JSP3 64bit VU Meter' script provides RMS and PEAK data as 32bit Analog VU Meter component once utilised as an ActiveX Object.
i just enclosed a sample script illustrated playing around with those values. others may have better ideas.
again, thank you very much for your endless effort contribution to audio-lovers with SMP scripts.
diving into your codes makes me think you are professional dev instead of an artist.
wish you all the best,
Stop using ActiveX filth like WshShell.Run. :P
https://jscript-panel.github.io/docs/namespaces/utils/#utilsruncmdasyncwindow_id-app-params
hi @marc2k3,
it is my honor to receive your feedback, and is amazing that year after year you are still be with us.
without you, WSHscript will never evolve into JScript Panel 3, even JScript Panel 2.
regarding the script, i did note JSP3 utils async run command, but leaving the algorithm followed serial processing to keep it simple. in saying that, i have another script with async and syn option to extract raw data from FFmpeg filter.
thank you a lot.
Hi @all,
This is a 64bit JScript Panel3, named "JSP3 64bit VU Meter" after 32bit "Analog VU Meter" component.
Feature:
# pseudo-"Analog Vu Meter" 64bit component.
(get RMS_Level and Peak_level of 2 channels).
# VU Meter colors can be changed on-the-fly (as sample attached).
limitation:
# local media files only.
# latency (at first run due to raw-data processing).
# files cached (deleted per foorbar2000 session by default).
An implementation sample script is attached for your quick reference.
You all are free to use and make any changes.
Cheer,
#viking aka ilovefb2k @vnav 01Aug24.
.
/*/ -------< P/S >-------------
-Inspired by
i> regorxxx's SMP script: Not a Waveform Seekbar
https://regorxxx.github.io/foobar2000-SMP.github.io/scripts/not-a-waveform-seekbar-smp/
and;
ii> Marc2003: Spectrogram Seekbar
https://jscript-panel.github.io/gallery/spectrogram-seekbar/
- dependency: 'ffprobe.exe' copied to as this folder: fb.ProfilePath + 'skins\\external_helper\\ffprobe.exe'
link : https://www.ffmpeg.org/
version test: https://www.gyan.dev/ffmpeg/builds/ , 2024-07-01 v46
- A little bit about algorithm:
+ get ffprobe.exe exported log file, including RMS_Level, Pek_Level value/data
+ transforming these raw_data into read-to-use:
- cleaning data.
- converting dB [-100,0] into number [0,1].
- adjusting frame number to increase refresh rate if any (varied between 26-92 ms/frame as quick observation)
- caching data to disk for next use (if any).
- delete all data files once foobar2000 "on" exit. (can be variable setting).
- A little bit about ffprobe (FFmpeg) filter:
+ example: for reference only.
https://stackoverflow.com/questions/38056970/ffmpeg-txt-from-audio-levels
https://stackoverflow.com/questions/32254818/generating-a-waveform-using-ffmpeg
+ more update:
https://ffmpeg.org/ffmpeg-filters.html#astats-1
https://trac.ffmpeg.org/wiki/FilteringGuide
+ "pkt_pts_time" parameter: was ignored from late 2021. We still keep this para along with the command or will get nothing out of log file(!!!).
OTW, it had been looked like: (source: Internet, @Gyan, commented Jun 27, 2016 at 19:4, stackoverflow.com as above link)
hit command [ffprobe -f lavfi -i
amovie=audio.aac,
astats=metadata=1:reset=1
-show_entries
frame=pkt_pts_time:frame_tags=lavfi.astats.Overall.RMS_level,lavfi.astats.1.RMS_level,lavfi.astats.2.RMS_level
-of csv=p=0]
=> got resuslt: (1st column is pkt_pts_time in sec, followed by overall RMS_level, 1 (Left channel ?) RMS_level and lastly 2(right channel ?) RMS_level).
Duration: N/A, start: 0.023220, bitrate: N/A
Stream #0:0: Audio: pcm_f64le, 44100 Hz, stereo, dbl, 5644 kb/s
0.023220,-inf,-inf,-inf
0.046440,-inf,-inf,-inf
0.069660,-inf,-inf,-inf
0.092880,-27.330401,-22.685612,-24.414572
0.116100,-21.141091,-18.986082,-19.931269
0.139320,-20.955719,-18.549085,-19.587788
0.162540,-20.938002,-18.198237,-19.355561
0.185760,-19.852306,-20.032553,-19.941494
0.208980,-20.495281,-21.684953,-21.049508
/*/
// Music can bring happiness, let it on.
Post installation prompt
chech ffprobe.exe file
fobar2000-v2\skins\external_helper\ffprobe.exe
hi sq68,
i noed your feedback hours ago but cannot feedback until i can access this site.
as mentioned, the script depends on ffprobe.exe, which is a stand-alone exe file to get RMS and PEAK level per channel.
you can follow marc2k3's instruction to download that file (link
https://jscript-panel.github.io/gallery/spectrogram-seekbar/)
cheer,
ilovefb2k.
@ilovefb2k
Is this the only color choice for the VU Meter?
(https://i.imgur.com/CwIcgdb.png)
Is it not possible to use FFmpeg showspectrumpic - color?
FFmpeg
showspectrumpic - color
‘channel’, ‘intensity’, ‘rainbow’ etc...
https://ffmpeg.org/ffmpeg-filters.html#showspectrumpic
Get the same result with the Spectrum Analyzer plugin:
(https://i.postimg.cc/ykHyQJZQ/Immagine-2024-08-02-070836.png) (https://postimg.cc/ykHyQJZQ)
Post installation prompt
chech ffprobe.exe file
fobar2000-v2\skins\external_helper\ffprobe.exe
Not sure how to interpret this post, if you're asking where to find ffprobe.exe it's in the same package as the complete ffmpeg install download from here: https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-full.7z (https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-full.7z) . It's inside the subfolder "bin" within.
I haven't used this meter yet but I imagine you could alter the script to point to a location for ffprobe.exe outside of the Foobar profile folder to avoid having to increase the size of a Foobar Portable backup by 130mb. For example, changing line 275 to read:
ffprobe : "C:\\ffprobe\\ffprobe.exe",
If you have the file already in your PATH environmental variable in Windows you may be able to substitute the location as simply %PATH% . Those who have installed the meter, feel free to correct me!!
@ilovefb2k
Is this the only color choice for the VU Meter?
Is it not possible to use FFmpeg showspectrumpic - color?
Can answer that. FFmpeg is only used to calculate the RMS values, not to display anything. Thus colors are set at the JS file. What you ask is simply not possible.
That's said, the author may provide more color options or whatever. But all has to be done within JS.
@regor
Many Thanks.
Post installation prompt
chech ffprobe.exe file
fobar2000-v2\skins\external_helper\ffprobe.exe
Not sure how to interpret this post, if you're asking where to find ffprobe.exe it's in the same package as the complete ffmpeg install download from here: https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-full.7z (https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-full.7z) . It's inside the subfolder "bin" within.
I haven't used this meter yet but I imagine you could alter the script to point to a location for ffprobe.exe outside of the Foobar profile folder to avoid having to increase the size of a Foobar Portable backup by 130mb. For example, changing line 275 to read:
ffprobe : "C:\\ffprobe\\ffprobe.exe",
If you have the file already in your PATH environmental variable in Windows you may be able to substitute the location as simply %PATH% . Those who have installed the meter, feel free to correct me!!
thanks!
Looks cool! :) I assume you used ffprobe instead of audiowaveform (easier) to support both RMS and peaks, dont you? Did you find anything useful on the process I should port back?
Maybe @TT is interested on doing something similar for Georgia. I have no interest on doing new things for SMP if it never gets ported to x64.
Hi
@regor,
actually we had this conversation 1.5 years ago and you told me that it may be possible to retrieve the levels and peaks from ffmpeg.
It's great that someone has written it and that we now have script, but I dunno... Actually I am not a big fan of this method.
My implemented peakmeter works flawlessly with the old foo_vis_vumeter component with instant data processing...
Well, now we have this big dilemma and imo it is kinda schizophrenic. We do not know if SMP will ONE day get continued active
development again and x64 conversion, on the other hand there are more and more people using JScript with these old stone age JS features and limitations.
Why would I make the extra work of implementing ffmpeg level and peak data retrieval, if SMP will not return to active development and x64?
Also IF Yuri returns, he could implement it in SMP directly and that would be much better.
I do not understand ( that's not really true but whatever... ) why in this community, there always needs to be a ONE MAN show
doing their own thing without any team work effort and help. Instead of beating a dead old horse, how about continue the work
where one has left and when he returns, work together as a team? Sounds easy? Because it actually is that easy...
Anyways, this whole situation is really weird, just think about it...
-TT
Reply #1644
@ilovefb2k
Is this the only color choice for the VU Meter?
Is it not possible to use FFmpeg showspectrumpic - color?
Can answer that. FFmpeg is only used to calculate the RMS values, not to display anything. Thus colors are set at the JS file. What you ask is simply not possible.
That's said, the author may provide more color options or whatever. But all has to be done within JS.
Hi @rego,
Again, thank you for your helpful support regarding the scripts and prompt feedback to @Air KEN. (Frankly, it is a little inconvenient for me to travel to some café to enable login into this site).
Hi @Air KEN and @all,
It’s me again, and as @rego pointed out, this script serves as a VU Meter provider only, in terms of Peak and RMS level data of 2 channels. I was still comfortable with the Analog VU Meter component (foo_vis_vumeter) until I switched to foobar2000 64-bit.
Having said that, this 64-bit VU Meter is in no way comparable to foo_vis_vumeter but may be useful to some extent. That said, we can apply any colors, step number or create any VU Meter shape (bar, cycle, etc.) as we like - the sky is our limit.
Not to mention its 64-bit capability, this approach may lead us to the FFmpeg framework (ffmpeg, ffprobe, ffplay) with a lot of features behind its ton of parameters.
Attached is a very simple and quick sample utilizing these Peak and RMS levels in building a bar or cycle VU Meter. I have left as many comments as possible within the script for easy reference.
Credit goes to @rego and @Marc2k3 for their endless effort in creating beautiful scripts.
Wish you all a nice weekend.
Cheers,
@Air KEN, Let me know if there’s anything else you need help with!
P/S. Can anyone shed me a light on how to stop this site from keeping me banning without reason. It is annoying that i have to go to some cafe to get access.
ilovefb2k.
I haven't used this meter yet but I imagine you could alter the script to point to a location for ffprobe.exe outside of the Foobar profile folder to avoid having to increase the size of a Foobar Portable backup by 130mb. For example, changing line 275 to read:
ffprobe : "C:\\ffprobe\\ffprobe.exe",
If you have the file already in your PATH environmental variable in Windows you may be able to substitute the location as simply %PATH% . Those who have installed the meter, feel free to correct me!!
I have tried substituting the code above in line 275 of version 1.0 for using an external location for ffprobe.exe (i.e. not in the Foobar profile folder) but while I get the GUI meter on the top panel I get no statistics panel below it so I assume it's not finding ffprobe.
Can someone give me a working replacement line for specifying ffprobe in the above location? This is the version 1.0 script; in 1.1.1 the line would be 776. It appears the scripts may be attempting to verify the location with additional entries, or do I just have the syntax wrong? Thanks!
@ilovefb2k
Thanks. ;)
(https://i.imgur.com/oiylfNV.png)
(https://i.imgur.com/Z6oUvCs.png)
Air Ken- could you please post the scripts you used for the nice colored meter versions in your last post?
Also, do you have any idea on how to resolve my scripting ffprobe.exe for an external location as described in my previous post?
Thanks for any help!
@sveakul
This is a default script.
Reply #1636 By: ilovefb2k
JSP3_64bit_VU_Meter_script.txt
https://hydrogenaud.io/index.php/topic,110516.msg1048520.html#msg1048520
https://hydrogenaud.io/index.php/topic,110516.msg1048559.html#msg1048559
> Also, do you have any idea on how to resolve my scripting ffprobe.exe for an external location as described in my previous post?
No. I just did as instructed
Reply #1636 By: ilovefb2k
> - dependency: 'ffprobe.exe' copied to as this folder: fb.ProfilePath + 'skins\\external_helper\\ffprobe.exe'
------
Reply #1592 By: ilovefb2k
JSPP3_fb2k0 (64 bit Windows11 - screen fullHD 150pct)_22Jul24.rar
https://hydrogenaud.io/index.php/topic,110516.msg1048254.html#msg1048254
Additional image folder
Reply #1593
{deployed} album_art [cd-vinyl].rar
https://hydrogenaud.io/index.php/topic,110516.msg1048255.html#msg1048255
Create an "external_helper" folder in the skin folder and put "ffprobe.exe" from the ffmpeg bin folder into the "external_helper" folder.
-----
"skins" folder:
\profile\skins or \AppData\Roaming\foobar2000-v2\skins
\profile\$recycle.bin folder
"Script":
\profile\skins\viking\scripts\jsp3 *.txt file (I am copying "JSP3_64bit_VU_Meter_script.txt" and "JSP3 64bit VUMeter_ver 1.1.1.txt" here)
\profile\skins\viking\scripts\jsp3_lib\vnav_mod *.jis file
An application the size of ffprobe.exe should be able to be called from anywhere when needed in a script, not be forced to be inside the Foobar structure. I have the portable version which I back up often, and that would add another 130mb to the folder size. For marc2k3's Spectrogram Seekbar, I already call ffmpeg.exe from an external location with a simple mod to that script. I'm sure the same can be done here with ffprobe.exe. Anyone?
An application the size of ffprobe.exe should be able to be called from anywhere when needed in a script, not be forced to be inside the Foobar structure. I have the portable version which I back up often, and that would add another 130mb to the folder size. For marc2k3's Spectrogram Seekbar, I already call ffmpeg.exe from an external location with a simple mod to that script. I'm sure the same can be done here with ffprobe.exe. Anyone?
Sure there is a way to make it work properly via CMD, but... nothing stops you to have a single place with the binary and create symlinks to it within foobar folder :)
@TT have nothing to add to your words and I mostly agree with all of them. Also found pretty weird to disregard a working 64 bits SMP and instead start an abstract new project without any deadline. But in the end of the day, anyone does whatever they wants with their work, so...
Sure there is a way to make it work properly via CMD, but... nothing stops you to have a single place with the binary and create symlinks to it within foobar folder :)
Symlinks being a new concept for me I was hoping to not have to learn a new technique to be able to do a simple "the file is located here" js code replacement and have it work. Actually it surprises me that files already specified in my PATH environmental variables would need to have their locations specified but that shows you I'm no javascript expert either. More like monkey-see, monkey-do, haha..
Since you hint there is way to make it work properly using the "old school" method I would be grateful if you would share that with me.
I found out that the path replacement for ffprobe.exe I already posted was working fine as far as displaying the basic meter and action, and didn't produce a "file not found" error. However, I had installed the script directly into a new jsp3 panel, not into a "skins" subfolder nor did I have any of the viking scripts, vnav_mod etc. installed as linked to by Air Ken. That's why the text values, extra colors, and proper movement of the circular meter weren't happening. Anyway, for me, too much support files needed for a VU meter, albeit pretty. I had figured it was just a straight JSP3 script addition, like a new sample. Thanks though to ilovefb2k for posting his code, I just misunderstood the actual requirements.
Hi Air Ken,
You mean script "{deployed} album_art [cd-vinyl].txt" !?
This script from and @Jul23 as stated, and we also need some images from TT (TT-ReBORN.Georgia-ReBORN) to apply CD/Vinyl mask.
As such, i was hesitant to enclose them with the early post.
Attached is these images in their folder structure. we can unzip and copy them into [foobar2000] root folder and the script should be compiled without error.
Credit goes to Jul23, TT for their hard work in creating beautiful CD/vinyl images.
Artwork is randomly tilted.
Cheer.
note: as i am not sure about IP in other countries, whether or not some artworks were under public domain or not, i can not make any screenshot. sorry.
I think of some pseudo screenshots.
It is weir that my web browser usually get stuck (banned) accessing this site.
The script "{deployed} album_art [cd-vinyl].txt" shows album art often in gray instead of color.
Hi Air Ken,
You mean script "{deployed} album_art [cd-vinyl].txt" !?
This script from and @Jul23 as stated, and we also need some images from TT (TT-ReBORN.Georgia-ReBORN) to apply CD/Vinyl mask.
As such, i was hesitant to enclose them with the early post.
Attached is these images in their folder structure. we can unzip and copy them into [foobar2000] root folder and the script should be compiled without error.
Credit goes to Jul23, TT for their hard work in creating beautiful CD/vinyl images.
Artwork is randomly tilted.
Cheer.
note: as i am not sure about IP in other countries, whether or not some artworks were under public domain or not, i can not make any screenshot. sorry.
I think of some pseudo screenshots.
It is weir that my web browser usually get stuck (banned) accessing this site.
The script "{deployed} album_art [cd-vinyl].txt" shows album art often in gray instead of color.
Send your new script of the vinyl . I would like to see it . Thanks you guys
@Jul2323
(https://i.imgur.com/DQTpreY.png)
Right click on the CD Panel > Spin
Reply #1592 By: ilovefb2k
JSPP3_fb2k0 (64 bit Windows11 - screen fullHD 150pct)_22Jul24.rar
https://hydrogenaud.io/index.php/topic,110516.msg1048254.html#msg1048254
Additional image folder
Reply #1593
{deployed} album_art [cd-vinyl].rar
https://hydrogenaud.io/index.php/topic,110516.msg1048255.html#msg1048255
"skins" folder:
\profile\skins or \AppData\Roaming\foobar2000-v2\skins
\profile\$recycle.bin folder
"Script":
\profile\skins\viking\scripts\jsp3 *.txt file
\profile\skins\viking\scripts\jsp3_lib\vnav_mod *.jis file
------------------
\profile\skins\viking\scripts\jsp3\{deployed} album_art [cd-vinyl].txt
\profile\skins\viking\images\vnav_fb2k\mask\TT-ReBORN.Georgia-ReBORN (CD Image folder)
(https://i.imgur.com/P4mRW9Y.png)
Hi Air Ken,
You mean script "{deployed} album_art [cd-vinyl].txt" !?
This script from and @Jul23 as stated, and we also need some images from TT (TT-ReBORN.Georgia-ReBORN) to apply CD/Vinyl mask.
As such, i was hesitant to enclose them with the early post.
Attached is these images in their folder structure. we can unzip and copy them into [foobar2000] root folder and the script should be compiled without error.
Credit goes to Jul23, TT for their hard work in creating beautiful CD/vinyl images.
Artwork is randomly tilted.
Cheer.
note: as i am not sure about IP in other countries, whether or not some artworks were under public domain or not, i can not make any screenshot. sorry.
I think of some pseudo screenshots.
It is weir that my web browser usually get stuck (banned) accessing this site.
The script "{deployed} album_art [cd-vinyl].txt" shows album art often in gray instead of color.
Send your new script of the vinyl . I would like to see it . Thanks you guys
(https://i.postimg.cc/FR6pmHDk/Snipaste-2024-08-06-16-49-06.jpg)
This also requires editing. You can change the CD image by changing the image file name.
CD Album Art
{deployed} album_art [cd-vinyl].txt
(https://i.imgur.com/jScVo70.png)
Sorry.
{deployed} album_art [cd-vinyl].txt:
I tried the following, but I got an error: Line 320: So I added // to the beginning of Line 320:
gr.DrawImage(common-cd-blank, (www * 100) / 1390 , (whh * 48) / 2400, whh / circle2_ratio, whh / circle2_ratio, 0, 0, common-cd-blank.Width, common-cd-blank.Height, 1, angle_circle );
// gr.DrawImage(common-cd-blank, (www * 100) / 1390 , (whh * 48) / 2400, whh / circle2_ratio, whh / circle2_ratio, 0, 0, common-cd-blank.Width, common-cd-blank.Height, 1, angle_circle );
Sorry.
{deployed} album_art [cd-vinyl].txt:
I tried the following, but I got an error: Line 320: So I added // to the beginning of Line 320:
gr.DrawImage(common-cd-blank, (www * 100) / 1390 , (whh * 48) / 2400, whh / circle2_ratio, whh / circle2_ratio, 0, 0, common-cd-blank.Width, common-cd-blank.Height, 1, angle_circle );
// gr.DrawImage(common-cd-blank, (www * 100) / 1390 , (whh * 48) / 2400, whh / circle2_ratio, whh / circle2_ratio, 0, 0, common-cd-blank.Width, common-cd-blank.Height, 1, angle_circle );
I'm saying that the artist picture is gray and should have nothing to do with vinyl_circle.png! I have logged out the vinyl_circle.png image.
I'm not looking at other people's scripts but the code that makes it grayscale is
ApplyEffect. Search for that and remove it. An example might look like...
img.ApplyEffect(0);
@sq68
What?
I'm not talking to you.
I'm just talking about CD Album Art.
And we're talking about how to change the CD image.
This is a continuation of my Reply #1659 and Reply #1661.
If you read from the top, you will understand.
It was like I was talking to myself.
@eurekagliese You've seen these changes made to the Custom Track.
There are interesting ideas.
(https://i.postimg.cc/tsWWQQyV/Immagine-2024-08-07-192421.png) (https://postimg.cc/tsWWQQyV)
@eurekagliese
You've seen these changes made to the Custom Track.
There are interesting ideas.
(https://i.postimg.cc/tsWWQQyV/Immagine-2024-08-07-192421.png) (https://postimg.cc/tsWWQQyV)
Looks nice!
Anyway, you may want to use other hosting image, that postimg links are flagged as Potential Security Issue and usually all the image you posted are not shown.
now I'm no expert in scripting, but how hard is it to load a script in as simple as notepad, do a search for "whatever.exe" and change the path to wherever it is located on one's system?
example: latest script from ilovefb2k
var binaries = {
ffprobe : fb.ProfilePath + 'skins\\external_helper\\ffprobe.exe',
}
don't understand what's so difficult in pointing that to wherever one wants...
I found out that the path replacement for ffprobe.exe I already posted was working fine as far as displaying the basic meter and action, and didn't produce a "file not found" error. However, I had installed the script directly into a new jsp3 panel, not into a "skins" subfolder nor did I have any of the viking scripts, vnav_mod etc. installed as linked to by Air Ken. That's why the text values, extra colors, and proper movement of the circular meter weren't happening. Anyway, for me, too much support files needed for a VU meter, albeit pretty. I had figured it was just a straight JSP3 script addition, like a new sample. Thanks though to ilovefb2k for posting his code, I just misunderstood the actual requirements.
What? Support files?
I don't know how you've setup your FB2K env. I run it as a portable, and did just that... dumped the script into a new JSP3 Panel after chaning the path to my ffmpeg home (for ffprobe) and it works... no support files needed other than telling the script where to find ffprobe.
@sq68
> The script "{deployed} album_art [cd-vinyl].txt" shows album art often in gray instead of color.
Reply #1660
https://hydrogenaud.io/index.php/topic,110516.msg1048728.html#msg1048728
Do you mean as weird as this picture?
\profile\skins\viking\images\vnav_fb2k\mask\TT-ReBORN.Georgia-ReBORN (CD Image folder)
The CD images in the "TT-ReBORN.Georgia-ReBORN (CD Image folder)" folder will be changed in order or randomly. Isn't that it?
Click the Next button to confirm.
(https://i.imgur.com/zUztgo3.png)
@sq68
> The script "{deployed} album_art [cd-vinyl].txt" shows album art often in gray instead of color.
Reply #1660
https://hydrogenaud.io/index.php/topic,110516.msg1048728.html#msg1048728
Do you mean as weird as this picture?
\profile\skins\viking\images\vnav_fb2k\mask\TT-ReBORN.Georgia-ReBORN (CD Image folder)
The CD images in the "TT-ReBORN.Georgia-ReBORN (CD Image folder)" folder will be changed in order or randomly. Isn't that it?
Click the Next button to confirm.
(https://i.imgur.com/zUztgo3.png)
Yes, and sometimes normal colors. Thank you!
now I'm no expert in scripting, but how hard is it to load a script in as simple as notepad, do a search for "whatever.exe" and change the path to wherever it is located on one's system?
...what's so difficult in pointing that to wherever one wants...
What? Support files?
I don't know how you've setup your FB2K env. I run it as a portable, and did just that... dumped the script into a new JSP3 Panel after chaning the path to my ffmpeg home (for ffprobe) and it works... no support files needed other than telling the script where to find ffprobe.
True, it's not difficult. I changed the pointer to ffprobe : "C:\\ffprobe\\ffprobe.exe", and it finds that file just fine.
Then I dumped the script "JSP3_64bit_VU_Meter_script.txt" from ilovefb2k's reply #1636 into a JSP3 panel with that path mod.
On playing files however, I only got a fundamental bar image which is reactive but missing both the dB scale and the RMS channel level summaries below it:
(https://i.imgur.com/r8HFi0H.png)
I then read Air Ken's post (https://hydrogenaud.io/index.php/topic,110516.msg1048616.html#msg1048616) where at the end he mentions a "skins" folder (I don't have any skins), and also says concerning scripts that:
"Script":
\profile\skins\viking\scripts\jsp3 *.txt file (I am copying "JSP3_64bit_VU_Meter_script.txt" and "JSP3 64bit VUMeter_ver 1.1.1.txt" here)
\profile\skins\viking\scripts\jsp3_lib\vnav_mod *.jis file"
As I have just a straight JSP3 install and his comment mentions skins and "jsp3_lib\vnav_mod *.jis file" I assume I am missing some kind of support files needed to produce the missing scale and RMS summaries below the meter image.
I'm happy to take any guidance that will help me produce the image ilovefb2k originally attached:
(https://i.imgur.com/yCAM8NN.jpeg)
ilovefb2k's Script
I'll just paste the link
Reply #1570 By: ilovefb2k
https://hydrogenaud.io/index.php/topic,110516.msg1048177.html#msg1048177
Scree Shot
https://hydrogenaud.io/index.php/topic,110516.msg1048256.html#msg1048256
New:
Reply #1592
https://hydrogenaud.io/index.php/topic,110516.msg1048254.html#msg1048254
Reply #1593
CD image folder
https://hydrogenaud.io/index.php/topic,110516.msg1048255.html#msg1048255
----------
Reply #1636 By: ilovefb2k
JSP3_64bit_VU_Meter_script.txt
https://hydrogenaud.io/index.php/topic,110516.msg1048520.html#msg1048520
- dependency: 'ffprobe.exe' copied to as this folder: fb.ProfilePath + 'skins\\external_helper\\ffprobe.exe'
https://hydrogenaud.io/index.php/topic,110516.msg1048559.html#msg1048559
----------
Again, I followed the developer's instructions (read.me), which is what I always do when I do testing, and then edited what I could.
New:
Reply #1648 By: ilovefb2k
JSP3 64bit VUMeter_ver 1.1.1
https://hydrogenaud.io/index.php/topic,110516.msg1048606.html#msg1048606
https://hydrogenaud.io/index.php/topic,110516.msg1048610.html#msg1048610
@eurekagliese
You've seen these changes made to the Custom Track.
There are interesting ideas.
(https://i.postimg.cc/tsWWQQyV/Immagine-2024-08-07-192421.png) (https://postimg.cc/tsWWQQyV)
Looks nice!
Anyway, you may want to use other hosting image, that postimg links are flagged as Potential Security Issue and usually all the image you posted are not shown.
@eurekaglieseIf you then confirm that this site for uploading images is fine.
Thank you
(https://i.imgur.com/wRDfrNM.png)
(https://imgur.com/LDrGzK5.png)
(https://i.imgur.com/eRl6b6U.png)
If you then confirm that this site for uploading images is fine.
Thank you
The links is fine and the images are shown now.
Air Ken: Thanks for your response to my question about the VU meter by posting links and images, but they do not answer my question.
My question is, why, if I have added a new JSP3 panel with the same script ""JSP3 64bit VU Meter" posted by ilovefb2k attached to his post at https://hydrogenaud.io/index.php/topic,110516.msg1048520.html#msg1048520 (https://hydrogenaud.io/index.php/topic,110516.msg1048520.html#msg1048520) , I do not get a panel image that matches what he attached to the same post.
Instead, I get the first image I posted here: https://hydrogenaud.io/index.php/topic,110516.msg1048794.html#msg1048794 (https://hydrogenaud.io/index.php/topic,110516.msg1048794.html#msg1048794)
Can anyone explain to me what I am missing?
This post is a compilation of ilovefb2k's Script for the benefit of users who view it.
Reply #1672
Reply #1673
-----
I haven't received a clear answer here either, so I don't fully understand how to adjust the colors. I'll just have to play around with it and check it out myself.
https://hydrogenaud.io/index.php/topic,110516.msg1048559.html#msg1048559
Reply #1648
https://hydrogenaud.io/index.php/topic,110516.msg1048606.html#msg1048606
> Having said that, this 64-bit VU Meter is in no way comparable to foo_vis_vumeter but may be useful to some extent. That said, we can apply any colors, step number or create any VU Meter shape (bar, cycle, etc.) as we like - the sky is our limit.
> Not to mention its 64-bit capability, this approach may lead us to the FFmpeg framework (ffmpeg, ffprobe, ffplay) with a lot of features behind its ton of parameters.
I've looked into it myself but I don't understand it at all.
-----
> P/S. Can anyone shed me a light on how to stop this site from keeping me banning without reason. It is annoying that i have to go to some cafe to get access.
ilovefb2k needs help, does anyone know?
To Anybody: I am just looking for a clear, text reply to the following question:
"Why, if I have added a new JSP3 panel with the same script "JSP3 64bit VU Meter" posted by ilovefb2k attached to his post at https://hydrogenaud.io/index.php/topic,110516.msg1048520.html#msg1048520 , I do NOT get a panel image that matches what he attached to the same post. Instead, I get the first image I posted here: https://hydrogenaud.io/index.php/topic,110516.msg1048794.html#msg1048794."
Obviously, something more was required than just adding the supplied JSP3 script.
To Anybody: I am just looking for a clear, text reply to the following question:
"Why, if I have added a new JSP3 panel with the same script "JSP3 64bit VU Meter" posted by ilovefb2k attached to his post at https://hydrogenaud.io/index.php/topic,110516.msg1048520.html#msg1048520 , I do NOT get a panel image that matches what he attached to the same post. Instead, I get the first image I posted here: https://hydrogenaud.io/index.php/topic,110516.msg1048794.html#msg1048794."
Obviously, something more was required than just adding the supplied JSP3 script.
First the script is missing on_colours_changed() function.
function on_colours_changed() {
update_colours();
window.Repaint();
}
So if you change the colours DUI or CUI in preferences they won't change until you reload the script.
As for your problem my guess is that somewhere in the script your colour selected for text is the same colour as the background.
Are you using DUI or CUI ?
Hi Zeremy, good to see you back! Thanks for giving me some real answers on this problem. I am using DUI. After reading your comments I'm almost sure my issue with no text is due to what you surmise about the text color in the script disappearing into my background color, as his shows in the image as being black with an off-white text.
I had thought whatever the color settings were in the script he posted would reflect what showed on my end, but if he started with using Foobar's "Dark Mode" which I am not (I use System - DUI) I guess an empty JSP3 panel would look black instead of white by default.
His script is rather hard for a novice to interpret as it is full of comment lines, variations for DUI/CUI, and what looks like pieces of script originally meant for SMP as well. If you could just give me a place to start, I'm looking for basically what he posted as the image, with a black background, white text, and blue meter bars--especially if you could point me to where the color of the bar pieces themselves may be modified, and the line #'s affecting text & background color. Once again, I'm referring to the script and the image he posted as attachments here:
https://hydrogenaud.io/index.php/topic,110516.msg1048520.html#msg1048520 (https://hydrogenaud.io/index.php/topic,110516.msg1048520.html#msg1048520) .
Thank you for helping me sort this out!
Hi Zeremy, good to see you back! Thanks for giving me some real answers on this problem. I am using DUI. After reading your comments I'm almost sure my issue with no text is due to what you surmise about the text color in the script disappearing into my background color, as his shows in the image as being black with an off-white text.
I had thought whatever the color settings were in the script he posted would reflect what showed on my end, but if he started with using Foobar's "Dark Mode" which I am not (I use System - DUI) I guess an empty JSP3 panel would look black instead of white by default.
His script is rather hard for a novice to interpret as it is full of comment lines, variations for DUI/CUI, and what looks like pieces of script originally meant for SMP as well. If you could just give me a place to start, I'm looking for basically what he posted as the image, with a black background, white text, and blue meter bars--especially if you could point me to where the color of the bar pieces themselves may be modified, and the line #'s affecting text & background color. Once again, I'm referring to the script and the image he posted as attachments here:
https://hydrogenaud.io/index.php/topic,110516.msg1048520.html#msg1048520 (https://hydrogenaud.io/index.php/topic,110516.msg1048520.html#msg1048520) .
Thank you for helping me sort this out!
@ilovefb2k I hope you don't mind - I made a few modifications, regarding the colours.
@sveakul You can override the default selection of colours that are loaded from DUI or CUI preferences at lines 94-95-96 (comment the lines out - remove the // s)
The values are what you asked for ( black background, white text, and blue meter bars)
At lines 98,99 you can define the 2 colours that are blended to create the vu bars
eg. black to red
color_1 = RGB(0,0,0);
color_2 = RGB(250,0,0);
Keep in mind that the latency is high
( on my pc it takes about 10sec to ffprobe the file and start displaying the vu bars)
@zeremy
Thank you for editing the script.
> At lines 98,99 you can define the 2 colours that are blended to create the vu bars
I don't understand the effect of lines 98 and 99.
Thanks.
(https://i.imgur.com/9579ZR5.png)
(https://i.imgur.com/5DaysB9.png)
(https://i.imgur.com/BYnlVJN.png)
@zeremy
Thank you for editing the script.
> At lines 98,99 you can define the 2 colours that are blended to create the vu bars
I don't understand the effect of lines 98 and 99.
Thanks.
(https://i.imgur.com/9579ZR5.png)
(https://i.imgur.com/5DaysB9.png)
(https://i.imgur.com/BYnlVJN.png)
@Airken The script I modified was version 1.1.0.
It has 2 colours, the effect of your example is to blend the colours starting from white and ending in blue
The other script in your pictures is version 1.1.1. which is different.
It uses 3 colours.
Yes, I know. Here is the image below.
Sorry. It's hard to understand.
> At lines 98,99 you can define the 2 colours that are blended to create the vu bars
I don't understand the effect of lines 98 and 99.
Thanks.
(https://i.imgur.com/WxQqKq6.png)
(https://i.imgur.com/BYnlVJN.png)
@marc2k3 - perhaps you should do like pgyt and give these people access to raw audio data from visualization stream. It's insane what they are doing.
@zeremy : Thanks a million for the mod script and explanations on the settings locations for the JSP3 VU Meter 1.0! Here are some observations of my own now that was able to get a sample script up and running for my DUI Foobar, no "Dark Mode" but has black Background color scheme. Line #'s refer to the ones in my modified script which is attached.
1. You can point the script to an external copy of ffprobe.exe by changing line #292 to i.e. :
ffprobe: 'C:\\ffmpeg\\ffprobe.exe',
2. As zeremy says there is about a 10s. latency delay before the start of the meter action while script caches the four RMS values across the whole song. These are saved per song in a *.js file in its cache folder and persist while Foobar is open, so if replayed the initial latency is gone. This folder is deleted when Foobar is closed to prevent an infinitely growing cache.
3. The RMS values are normally displayed in real-time at the bottom area of the panel as in other's screenshots, but I found these numbers to change so rapidly while the song played that they were too much of a distraction for my eyes. I deleted their text display by editing the //legend section which begins on line #243 to only write the refresh rate values. This also gave the ability to use the same panel height I use for all my tabbed meters. See attached screenshot.
4. While not designed to function properly for streaming radio, ilovefb2k mentioned in a post that, "I am thinking of getting FFmpeg (to) filter exported log data into memory (stdout) on-the-fly to deal with online media."
I strongly encourage ilovefb2k or someone else to implement this, so the meter can be used with radio streams as well as fixed files like any standard VU Meter.So I've attached where I'm at now, and my next step will be experimenting with the bar color blends. Thanks again to zeremy.
Sorry. It's hard to understand.
> At lines 98,99 you can define the 2 colours that are blended to create the vu bars
I don't understand the effect of lines 98 and 99.
Thanks.
(https://i.imgur.com/WxQqKq6.png)
(https://i.imgur.com/BYnlVJN.png)
Either use the default values
color_1 = colours.text;
color_2 = colours.highlight;
or define whatever other like this
color_1 = RGB(250,250,250);
color_2 = RGB(255,0,0);
@marc2k3 - perhaps you should do like pgyt and give these people access to raw audio data from visualization stream. It's insane what they are doing.
Case we're just having fun with what we've got to experiment with!
JSP3 VU Meter when running creates a set of subdirectories in the profile\$recycle.bin\js_data folder based on file tag, such as:
C:\foobar2000-x64_v2\profile\$recycle.bin\js_data\jsp3_vu_meter\aqua\euro hits forever
In the last "album" folder a json file is created based on the song title, like in this case "Barbie Girl.json", in which a long string of all the changing RMS peak/average value numbers for each channel are written.
While this file is deleted along with all the subdirectories when Foobar is closed, I found that commenting out (//) line #524 in the script I last posted (JSP3_64bit_VU_Meter-SV1.txt) will prevent the script from creating and writing values into the (filename).json file. While the tag-based folder structure is still created (and deleted normally when closing Foobar), the values file never is, saving a multitude of file-write operations (think, "SSD"). The only drawback is that if you play the same file again while Foobar is open the meter will exhibit the initial latency period it did before.
The script including both this and the mods made in *-SV1 is attached below.
@marc2k3 - perhaps you should do like pgyt and give these people access to raw audio data from visualization stream. It's insane what they are doing.
It is absolutely insane and it's to my eternal credit that I've kept quiet on this instead of resorting to my usual insults. :D
But it's less insane than me trying to implement this. I don't know anything about working with audio data. pqyt already maintained a vis component before he started. I'm an uneducated oik who knows nothing. I don't understand anything about the underlying concepts. I had a quick peak at the webview source and I have no idea what to do with it. :o
FFmpeg is a good fundamental media processing, foobar2000 is based on that platform among others.
Small clarification. foobar2000 is in no way based on FFmpeg. At some point a few decoders were switched from other libraries to decoders found in FFmpeg because they were faster and better. And some of these decoders have been reverted back away from FFmpeg because they turned out to be too buggy.
P/S. Can anyone shed me a light on how to stop this site from keeping me banning without reason. It is annoying that i have to go to some cafe to get access.
How do you connect to the site? I believe some anonymizing VPN services are banned/blocked because of abuse. I also fear that when a spammer is banned the IP-address that was used is banned with the account. Personally I don't believe in IP-banning as the problematic spammers are not stuck with a static IP.
I'm not sure VPN bans will be lifted, but if your normal connection's IP is blocked, you can for example PM the IP info to me and I'll try to get an admin to remove the ban.
@zeremy
Thanks.
@sveakul
JSP3_64bit_VU_Meter-SV2.txt
Nice!
I'm toying with the idea of providing audio data but I really have no idea what I'm doing.
@Case , if you have a minute or 2 could you check this...
I'm thinking of JS code like this...
// offset is optional, defaults to zero
var chunk = fb.GetAudioChunk(requested_length, offset);
if (chunk) {
// expose these properties
// chunk.ChannelConfig
// chunk.ChannelCount
// chunk.SampleRate
// chunk.SampleCount
// chunk.Data
var data = chunk.Data.toArray();
var channel_count = chunk.ChannelCount;
for (var i = 0; i < data.length; i += channel_count) {
// assuming stereo
var l = data[i];
var r = data[i + 1];
}
}
The C++...
STDMETHODIMP Fb::GetAudioChunk(double requested_length, double offset, IAudioChunk** out)
{
RETURN_HR_IF_NULL(E_POINTER, out);
*out = nullptr;
if (m_vis.is_valid())
{
double time{};
if (m_vis->get_absolute_time(time))
{
audio_chunk_impl chunk;
if (m_vis->get_chunk_absolute(chunk, time + offset, requested_length))
{
*out = new ComObject<AudioChunk>(chunk);
}
}
}
return S_OK;
}
Looks correct. I'm not JavaScript guru, but do you need the .toArray() call in javascript part? Isn't the data already accessible without copying it into yet another buffer?
It's a VARIANT in C++
https://github.com/jscript-panel/Core/blob/48f3cff3932f10a26336eb6a7ceb8a70805ef48a/ComArrayWriter.cpp#L110-L114
And this is somehow a VBArray(??) in script and it can't be accessed directly. The toArray is the what makes it a "normal" JS array.
edit: I will use the performance profiler in VS before contemplating release to see if there any sticky points,
I am trying to replace Spider Monkey Panel with JScript Panel for and I almost got it except the ugly NULL showing in the picture below
JScript Panel
(https://i.imgur.com/ge3oH7z.png)
Spider Monkey Panel
(https://i.imgur.com/0CUYxBo.png)
Urgh, that instruction to use null in the panel settings is a mess and needs removing. Look out for a release later on tonight.
Reply #1680 – 2024-08-09 20:31:50
Hi Zeremy, good to see you back! Thanks for giving me some real answers on this problem. I am using DUI. After reading your comments I'm almost sure my issue with no text is due to what you surmise about the text color in the script disappearing into my background color, as his shows in the image as being black with an off-white text.
I had thought whatever the color settings were in the script he posted would reflect what showed on my end, but if he started with using Foobar's "Dark Mode" which I am not (I use System - DUI) I guess an empty JSP3 panel would look black instead of white by default.
His script is rather hard for a novice to interpret as it is full of comment lines, variations for DUI/CUI, and what looks like pieces of script originally meant for SMP as well. If you could just give me a place to start, I'm looking for basically what he posted as the image, with a black background, white text, and blue meter bars--especially if you could point me to where the color of the bar pieces themselves may be modified, and the line #'s affecting text & background color. Once again, I'm referring to the script and the image he posted as attachments here:
https://hydrogenaud.io/index.php/topic,110516.msg1048520.html#msg1048520 .
Thank you for helping me sort this out!
Hi @Zeremy and @Air KEN,
Thank and appreciate you both for your valued, kind support.
Hi @sveakul,
I apologize for late reply. Upon reviewing the image post from [Reply #1671 – 2024-08-08 06:58:00], it seems that the background and text color in your fb2k (foobar2000) are white (technically, RGB 255,255,255). To address this, we can adjust the settings via the fb2k reference to make them different.
If the text is still not highlighting properly, we’ll need to delve deeper into the script.
If you’re still using ‘JSP1 64bit VU meter’ 1.0,
1. Navigate to line 133 to fix the VU Meter color:
var color_1 = colours.text; // or any color (RGB 250,250,250);
var color_2 = colours.highlight; // or any color (RGB 0,0,0);
In the above code snippet, color_1 and color_2 are assigned by default to the DUI/CUI text and text highlight colors.
These colors serve as gradient colors of VU Meter, with color_1 at the beginning and color_2 at the end of the gradient.
As indicated in the comments, you can assign any color to them using the RGB function (e.g., RGB[r,g,b], where r, g, and b are integers from 0 to 255). Adjusting these color settings to achieve the desired appearance of VU Meter.
2. Additionally, if we navigate to line 235, we can see that the text is written in the text’s DUI/CUI color. This explains why we cannot see this text and the beginning of the VU Meter bar:
gr.WriteText(g_text, font, colours.text, VU_x, yR+h+40, ww, wh);
replace 'colours.text' by other color, e.g black 'RGB(0,0,0)' as following and the text should be visible.
gr.WriteText(g_text, font, RGB(0,0,0), VU_x, yR+h+40, ww, wh);
I have just created another example, in which the ‘JSP3 64-bit Vu Meter’ was applied to a more relevant context.
Regards,
Quote from: ilovefb2k on 2024-08-02 05:28:14
FFmpeg is a good fundamental media processing, foobar2000 is based on that platform among others.
Small clarification. foobar2000 is in no way based on FFmpeg. At some point a few decoders were switched from other libraries to decoders found in FFmpeg because they were faster and better. And some of these decoders have been reverted back away from FFmpeg because they turned out to be too buggy.
Quote from: ilovefb2k on 2024-08-03 06:23:14
P/S. Can anyone shed me a light on how to stop this site from keeping me banning without reason. It is annoying that i have to go to some cafe to get access.
How do you connect to the site? I believe some anonymizing VPN services are banned/blocked because of abuse. I also fear that when a spammer is banned the IP-address that was used is banned with the account. Personally I don't believe in IP-banning as the problematic spammers are not stuck with a static IP.
I'm not sure VPN bans will be lifted, but if your normal connection's IP is blocked, you can for example PM the IP info to me and I'll try to get an admin to remove the ban.
Hi @Case,
Regarding foobar2000 and FFmpeg, I may have misinterpreted the statement “foobar2000 uses FFmpeg under the GNU LGPL v2.1,” which I quoted from the foobar2000 site [https://www.foobar2000.org/ffmpeg]. Thank you for pointing out the correction.
In terms of accessing the Hydrogenaud.io site [https://hydrogenaud.io/], I initially thought my username or IP might be blacklisted. However, even after refreshing my history cache, I encountered the same problem. It appears that this issue is related to region-specific policies, as I was able to access a German site [https://www.mathcs.uni-leipzig.de/]. Interestingly, configuring a VPN at a café’s internet connection resolved the issue for me.
Lastly, thank you for your very useful components as well as your efforts in persuading @Marc2003 to provide us with real-time audio data chunks.
Best regards,
Ilovefb2k
Hi @all,
//Ref: JSP3 64-bit VU Meter (script).
It’s me, the lazy man, again.
My sincere apologies for the delayed response.
As we can see, the ‘JSP3 64-bit VU Meter’ script allows us to customize colors and shape the meter in various ways. Another unique feature is the ability to position it anywhere within the panel by specifying its x and y coordinates. This targeted positioning also enables us to repaint only that specific area, rather than the entire panel. By this way, we can construct our own skin using this flexibility.
I’ve attached an example of the ‘TechnicsRSBX’ skin created by @iprad [https://foobar2000.ru/forum/viewtopic.php?t=5081] around 10 years ago. Originally, this skin employed the ingenious ‘VU Meter’ 32bit foo_vis_vumeter to control the skin’s VU meter. However, we’re now experimenting it with the ‘JSP3 64-bit VU Meter’ instead. Let’s see how this lazy ‘JSP3 64-bit VU Meter’ performs.
/*
P/S.
It’s very fascinating that @Marc2003 is reconsidering providing us with JSP3 real-time audio data .
By that, we can imagine the possibilities:
- one day, @pqyt might redirect audio path from foo_uie_webview through foobar2000, allowing us to control audio from platforms like YouTube.
- one day, we can listen to music streaming platforms (Spotify, Tidal, . .) from within foobar2000.
The potential for fun and creativity is boundless.
*/
Wish you all the best.
Cheers,
Ilovefb2k
// We need JScript Panel 3 (64bit) installed and ffprobe.exe [ffmpeg.org] copied into folder {foobar2000 profile folded}\skins\external_helper\ffprobe.exe
@ilovefb2k : thanks for your posts and for this new script!
To be perfectly honest with you though I don't want part of Foobar to look like a Technics tape deck. The folks over at the AIMP forum for skins love this stuff, they have skins to make AIMP look like/"react" like dozens of different cassette decks and reel-to-reel tape players from days gone by. It's interesting but I was happy to get rid of that stuff, haha..
What would be incredibly useful would be if someone could come up with a guide, perhaps based on this script, on how users could use image files in a similar way to create their own meter "look" minus the huge, confusing code investment this one makes in an animated body, etc. Maybe including "sample" templates for a more paint-by-numbers approach for novice script editors like myself--light, and easy to experiment with. Thanks for your interest in Foobar, glad to see your forum access issue has been resolved.
P.S. You added, "We need JScript Panel 3 (64bit) installed and ffprobe.exe [ffmpeg.org] copied into folder {foobar2000 profile folded}\skins\external_helper\ffprobe.exe." Actually folks should know it's easy to change the script line that defines the ffprobe.exe path to anywhere on your PC just using Notepad, like
var binaries = {
ffprobe: 'C:\\ffmpeg\\ffprobe.exe',
I know YOU know that, but many beginners faced with adding another 150mb to their Foobar Portable backup folder might be put off altogether, especially with the availability of pqyt's Peak Meter.
Here's a super-quick conversion of the VU-meter script changed to use the new audio interface in JScript Panel 3.6.6.
// ==PREPROCESSOR==
// @name "JSP3 VU Meter"
// ==/PREPROCESSOR==
var timer_SetInterval = 30; //ms
var VUMeterFb2k = false; // true: foobar2000 VU Meter style; false: free style
var font,font_t = "";
var g_text = "";
var ww = 0, wh = 0;
var colours = {
text : 0,
background : 0,
highlight : 0,
}
var color_1;
var color_2;
var color = [];
var step = 20; // more is less space between bars (cpu powers consumed) and vice versa.
var minDB = -60; //dB as Foobar2000' s built - in VU Meter
var db = [];
var ColourTypeCUI = {
text: 0,
selection_text: 1,
inactive_selection_text: 2,
background: 3,
selection_background: 4,
inactive_selection_background: 5,
active_item_frame: 6
};
var ColourTypeDUI = {
text: 0,
background: 1,
highlight: 2,
selection: 3
};
var FontTypeCUI = {
items : 0,
labels : 1,
};
var FontTypeDUI = {
defaults : 0,
tabs : 1,
lists : 2,
playlists : 3,
statusbar : 4,
console : 5,
};
function update_colours() {
if (window.IsDefaultUI) {
colours.text = window.GetColourDUI(ColourTypeDUI.text);
colours.highlight = window.GetColourDUI(ColourTypeDUI.highlight);
colours.background = window.GetColourDUI(ColourTypeDUI.background);
} else {
colours.text = window.GetColourCUI(ColourTypeCUI.text);
colours.background = window.GetColourCUI(ColourTypeCUI.background);
colours.highlight = blendColours(colours.text, colours.background, 0.4);
}
//custom colours override
// colours.text = RGB(255,255,255);
// colours.highlight = RGB(0,0,250);
// colours.background = RGB(0,0,0);
color_1 = colours.text; // or any color RGB(250,250,250);
color_2 = colours.highlight; // or any color RGB(0,0,0);
color = [];
for (var i = 0; i <= step; i++) {
color.push(blendColours(color_1, color_2, (i / step)));
db.push((minDB / step) * (step - i))
}
}
function update_font() {
if (window.IsDefaultUI) {
font = window.GetFontDUI(FontTypeDUI.defaults);
} else {
font = window.GetFontCUI(FontTypeCUI.items);
}
// adjust size
font_t = font;
var obj = JSON.parse(font_t);
obj.Size -= 4;
font_t = JSON.stringify(obj);
}
update_colours();
update_font();
function on_colours_changed() {
update_colours();
window.Repaint();
}
function on_mouse_lbtn_up(x, y) {
window.ShowConfigure();
}
function on_size() {
ww = window.Width;
wh = window.Height;
}
//------------- just an implementation /////////////
function RGB(r,g,b) { return (0xff000000|(r<<16)|(g<<8)|(b)); }
function RGBA(r, g, b, a) { return ((a << 24) | (r << 16) | (g << 8) | (b)); }
function toRGB(col) {
var a = col - 0xFF000000;
return [a >> 16, a >> 8 & 0xFF, a & 0xFF];
}
function blendColours(c1, c2, factor) { //@Marc2003
var c1 = toRGB(c1);
var c2 = toRGB(c2);
var r = Math.round(c1[0] + factor * (c2[0] - c1[0]));
var g = Math.round(c1[1] + factor * (c2[1] - c1[1]));
var b = Math.round(c1[2] + factor * (c2[2] - c1[2]));
return (0xff000000 | (r << 16) | (g << 8) | (b));
}
function on_paint(gr) {
gr.FillRectangle(0, 0, ww, wh, colours.background);
//
LM = RMS_level1; // ~ VUMeter.LeftLevel;
RM = RMS_level2; // ~ VUMeter.RightLevel;
L = Peak_level1; // ~ VUMeter.LeftPeak;
R = Peak_level2; // ~ VUMeter.RightPeak;
var h = 20; // VUh_bar;
var VUh_bar = 20; //
var VU_x = 20; //VUx;
var VUy = 5;
var VUh_off = h + 5;
var VUw = ww - 20;
var yL = (VUy + h);
var yLM = (VUy + h) + VUh_bar;
var yRM = (VUy + h) + VUh_bar + VUh_off;
var yR = (VUy + h) + VUh_bar + VUh_off + VUh_bar;
var dbLM = PctToDB(LM),
dbRM = PctToDB(RM),
dbL = PctToDB(L),
dbR = PctToDB(R);
if (VUMeterFb2k) {// foobar2000 VUMeter style
if (!(dbLM == 0 || dbLM == -Infinity)) {
// 65 : -60db- 0dB (+ 5dB offset at the end beyond 0dB ) scale
var wLM = Math.round(ww * ((100 + Number(dbLM)) / 65 - 40 / 65));
var wRM = Math.round(ww * ((100 + Number(dbRM)) / 65 - 40 / 65));
var wL = Math.round(ww * ((100 + Number(dbL)) / 65 - 40 / 65));
var wR = Math.round(ww * ((100 + Number(dbR)) / 65 - 40 / 65));
FillGradientRectangle(gr, VU_x, yLM, wLM, h - 1, 1, colours.text, colours.highlight);
FillGradientRectangle(gr, VU_x, yRM, wRM, h - 1, 1, colours.text, colours.highlight);
FillGradientRectangle(gr, VU_x, yL, wL, h - 1, 1, colours.text, colours.highlight);
FillGradientRectangle(gr, VU_x, yR, wR, h - 1, 1, colours.text, colours.highlight);
}
} else { // free style
h = 15;
var offset = Math.floor((VUw - VU_x) / (step + 1)); //step+1 : number of bars and we need 1 more bar at the end
var w = Math.floor((VUw - VU_x) / (step + 4)); // step+4 : width bar. we need some spaces between bars.
for (var i = 0; i <= step; i++) {
if (i > 0) {
dbLM = PctToDB(LM),
dbRM = PctToDB(RM),
dbL = PctToDB(L),
dbR = PctToDB(R);
}
gr.FillRectangle(VU_x + i * offset, yLM, w, h, dbLM >= db[i] ? color[i] : RGBA(0, 0, 0, 0));
gr.FillRectangle(VU_x + i * offset, yRM, w, h, dbRM >= db[i] ? color[i] : RGBA(0, 0, 0, 0));
if ((dbL > db[i] && dbL < db[i + 1])) {
var wL = i * offset + offset / Math.abs(db[i + 1] - db[i]) * Math.abs(dbL - db[i]);
gr.FillRectangle(VU_x, yL, wL, h, color[i]);
}
if ((dbR > db[i] && dbR < db[i + 1])) {
var wR = i * offset + offset / Math.abs(db[i + 1] - db[i]) * Math.abs(dbR - db[i]);
gr.FillRectangle(VU_x, yR, wR, h, color[i]);
}
}
}
// X-,Y-axis
for (var i = (65 - 5) / 5, j = 0; i >= 0; i--, j++)
gr.WriteText("-" + 5 * i + "dB", font_t, colours.text, VU_x / 2 + j * (ww - VU_x) / 13, yR + h + 10, ww, wh);
gr.WriteText("FL", font_t, colours.text, 0, yLM, ww, wh);
gr.WriteText("FL", font_t, colours.text, 0, yL, ww, wh);
gr.WriteText("FR", font_t, colours.text, 0, yRM, ww, wh);
gr.WriteText("FR", font_t, colours.text, 0, yR, ww, wh);
FillGradientRectangle(gr, VU_x, yR + h + 5, ww, 1, 1, colours.text, colours.highlight);
}
function clear_meter() {
RMS_level1 = 0;
RMS_level2 = 0;
Peak_level1 = 0;
Peak_level2 = 0;
prev_time = 0;
window.Repaint();
}
function on_playback_new_track(handler) {
VUMeter();
}
function on_playback_stop(reason) {
if (reason != 2) { // not starting another track
offVUMeterTimer();
clear_meter();
}
}
function on_playback_pause(state) {
state ? offVUMeterTimer() : onVUMeterTimer();
}
var RMS_level1 = RMS_level2 = Peak_level1 = Peak_level2 = 0; // RMS and Peak level of each 2 channels.
var timer_SetInterval_id = null;
var prev_time = 0;
function on_script_unload() {
}
function PctToDB(num) {
// input : num [0-1]
// output: dB [-100,0]
return ((2000 * Math.log(num) / Math.LN10) / 100).toFixed(2);
}
function onVUMeterTimer() {
if (!fb.IsPlaying || fb.IsPaused) return;
if (timer_SetInterval_id === null) {
timer_SetInterval_id = window.SetInterval(function() {
if (fb.PlaybackTime) {
var cur_time = fb.PlaybackTime;
var chunk = fb.GetAudioChunk(cur_time - prev_time);
if (chunk) {
prev_time = cur_time;
var data = chunk.Data.toArray();
if (data) {
var ch_count = chunk.ChannelCount;
var frame_len = chunk.SampleCount;
var ch2_idx = 1;
if (ch_count < 2) ch2_idx = 0;
var sum1 = 0;
var sum2 = 0;
var peak1 = 0;
var peak2 = 0;
for (var i = 0; i < data.length; i += ch_count) {
var l = data[i];
var r = data[i + ch2_idx];
if (l > peak1) peak1 = l;
if (r > peak2) peak2 = r;
sum1 += l * l;
sum2 += r * r;
}
RMS_level1 = Math.sqrt(sum1/frame_len);
RMS_level2 = Math.sqrt(sum2/frame_len);
Peak_level1 = peak1;
Peak_level2 = peak2;
}
}
}
//(window.RepaintRect(x, y, w, h);
window.Repaint();
}, timer_SetInterval);
}
}
function offVUMeterTimer() {
if (timer_SetInterval_id) window.ClearInterval(timer_SetInterval_id);
timer_SetInterval_id = null;
}
onVUMeterTimer();
function VUMeter() {
offVUMeterTimer(); //turn off timer
var handle = fb.IsPlaying ? fb.GetNowPlaying() : false;
if (!handle) return;
// set VUMeter timer tiktok
onVUMeterTimer();
}
function FillGradientRectangle(gr, x, y, w, h, direction, colour1, colour2) { //@Marc2003
var stops = [[0, colour1], [1, colour2]];
var brush = {
Start: [0, 0],
Stops: stops
};
if (direction == 0)
brush.End = [0, h];
else
brush.End = [w, 0];
gr.FillRectangle(x, y, w, h, JSON.stringify(brush));
}
//EOF
Edit: tiny bit cleaned up version.
Sorry for being off-topic:
Quote from: ilovefb2k on 2024-08-02 05:28:14
FFmpeg is a good fundamental media processing, foobar2000 is based on that platform among others.
Small clarification. foobar2000 is in no way based on FFmpeg. At some point a few decoders were switched from other libraries to decoders found in FFmpeg because they were faster and better. And some of these decoders have been reverted back away from FFmpeg because they turned out to be too buggy.
Quote from: ilovefb2k on 2024-08-03 06:23:14
P/S. Can anyone shed me a light on how to stop this site from keeping me banning without reason. It is annoying that i have to go to some cafe to get access.
How do you connect to the site? I believe some anonymizing VPN services are banned/blocked because of abuse. I also fear that when a spammer is banned the IP-address that was used is banned with the account. Personally I don't believe in IP-banning as the problematic spammers are not stuck with a static IP.
I'm not sure VPN bans will be lifted, but if your normal connection's IP is blocked, you can for example PM the IP info to me and I'll try to get an admin to remove the ban.
Hi @Case,
Regarding foobar2000 and FFmpeg, I may have misinterpreted the statement “foobar2000 uses FFmpeg under the GNU LGPL v2.1,” which I quoted from the foobar2000 site [https://www.foobar2000.org/ffmpeg]. Thank you for pointing out the correction.
In terms of accessing the Hydrogenaud.io site [https://hydrogenaud.io/], I initially thought my username or IP might be blacklisted. However, even after refreshing my history cache, I encountered the same problem. It appears that this issue is related to region-specific policies, as I was able to access a German site [https://www.mathcs.uni-leipzig.de/]. Interestingly, configuring a VPN at a café’s internet connection resolved the issue for me.
Lastly, thank you for your very useful components as well as your efforts in persuading @Marc2003 to provide us with real-time audio data chunks.
Best regards,
Ilovefb2k
Then I ask myself why you are not using a browser with VPN at home like Opera, or a browser-plugin providing a VPN service, there are enough free solutions available at least for Firefox (for instance Browsec, Urban VPN, among other free solutions), but I guess you'll find such plugins for every browser that can handle plugins.
Michelist
Here's a super-quick conversion of the VU-meter script changed to use the new audio interface in JScript Panel 3.6.6.
Thanks. All very much over my head as expected. ;D
Here's an even tidier version with lots of rubbish removed. There is some unexpected flickering which I can't figure out but it seems to be present in the original too.
// ==PREPROCESSOR==
// @name "JSP3 VU Meter"
// @import "%fb2k_component_path%helpers.txt"
// ==/PREPROCESSOR==
var timer_interval = 30; //ms
var timer_id = 0;
var font_t = CreateFontString("Segoe UI", 8);
var ww = 0, wh = 0;
var minDB = -60;
var RMS_level1 = RMS_level2 = Peak_level1 = Peak_level2 = 0;
var prev_time = 0;
var stops = [
[ 1.0, RGB(227, 9, 64) ],
[ 0.66, RGB(231, 215, 2) ],
[ 0.33, RGB(15, 168, 149) ],
[ 0.0, RGB(19, 115, 232) ]
];
var brush = {
Stops : stops,
Start : [0, 0], // x and y values
End : [0, 0], // x and y values
};
var brush_str = "";
var colours = {
text : 0,
background : 0,
};
var ColourTypeCUI = {
text: 0,
selection_text: 1,
inactive_selection_text: 2,
background: 3,
selection_background: 4,
inactive_selection_background: 5,
active_item_frame: 6
};
var ColourTypeDUI = {
text: 0,
background: 1,
highlight: 2,
selection: 3
};
update_colours();
if (fb.IsPlaying) start_timer();
function update_colours() {
if (window.IsDefaultUI) {
colours.text = window.GetColourDUI(ColourTypeDUI.text);
colours.highlight = window.GetColourDUI(ColourTypeDUI.highlight);
colours.background = window.GetColourDUI(ColourTypeDUI.background);
} else {
colours.text = window.GetColourCUI(ColourTypeCUI.text);
colours.highlight = window.GetColourCUI(ColourTypeCUI.text);
colours.background = window.GetColourCUI(ColourTypeCUI.background);
}
}
function clear_meter() {
RMS_level1 = 0;
RMS_level2 = 0;
Peak_level1 = 0;
Peak_level2 = 0;
prev_time = 0;
window.Repaint();
}
function to_db(num) {
var ret = (2000 * Math.log(num) / Math.LN10 / 100).toFixed(2);
return clamp(ret, minDB, 0);
}
function clamp(value, min, max) {
if (value < min) return min;
if (value > max) return max;
return value;
}
function start_timer() {
if (!timer_id) {
timer_id = window.SetInterval(function() {
var cur_time = fb.PlaybackTime;
if (cur_time) {
var chunk = fb.GetAudioChunk(cur_time - prev_time);
if (chunk) {
prev_time = cur_time;
var data = chunk.Data.toArray();
if (data) {
var ch_count = chunk.ChannelCount;
var frame_len = chunk.SampleCount;
var ch2_idx = 1;
if (ch_count < 2) ch2_idx = 0;
var sum1 = 0;
var sum2 = 0;
var peak1 = 0;
var peak2 = 0;
for (var i = 0; i < data.length; i += ch_count) {
var l = data[i];
var r = data[i + ch2_idx];
if (l > peak1) peak1 = l;
if (r > peak2) peak2 = r;
sum1 += l * l;
sum2 += r * r;
}
RMS_level1 = Math.sqrt(sum1/frame_len);
RMS_level2 = Math.sqrt(sum2/frame_len);
Peak_level1 = peak1;
Peak_level2 = peak2;
}
}
}
window.Repaint();
}, timer_interval);
}
}
function stop_timer() {
if (timer_id) {
window.ClearInterval(timer_id);
}
timer_id = 0;
}
function on_colours_changed() {
update_colours();
window.Repaint();
}
function on_paint(gr) {
gr.FillRectangle(0, 0, ww, wh, colours.background);
var h = 20;
var VU_x = 20;;
var VUy = 5;
var VUw = ww - 20;
var yL = VUy + h;
var yLM = VUy + (h * 2);
var yRM = VUy + (h * 3);
var yR = VUy + (h * 4);
// labels
for (var i = (65 - 5) / 5, j = 0; i >= 0; i--, j++) {
gr.WriteText("-" + 5 * i + "dB", font_t, colours.text, VU_x / 2 + j * (ww - VU_x) / 13, yR + h + 10, ww, wh);
}
gr.WriteText("FL", font_t, colours.text, 4, yLM, ww, wh);
gr.WriteText("FL", font_t, colours.text, 4, yL, ww, wh);
gr.WriteText("FR", font_t, colours.text, 4, yRM, ww, wh);
gr.WriteText("FR", font_t, colours.text, 4, yR, ww, wh);
gr.FillRectangle(VU_x, yR + h + 5, ww, 1, colours.text);
// bars
var dbLM = to_db(RMS_level1),
dbRM = to_db(RMS_level2),
dbL = to_db(Peak_level1),
dbR = to_db(Peak_level2);
var wLM = Math.round(ww * ((100 + Number(dbLM)) / 65 - 40 / 65));
var wRM = Math.round(ww * ((100 + Number(dbRM)) / 65 - 40 / 65));
var wL = Math.round(ww * ((100 + Number(dbL)) / 65 - 40 / 65));
var wR = Math.round(ww * ((100 + Number(dbR)) / 65 - 40 / 65));
gr.FillRectangle(VU_x, yLM, wLM, h - 1, brush_str);
gr.FillRectangle(VU_x, yRM, wRM, h - 1, brush_str);
gr.FillRectangle(VU_x, yL, wL, h - 1, brush_str);
gr.FillRectangle(VU_x, yR, wR, h - 1, brush_str);
}
function on_playback_new_track(handle) {
start_timer();
}
function on_playback_pause(state) {
state ? stop_timer() : start_timer();
}
function on_playback_stop(reason) {
if (reason != 2) {
stop_timer();
clear_meter();
}
}
function on_size() {
ww = window.Width;
wh = window.Height;
brush.End = [ww, 0];
brush_str = JSON.stringify(brush);
}
@marc2k3
Nice! Thanks.
Here's a super-quick conversion of the VU-meter script changed to use the new audio interface in JScript Panel 3.6.6.
Thanks. All very much over my head as expected. ;D
Here's an even tidier version with lots of rubbish removed. There is some unexpected flickering which I can't figure out but it seems to be present in the original too.
// ==PREPROCESSOR==
// @name "JSP3 VU Meter"
// @import "%fb2k_component_path%helpers.txt"
// ==/PREPROCESSOR==
var timer_interval = 30; //ms
var timer_id = 0;
var font_t = CreateFontString("Segoe UI", 8);
var ww = 0, wh = 0;
var minDB = -60;
var RMS_level1 = RMS_level2 = Peak_level1 = Peak_level2 = 0;
var prev_time = 0;
var stops = [
[ 1.0, RGB(227, 9, 64) ],
[ 0.66, RGB(231, 215, 2) ],
[ 0.33, RGB(15, 168, 149) ],
[ 0.0, RGB(19, 115, 232) ]
];
var brush = {
Stops : stops,
Start : [0, 0], // x and y values
End : [0, 0], // x and y values
};
var brush_str = "";
var colours = {
text : 0,
background : 0,
};
var ColourTypeCUI = {
text: 0,
selection_text: 1,
inactive_selection_text: 2,
background: 3,
selection_background: 4,
inactive_selection_background: 5,
active_item_frame: 6
};
var ColourTypeDUI = {
text: 0,
background: 1,
highlight: 2,
selection: 3
};
update_colours();
if (fb.IsPlaying) start_timer();
function update_colours() {
if (window.IsDefaultUI) {
colours.text = window.GetColourDUI(ColourTypeDUI.text);
colours.highlight = window.GetColourDUI(ColourTypeDUI.highlight);
colours.background = window.GetColourDUI(ColourTypeDUI.background);
} else {
colours.text = window.GetColourCUI(ColourTypeCUI.text);
colours.highlight = window.GetColourCUI(ColourTypeCUI.text);
colours.background = window.GetColourCUI(ColourTypeCUI.background);
}
}
function clear_meter() {
RMS_level1 = 0;
RMS_level2 = 0;
Peak_level1 = 0;
Peak_level2 = 0;
prev_time = 0;
window.Repaint();
}
function to_db(num) {
var ret = (2000 * Math.log(num) / Math.LN10 / 100).toFixed(2);
return clamp(ret, minDB, 0);
}
function clamp(value, min, max) {
if (value < min) return min;
if (value > max) return max;
return value;
}
function start_timer() {
if (!timer_id) {
timer_id = window.SetInterval(function() {
var cur_time = fb.PlaybackTime;
if (cur_time) {
var chunk = fb.GetAudioChunk(cur_time - prev_time);
if (chunk) {
prev_time = cur_time;
var data = chunk.Data.toArray();
if (data) {
var ch_count = chunk.ChannelCount;
var frame_len = chunk.SampleCount;
var ch2_idx = 1;
if (ch_count < 2) ch2_idx = 0;
var sum1 = 0;
var sum2 = 0;
var peak1 = 0;
var peak2 = 0;
for (var i = 0; i < data.length; i += ch_count) {
var l = data[i];
var r = data[i + ch2_idx];
if (l > peak1) peak1 = l;
if (r > peak2) peak2 = r;
sum1 += l * l;
sum2 += r * r;
}
RMS_level1 = Math.sqrt(sum1/frame_len);
RMS_level2 = Math.sqrt(sum2/frame_len);
Peak_level1 = peak1;
Peak_level2 = peak2;
}
}
}
window.Repaint();
}, timer_interval);
}
}
function stop_timer() {
if (timer_id) {
window.ClearInterval(timer_id);
}
timer_id = 0;
}
function on_colours_changed() {
update_colours();
window.Repaint();
}
function on_paint(gr) {
gr.FillRectangle(0, 0, ww, wh, colours.background);
var h = 20;
var VU_x = 20;;
var VUy = 5;
var VUw = ww - 20;
var yL = VUy + h;
var yLM = VUy + (h * 2);
var yRM = VUy + (h * 3);
var yR = VUy + (h * 4);
// labels
for (var i = (65 - 5) / 5, j = 0; i >= 0; i--, j++) {
gr.WriteText("-" + 5 * i + "dB", font_t, colours.text, VU_x / 2 + j * (ww - VU_x) / 13, yR + h + 10, ww, wh);
}
gr.WriteText("FL", font_t, colours.text, 4, yLM, ww, wh);
gr.WriteText("FL", font_t, colours.text, 4, yL, ww, wh);
gr.WriteText("FR", font_t, colours.text, 4, yRM, ww, wh);
gr.WriteText("FR", font_t, colours.text, 4, yR, ww, wh);
gr.FillRectangle(VU_x, yR + h + 5, ww, 1, colours.text);
// bars
var dbLM = to_db(RMS_level1),
dbRM = to_db(RMS_level2),
dbL = to_db(Peak_level1),
dbR = to_db(Peak_level2);
var wLM = Math.round(ww * ((100 + Number(dbLM)) / 65 - 40 / 65));
var wRM = Math.round(ww * ((100 + Number(dbRM)) / 65 - 40 / 65));
var wL = Math.round(ww * ((100 + Number(dbL)) / 65 - 40 / 65));
var wR = Math.round(ww * ((100 + Number(dbR)) / 65 - 40 / 65));
gr.FillRectangle(VU_x, yLM, wLM, h - 1, brush_str);
gr.FillRectangle(VU_x, yRM, wRM, h - 1, brush_str);
gr.FillRectangle(VU_x, yL, wL, h - 1, brush_str);
gr.FillRectangle(VU_x, yR, wR, h - 1, brush_str);
}
function on_playback_new_track(handle) {
start_timer();
}
function on_playback_pause(state) {
state ? stop_timer() : start_timer();
}
function on_playback_stop(reason) {
if (reason != 2) {
stop_timer();
clear_meter();
}
}
function on_size() {
ww = window.Width;
wh = window.Height;
brush.End = [ww, 0];
brush_str = JSON.stringify(brush);
}
Hi
@Case,
Frankly, I had no idea until I saw your post. Again, thank you for persuading Marc2003 to give JSP3 a nice feature.
Hi
@marc2k3,
It seems you have just pushed the JSP3 to the edge of ES5.
Your script is very beautiful and tidy.
Wishing you both happiness.
Ilovefb2k
Cheers.
Sorry for being off-topic:
Quote from: ilovefb2k on 2024-08-02 05:28:14
FFmpeg is a good fundamental media processing, foobar2000 is based on that platform among others.
Small clarification. foobar2000 is in no way based on FFmpeg. At some point a few decoders were switched from other libraries to decoders found in FFmpeg because they were faster and better. And some of these decoders have been reverted back away from FFmpeg because they turned out to be too buggy.
Quote from: ilovefb2k on 2024-08-03 06:23:14
P/S. Can anyone shed me a light on how to stop this site from keeping me banning without reason. It is annoying that i have to go to some cafe to get access.
How do you connect to the site? I believe some anonymizing VPN services are banned/blocked because of abuse. I also fear that when a spammer is banned the IP-address that was used is banned with the account. Personally I don't believe in IP-banning as the problematic spammers are not stuck with a static IP.
I'm not sure VPN bans will be lifted, but if your normal connection's IP is blocked, you can for example PM the IP info to me and I'll try to get an admin to remove the ban.
Hi @Case,
Regarding foobar2000 and FFmpeg, I may have misinterpreted the statement “foobar2000 uses FFmpeg under the GNU LGPL v2.1,” which I quoted from the foobar2000 site [https://www.foobar2000.org/ffmpeg]. Thank you for pointing out the correction.
In terms of accessing the Hydrogenaud.io site [https://hydrogenaud.io/], I initially thought my username or IP might be blacklisted. However, even after refreshing my history cache, I encountered the same problem. It appears that this issue is related to region-specific policies, as I was able to access a German site [https://www.mathcs.uni-leipzig.de/]. Interestingly, configuring a VPN at a café’s internet connection resolved the issue for me.
Lastly, thank you for your very useful components as well as your efforts in persuading @Marc2003 to provide us with real-time audio data chunks.
Best regards,
Ilovefb2k
Then I ask myself why you are not using a browser with VPN at home like Opera, or a browser-plugin providing a VPN service, there are enough free solutions available at least for Firefox (for instance Browsec, Urban VPN, among other free solutions), but I guess you'll find such plugins for every browser that can handle plugins.
Michelist
Hi
@MichelistI did a google search and followed the instruction here https://www.reddit.com/r/foobar2000/comments/9eb8ua/why_i_banned_on_hydrogenaudioio/ (." . .It does work on Brave if I select 'Open Private Window with Tor' though . . ").
That saves my life sometimes.
But , why do we have to play around with VPN ? and my case may not the only one.
Regards,
Ilovefb2k.
But , why do we have to play around with VPN ? and my case may not the only one.
You are not supposed to play around with VPN, and actually VPN services are most likely to be blocked. Especially free ones.
The forums have no geo blocking going on.
But you don't tell any information about the connection you have trouble accessing the site with. How do you expect people to help you if there is zero data?
Here's a super-quick conversion of the VU-meter script changed to use the new audio interface in JScript Panel 3.6.6.
Thanks. All very much over my head as expected. ;D
Here's an even tidier version with lots of rubbish removed. There is some unexpected flickering which I can't figure out but it seems to be present in the original too.
Thanks marc2k3 and Case! Great job marc2k3 on the JSP3 3.6.6 revision that makes this possible, man like overnight! Case thanks for getting it started, yours kept the original segmented bars for median which I liked but as you said the RMS peak bars would flicker and often disappear completely on high-level material. Loved marc2k3's revision with the colors and smooth operation. Cool to be able to use the meter on radio streams now with a nice accuracy level and no more caching.
@eurekagliese
Hi :)
Thank you for the wonderful script as always
Crash when wheeling on panel (JSP3 panel only).
I know I won't be using a mouse on this panel.
Text Display + Album Art + Custom SVG and PNG Buttons (2024-07-18).txt
https://hydrogenaud.io/index.php/topic,110516.msg1048037.html#msg1048037
Sorry, this was it.
@marc2k3
Reply #1531
https://hydrogenaud.io/index.php/topic,110516.msg1048043.html#msg1048043
Line 113, replace
function on_mouse_wheel(s) {
if (seekbar.wheel(s)) {
return;
}
text.wheel(s);
}
with
function on_mouse_wheel(s) {
text.wheel(s);
}
But , why do we have to play around with VPN ? and my case may not the only one.
You are not supposed to play around with VPN, and actually VPN services are most likely to be blocked. Especially free ones.
The forums have no geo blocking going on.
But you don't tell any information about the connection you have trouble accessing the site with. How do you expect people to help you if there is zero data?
Hi @Case
Thank you for your attention,
I made this noise not just for my shake.
If this is a public forum, then : Why make it easy accessing as https://wiki.hydrogenaud.io ? some people just look around for information from this knowledge base. Do they walk away from this site [hydrogenaud.io] right away or keep trying.
I made this noise for others and for this forum.
Regards,
Ilovefb2k
@marc2k3
Perfect.
Thanks.
I noticed is that if the tag contains a number in the streaming information, it is not displayed correctly.
In Custom title I use:
$font(Twemoji Mozilla,10)$country_flag($meta(country,$sub($meta_num(country),1))) [%artist%] - [%title%]
(https://i.imgur.com/i4LXiVI.png) (https://i.imgur.com/9tRrJR5.png)
You're telling it to use the Twemoji Mozilla font for the whole text which is wrong. You need to use $font() which tells it to revert to the default font after the country flag...
$font(Twemoji Mozilla,10)FLAG STUFF$font() %artist% - %title%
You're telling it to use the Twemoji Mozilla font for the whole text which is wrong. You need to use $font() which tells it to revert to the default font after the country flag...
$font(Twemoji Mozilla,10)FLAG STUFF$font() %artist% - %title%
Perfect, thanks.
(https://i.imgur.com/WA6RGmy.png)
Here's another tweak on the VU Meter that ilovefb2k/Case provided and I tidied up. It will be in the next release.
https://raw.githubusercontent.com/jscript-panel/component/main/samples/VU%20Meter.txt
I changed the timer interval to 50ms which seems to have solved my unexpected flickering and I prefer the less frenetic updates. I'm guessing it was monitor refresh rate related but I really have no idea what I'm talking about. Just the first line needs to be edited if people want to experiment with it.
Here's another tweak on the VU Meter that ilovefb2k/Case provided and I tidied up. It will be in the next release.
https://raw.githubusercontent.com/jscript-panel/component/main/samples/VU%20Meter.txt
I changed the timer interval to 50ms which seems to have solved my unexpected flickering and I prefer the less frenetic updates. I'm guessing it was monitor refresh rate related but I really have no idea what I'm talking about. Just the first line needs to be edited if people want to experiment with it.
Thanks marc2k3 for the timer fix, the beautiful color blend, and for your intention to add the VU Meter to your own samples!
I tried making the same timer change to 50ms on Case's original trial version, but it doesn't make the same change as it did on yours, only on very quiet passages. The LR Peak value bars still end up vanishing off the screen when the amplitude increases, while the segmented RMS meters behave normally. If I can make a request, would you consent to doing a version of your own meter that maintains the blue/white color scheme and the segmented RMS bars of his original? It would be great to have that design working as well as yours does now. Thanks for any consideration.
I have worked on some improvements to the VU meter too, below you can find current work-in-progress version. It uses marc2k3's cleaned up version as the base but with some fixes and I think improvements.
This shows meters for all channels, bars scale according to panel size, channels are labeled correctly from channel mask. Range is configurable, RMS window is configurable. Optional "AES +3dB" mode. Peak is now shown as a bar at the end of the VU meter and it falls off at configurable speed.
All user-configurable settings are at the top easily editable.
If this is something usable it can be modified to use a block mode and original RMS meter colors.
// ==PREPROCESSOR==
// @name "JSP3 VU Meter"
// @import "%fb2k_component_path%helpers.txt"
// ==/PREPROCESSOR==
// User adjustable settings:
var timer_interval = 1000 / 60; // in ms (default: 60 fps update rate)
var rms_window = 50 / 1000; // in seconds (default: 50 ms)
var peak_hold = 20; // in frames
var peak_fall_mul = 0.99;
var peak_bar_width = 3; // in pixels
var minDB = -60; // minimum dB on the meter (meter range)
var maxDB = 5; // maximum dB on the meter (meter range)
var rms_3db = false; // use AES +3dB RMS mode
// End of user adjustable settings
// -------------------------------
var font_t = CreateFontString("Segoe UI", 8);
var RMS_levels = [], Peak_levels = [], Peak_falldown = [];
var ch_count = 0;
var ch_config = 0;
var ww = 0, wh = 0;
var timer_id = 0;
var rms_db_offset = 0;
if (rms_3db) rms_db_offset = 20 * Math.log(Math.sqrt(2)) / Math.LN10; // 3.01029995663981 dB
var stops = [
[ 1.0, RGB(227, 9, 64) ],
[ 0.66, RGB(231, 215, 2) ],
[ 0.33, RGB(15, 168, 149) ],
[ 0.0, RGB(19, 115, 232) ]
];
var brush = {
Stops : stops,
Start : [0, 0], // x and y values
End : [0, 0], // x and y values
};
var brush_str = "";
var colours = {
text : 0,
background : 0,
};
var ColourTypeCUI = {
text: 0,
selection_text: 1,
inactive_selection_text: 2,
background: 3,
selection_background: 4,
inactive_selection_background: 5,
active_item_frame: 6
};
var ColourTypeDUI = {
text: 0,
background: 1,
highlight: 2,
selection: 3
};
var ChannelNames = [ "FL", "FR", "FC", "LFE", "BL", "BR", "FCL", "FCR", "BC", "SL", "SR", "TC", "TFL", "TFC", "TFR", "TBL", "TBC", "TBR" ];
function update_colours() {
if (window.IsDefaultUI) {
colours.text = window.GetColourDUI(ColourTypeDUI.text);
colours.highlight = window.GetColourDUI(ColourTypeDUI.highlight);
colours.background = window.GetColourDUI(ColourTypeDUI.background);
} else {
colours.text = window.GetColourCUI(ColourTypeCUI.text);
colours.highlight = window.GetColourCUI(ColourTypeCUI.text);
colours.background = window.GetColourCUI(ColourTypeCUI.background);
}
}
function clear_graph() {
for (var c = 0; c < ch_count; ++c) {
RMS_levels[c] = 0;
Peak_levels[c] = 0;
Peak_falldown[c] = 0;
}
window.Repaint();
}
function update_graph() {
var cur_time = fb.PlaybackTime;
if (cur_time > rms_window) {
var chunk = fb.GetAudioChunk(rms_window);
if (chunk) {
ch_count = chunk.ChannelCount;
ch_config = chunk.ChannelConfig;
var data = chunk.Data.toArray();
var frame_len = chunk.SampleCount;
if (data && ch_count > 0 && frame_len > 0) {
var old_count = Peak_levels.length;
RMS_levels.length = ch_count;
Peak_levels.length = ch_count;
Peak_falldown.length = ch_count;
if (old_count < ch_count) {
for (var c = old_count; c < ch_count; ++c) {
Peak_levels[c] = 0;
Peak_falldown[c] = 0;
}
}
for (var c = 0; c < ch_count; ++c) {
var sum = 0, peak = 0;
for (var i = c; i < data.length; i += ch_count) {
var s = Math.abs(data[i]);
if (s > peak) peak = s;
sum += s * s;
}
RMS_levels[c] = Math.sqrt(sum/frame_len);
if (peak >= Peak_levels[c]) {
Peak_levels[c] = peak;
Peak_falldown[c] = 0;
} else {
if (++Peak_falldown[c] > peak_hold) Peak_levels[c] *= peak_fall_mul;
}
}
window.Repaint();
}
}
}
}
function to_db(num) {
return 20 * Math.log(num) / Math.LN10;
}
function clamp(value, min, max) {
if (value < min) return min;
if (value > max) return max;
return value;
}
function start_timer() {
if (!timer_id) {
timer_id = window.SetInterval(update_graph, timer_interval);
}
}
function stop_timer() {
if (timer_id) {
window.ClearInterval(timer_id);
}
timer_id = 0;
}
function on_colours_changed() {
update_colours();
window.Repaint();
}
var dBrange = maxDB - minDB;
function channel_name(ch) {
if (ch < ChannelNames.length) {
if (ch_config) {
for (var i = 0, idx = 0; i < ChannelNames.length; ++i) {
if (ch_config & (1 << i)) {
if (idx == ch) return ChannelNames[i];
idx++;
}
}
} else {
return ChannelNames[ch];
}
}
var name = "Ch" + (ch+1).toString();
return name;
}
function on_paint(gr) {
gr.Clear(colours.background);
if (wh < 1 || ww < 1) return;
var hide_ch_labels = false;
var hide_db_labels = false;
var bar_pad_left = 3*8;
var bar_pad_right = 3*8;
var bar_pad_top = 5;
var bar_pad_bottom = 30;
var bar_height = 0;
var bar_width = 0;
bar_height = Math.floor((wh - bar_pad_top - bar_pad_bottom) / ch_count);
if (bar_height < 8) { // bars are too thin for channel labels, hide them
hide_ch_labels = true;
}
if (bar_height < 4) { // bars are too thin for dB scale too
hide_ch_labels = true;
hide_db_labels = true;
bar_pad_top = 0;
bar_pad_bottom = 0;
bar_pad_left = 0;
bar_pad_right = 0;
bar_height = Math.floor(wh / ch_count);
}
if (bar_height < 2 || bar_height * ch_count > wh) { // bars won't fit in the window, downmix to mono
var rms_sum = 0;
var peak_sum = 0;
for (var c = 0; c < ch_count; ++c) {
rms_sum += RMS_levels[c] * RMS_levels[c];
peak_sum += Peak_levels[c];
}
RMS_levels[0] = Math.sqrt(rms_sum/ch_count);
Peak_levels[0] = peak_sum/ch_count;
ch_count = 1;
hide_ch_labels = true;
hide_db_labels = true;
bar_pad_top = 0;
bar_pad_bottom = 0;
bar_pad_left = 0;
bar_pad_right = 0;
bar_height = Math.floor(wh / ch_count);
}
bar_width = ww - bar_pad_left - bar_pad_right;
// labels
if (!hide_db_labels) {
var db_spacing = 5;
if (dBrange < db_spacing) db_spacing = 1;
if (ww * db_spacing / dBrange < 10*8) {
db_spacing = ((10*8 * dBrange) / ww);
db_spacing -= (db_spacing % 5);
}
gr.FillRectangle(bar_pad_left, bar_pad_top + (bar_height * ch_count) + 5, bar_width, 1, colours.text);
for (var i = minDB, j = 0; i <= maxDB; i += db_spacing, j++) {
gr.WriteText(i + "dB", font_t, colours.text, bar_pad_left / 2 + bar_width * j / (dBrange/db_spacing), wh - 20, ww, wh);
}
}
if (!hide_ch_labels) {
for (var c = 0; c < ch_count; ++c) {
gr.WriteText(channel_name(c), font_t, colours.text, 4, bar_pad_top + (bar_height * c) + bar_height / 2 - 8, ww, wh);
}
}
// bars
for (var c = 0; c < ch_count; ++c) {
if (RMS_levels[c]) {
var rms_db = clamp(to_db(RMS_levels[c]) + rms_db_offset, minDB, maxDB);
var width = Math.round(bar_width * (rms_db - minDB) / dBrange);
gr.FillRectangle(bar_pad_left, bar_pad_top + (bar_height * c), width, bar_height - 1, brush_str);
}
if (peak_bar_width > 0 && Peak_levels[c] > 0) {
var peak_db = clamp(to_db(Peak_levels[c]), minDB, maxDB);
if (peak_db > minDB) {
var peak_pos = Math.round(bar_width * (peak_db - minDB) / dBrange);
gr.FillRectangle(bar_pad_left + peak_pos - peak_bar_width / 2, bar_pad_top + (bar_height * c), peak_bar_width, bar_height - 1, brush_str);
}
}
}
}
function on_playback_new_track(handle) {
start_timer();
}
function on_playback_pause(state) {
state ? stop_timer() : start_timer();
}
function on_playback_stop(reason) {
if (reason != 2) {
stop_timer();
}
clear_graph();
}
function on_size() {
ww = window.Width;
wh = window.Height;
brush.End = [ww, 0];
brush_str = JSON.stringify(brush);
}
function get_initial_track_info() {
if (ch_count > 0) return;
var handle = fb.GetNowPlaying();
if (!handle) handle = fb.GetFocusItem();
if (!handle) return;
var info = handle.GetFileInfo();
if (info) {
var idx_ch_count = info.InfoFind("channels");
var idx_ch_config = info.InfoFind("WAVEFORMATEXTENSIBLE_CHANNEL_MASK");
if (idx_ch_count >= 0) {
ch_count = Number(info.InfoValue(idx_ch_count));
}
if (idx_ch_config >= 0) {
ch_config = Number(info.InfoValue(idx_ch_config));
}
info.Dispose();
}
handle.Dispose();
}
update_colours();
if (fb.IsPlaying) start_timer();
get_initial_track_info();
Wow, thanks Case for deciding to get back in with your own VU meter scripts! I'm running this one right now and it's working beautifully. Thanks for the user-adjustable settings; the only change I made was to raise the max db to 10.
It was a good idea making the RMS level bars and the max levels share the same horizontal space. The peaks are easier to spot with this design and adjustable fallback, while the RMS levels are very accurate and responsive without being too "hyper."
You sort of "asked for it" when you mentioned "If this is something usable it can be modified to use a block mode and original RMS meter colors," because OF COURSE it usable, and of course I'd love to see a second version with the original meter colors and block mode!!
Thanks for your work on this, and to marc2k3's new JSP3 3.6.6 version that made all this possible.
Here's a quick and dirty mod with right click menu for toggling bar colours between UI and Rainbow. CUI is single colour only because there is no "highlight" like DUI.
// ==PREPROCESSOR==
// @name "JSP3 VU Meter"
// @import "%fb2k_component_path%helpers.txt"
// ==/PREPROCESSOR==
// User adjustable settings:
var timer_interval = 1000 / 60; // in ms (default: 60 fps update rate)
var rms_window = 50 / 1000; // in seconds (default: 50 ms)
var peak_hold = 20; // in frames
var peak_fall_mul = 0.99;
var peak_bar_width = 3; // in pixels
var minDB = -60; // minimum dB on the meter (meter range)
var maxDB = 5; // maximum dB on the meter (meter range)
var rms_3db = false; // use AES +3dB RMS mode
// End of user adjustable settings
// -------------------------------
var font_t = CreateFontString("Segoe UI", 8);
var colour_mode = window.GetProperty("2K3.METER.COLOUR.MODE", 1); // 0 UI, 1 Rainbow
var solid_colour = false;
var RMS_levels = [], Peak_levels = [], Peak_falldown = [];
var ch_count = 0;
var ch_config = 0;
var ww = 0, wh = 0;
var timer_id = 0;
var rms_db_offset = 0;
if (rms_3db) rms_db_offset = 20 * Math.log(Math.sqrt(2)) / Math.LN10; // 3.01029995663981 dB
var rainbow_stops = [
[ 1.0, RGB(227, 9, 64) ],
[ 0.66, RGB(231, 215, 2) ],
[ 0.33, RGB(15, 168, 149) ],
[ 0.0, RGB(19, 115, 232) ]
];
var brush = {
Stops : [],
Start : [0, 0], // x and y values
End : [0, 0], // x and y values
};
var brush_str = "";
var colours = {
text : 0,
highlight : 0,
background : 0,
};
var ChannelNames = [ "FL", "FR", "FC", "LFE", "BL", "BR", "FCL", "FCR", "BC", "SL", "SR", "TC", "TFL", "TFC", "TFR", "TBL", "TBC", "TBR" ];
function update_colours() {
if (window.IsDefaultUI) {
colours.text = window.GetColourDUI(ColourTypeDUI.text);
colours.highlight = window.GetColourDUI(ColourTypeDUI.highlight);
colours.background = window.GetColourDUI(ColourTypeDUI.background);
} else {
colours.text = window.GetColourCUI(ColourTypeCUI.text);
colours.highlight = window.GetColourCUI(ColourTypeCUI.text);
colours.background = window.GetColourCUI(ColourTypeCUI.background);
}
if (colour_mode == 0) {
solid_colour = colours.text == colours.highlight;
if (!solid_colour) {
brush.Stops = [
[0.0, colours.text],
[1.0, colours.highlight],
]
brush_str = JSON.stringify(brush);
}
} else {
solid_colour = false;
brush.Stops = rainbow_stops;
brush_str = JSON.stringify(brush);
}
}
function clear_graph() {
for (var c = 0; c < ch_count; ++c) {
RMS_levels[c] = 0;
Peak_levels[c] = 0;
Peak_falldown[c] = 0;
}
window.Repaint();
}
function update_graph() {
var cur_time = fb.PlaybackTime;
if (cur_time > rms_window) {
var chunk = fb.GetAudioChunk(rms_window);
if (chunk) {
ch_count = chunk.ChannelCount;
ch_config = chunk.ChannelConfig;
var data = chunk.Data.toArray();
var frame_len = chunk.SampleCount;
if (data && ch_count > 0 && frame_len > 0) {
var old_count = Peak_levels.length;
RMS_levels.length = ch_count;
Peak_levels.length = ch_count;
Peak_falldown.length = ch_count;
if (old_count < ch_count) {
for (var c = old_count; c < ch_count; ++c) {
Peak_levels[c] = 0;
Peak_falldown[c] = 0;
}
}
for (var c = 0; c < ch_count; ++c) {
var sum = 0, peak = 0;
for (var i = c; i < data.length; i += ch_count) {
var s = Math.abs(data[i]);
if (s > peak) peak = s;
sum += s * s;
}
RMS_levels[c] = Math.sqrt(sum/frame_len);
if (peak >= Peak_levels[c]) {
Peak_levels[c] = peak;
Peak_falldown[c] = 0;
} else {
if (++Peak_falldown[c] > peak_hold) Peak_levels[c] *= peak_fall_mul;
}
}
window.Repaint();
}
}
}
}
function to_db(num) {
return 20 * Math.log(num) / Math.LN10;
}
function clamp(value, min, max) {
if (value < min) return min;
if (value > max) return max;
return value;
}
function start_timer() {
if (!timer_id) {
timer_id = window.SetInterval(update_graph, timer_interval);
}
}
function stop_timer() {
if (timer_id) {
window.ClearInterval(timer_id);
}
timer_id = 0;
}
function on_colours_changed() {
update_colours();
window.Repaint();
}
var dBrange = maxDB - minDB;
function channel_name(ch) {
if (ch < ChannelNames.length) {
if (ch_config) {
for (var i = 0, idx = 0; i < ChannelNames.length; ++i) {
if (ch_config & (1 << i)) {
if (idx == ch) return ChannelNames[i];
idx++;
}
}
} else {
return ChannelNames[ch];
}
}
var name = "Ch" + (ch+1).toString();
return name;
}
function on_mouse_rbtn_up(x, y) {
var menu = window.CreatePopupMenu();
var colour_menu = window.CreatePopupMenu();
colour_menu.AppendMenuItem(MF_STRING, 1, 'UI');
colour_menu.AppendMenuItem(MF_STRING, 2, 'Rainbow');
colour_menu.CheckMenuRadioItem(1, 2, colour_mode +1);
colour_menu.AppendTo(menu, MF_STRING, 'Bar Colours');
menu.AppendMenuSeparator();
menu.AppendMenuItem(MF_STRING, 10, 'Configure...');
var idx = menu.TrackPopupMenu(x, y);
menu.Dispose();
switch (idx) {
case 0:
break;
case 1:
case 2:
colour_mode = idx -1;
window.SetProperty("2K3.METER.COLOUR.MODE", colour_mode);
update_colours();
window.Repaint();
break;
case 10:
window.ShowConfigure();
break;
}
return true;
}
function on_paint(gr) {
gr.Clear(colours.background);
if (wh < 1 || ww < 1) return;
var hide_ch_labels = false;
var hide_db_labels = false;
var bar_pad_left = 3*8;
var bar_pad_right = 3*8;
var bar_pad_top = 5;
var bar_pad_bottom = 30;
var bar_height = 0;
var bar_width = 0;
bar_height = Math.floor((wh - bar_pad_top - bar_pad_bottom) / ch_count);
if (bar_height < 8) { // bars are too thin for channel labels, hide them
hide_ch_labels = true;
}
if (bar_height < 4) { // bars are too thin for dB scale too
hide_ch_labels = true;
hide_db_labels = true;
bar_pad_top = 0;
bar_pad_bottom = 0;
bar_pad_left = 0;
bar_pad_right = 0;
bar_height = Math.floor(wh / ch_count);
}
if (bar_height < 2 || bar_height * ch_count > wh) { // bars won't fit in the window, downmix to mono
var rms_sum = 0;
var peak_sum = 0;
for (var c = 0; c < ch_count; ++c) {
rms_sum += RMS_levels[c] * RMS_levels[c];
peak_sum += Peak_levels[c];
}
RMS_levels[0] = Math.sqrt(rms_sum/ch_count);
Peak_levels[0] = peak_sum/ch_count;
ch_count = 1;
hide_ch_labels = true;
hide_db_labels = true;
bar_pad_top = 0;
bar_pad_bottom = 0;
bar_pad_left = 0;
bar_pad_right = 0;
bar_height = Math.floor(wh / ch_count);
}
bar_width = ww - bar_pad_left - bar_pad_right;
// labels
if (!hide_db_labels) {
var db_spacing = 5;
if (dBrange < db_spacing) db_spacing = 1;
if (ww * db_spacing / dBrange < 10*8) {
db_spacing = ((10*8 * dBrange) / ww);
db_spacing -= (db_spacing % 5);
}
gr.FillRectangle(bar_pad_left, bar_pad_top + (bar_height * ch_count) + 5, bar_width, 1, colours.text);
for (var i = minDB, j = 0; i <= maxDB; i += db_spacing, j++) {
gr.WriteText(i + "dB", font_t, colours.text, bar_pad_left / 2 + bar_width * j / (dBrange/db_spacing), wh - 20, ww, wh);
}
}
if (!hide_ch_labels) {
for (var c = 0; c < ch_count; ++c) {
gr.WriteText(channel_name(c), font_t, colours.text, 4, bar_pad_top + (bar_height * c) + bar_height / 2 - 8, ww, wh);
}
}
// bars
var bar_colour = solid_colour ? colours.text : brush_str;
for (var c = 0; c < ch_count; ++c) {
if (RMS_levels[c]) {
var rms_db = clamp(to_db(RMS_levels[c]) + rms_db_offset, minDB, maxDB);
var width = Math.round(bar_width * (rms_db - minDB) / dBrange);
gr.FillRectangle(bar_pad_left, bar_pad_top + (bar_height * c), width, bar_height - 1, bar_colour);
}
if (peak_bar_width > 0 && Peak_levels[c] > 0) {
var peak_db = clamp(to_db(Peak_levels[c]), minDB, maxDB);
if (peak_db > minDB) {
var peak_pos = Math.round(bar_width * (peak_db - minDB) / dBrange);
gr.FillRectangle(bar_pad_left + peak_pos - peak_bar_width / 2, bar_pad_top + (bar_height * c), peak_bar_width, bar_height - 1, bar_colour);
}
}
}
}
function on_playback_new_track(handle) {
start_timer();
}
function on_playback_pause(state) {
state ? stop_timer() : start_timer();
}
function on_playback_stop(reason) {
if (reason != 2) {
stop_timer();
}
clear_graph();
}
function on_size() {
ww = window.Width;
wh = window.Height;
brush.End = [ww, 0];
brush_str = JSON.stringify(brush);
}
function get_initial_track_info() {
if (ch_count > 0) return;
var handle = fb.GetNowPlaying();
if (!handle) handle = fb.GetFocusItem();
if (!handle) return;
var info = handle.GetFileInfo();
if (info) {
var idx_ch_count = info.InfoFind("channels");
var idx_ch_config = info.InfoFind("WAVEFORMATEXTENSIBLE_CHANNEL_MASK");
if (idx_ch_count >= 0) {
ch_count = Number(info.InfoValue(idx_ch_count));
}
if (idx_ch_config >= 0) {
ch_config = Number(info.InfoValue(idx_ch_config));
}
info.Dispose();
}
handle.Dispose();
}
update_colours();
if (fb.IsPlaying) start_timer();
get_initial_track_info();
edit: obviously this superior version will be included in the next component release. Thanks Case.
Here's first attempt of added block mode. I used marc2k3's menu code and added the option there.
The first "simple" block mode tries to mimic the original code, it has a static number of blocks. I'm not a fan of that mode as the indicators don't align nicely with the dB scale. There's also a second block mode that aligns the blocks steadily on the dB axel.
The smooth peak indicator feels a bit weird in this mode.
Here's the code:
// ==PREPROCESSOR==
// @name "JSP3 VU Meter"
// @import "%fb2k_component_path%helpers.txt"
// ==/PREPROCESSOR==
// User adjustable settings:
var timer_interval = 1000 / 60; // in ms (default: 60 fps update rate)
var rms_window = 50 / 1000; // in seconds (default: 50 ms)
var peak_hold = 20; // in frames
var peak_fall_mul = 0.99;
var peak_bar_width = 3; // in pixels
var minDB = -60; // minimum dB on the meter (meter range)
var maxDB = 5; // maximum dB on the meter (meter range)
var rms_block_count = 20; // number of blocks in meter style 1
var rms_block_db = 2.5; // dBs per block in meter style 2
var rms_3db = false; // use AES +3dB RMS mode
// End of user adjustable settings
// -------------------------------
var font_t = CreateFontString("Segoe UI", 8);
var colour_mode = window.GetProperty("2K3.METER.COLOUR.MODE", 1); // 0 UI, 1 Rainbow
var meter_style = window.GetProperty("2K3.METER.STYLE", 0); // 0: smooth, 1: blocks-by-count, 2: blocks-by-dB
var solid_colour = false;
var RMS_levels = [], Peak_levels = [], Peak_falldown = [];
var ch_count = 0;
var ch_config = 0;
var ww = 0, wh = 0;
var timer_id = 0;
var rms_db_offset = 0;
if (rms_3db) rms_db_offset = 20 * Math.log(Math.sqrt(2)) / Math.LN10; // 3.01029995663981 dB
var dBrange = maxDB - minDB;
var rainbow_stops = [
[ 1.0, RGB(227, 9, 64) ],
[ 0.66, RGB(231, 215, 2) ],
[ 0.33, RGB(15, 168, 149) ],
[ 0.0, RGB(19, 115, 232) ]
];
var brush = {
Stops : [],
Start : [0, 0], // x and y values
End : [0, 0], // x and y values
};
var brush_str = "";
var colours = {
text : 0,
highlight : 0,
background : 0,
};
var ChannelNames = [ "FL", "FR", "FC", "LFE", "BL", "BR", "FCL", "FCR", "BC", "SL", "SR", "TC", "TFL", "TFC", "TFR", "TBL", "TBC", "TBR" ];
function get_colour_for_db(db) {
if (colour_mode != 0) {
var f = db / dBrange;
for (var i = 0; i < rainbow_stops.length-1; ++i) {
var a = rainbow_stops[i][0];
var b = rainbow_stops[i+1][0];
var ca = rainbow_stops[i][1];
var cb = rainbow_stops[i+1][1];
if (b > a) {
var t = a; a = b; b = t;
var tc = ca; ca = cb; cb = tc;
}
if (a >= f && f >= b) {
return blendColours(cb, ca, (f - b) / (a - b));
}
}
}
if (!solid_colour) {
return blendColours(colours.text, colours.highlight, db / dBrange);
} else {
return colours.text;
}
}
function update_colours() {
if (window.IsDefaultUI) {
colours.text = window.GetColourDUI(ColourTypeDUI.text);
colours.highlight = window.GetColourDUI(ColourTypeDUI.highlight);
colours.background = window.GetColourDUI(ColourTypeDUI.background);
} else {
colours.text = window.GetColourCUI(ColourTypeCUI.text);
colours.highlight = window.GetColourCUI(ColourTypeCUI.text);
colours.background = window.GetColourCUI(ColourTypeCUI.background);
}
if (colour_mode == 0) {
solid_colour = colours.text == colours.highlight;
if (!solid_colour) {
brush.Stops = [
[0.0, colours.text],
[1.0, colours.highlight],
]
brush_str = JSON.stringify(brush);
}
} else {
solid_colour = false;
brush.Stops = rainbow_stops;
brush_str = JSON.stringify(brush);
}
}
function clear_graph() {
for (var c = 0; c < ch_count; ++c) {
RMS_levels[c] = 0;
Peak_levels[c] = 0;
Peak_falldown[c] = 0;
}
window.Repaint();
}
function update_graph() {
var cur_time = fb.PlaybackTime;
if (cur_time > rms_window) {
var chunk = fb.GetAudioChunk(rms_window);
if (chunk) {
ch_count = chunk.ChannelCount;
ch_config = chunk.ChannelConfig;
var data = chunk.Data.toArray();
var frame_len = chunk.SampleCount;
if (data && ch_count > 0 && frame_len > 0) {
var old_count = Peak_levels.length;
RMS_levels.length = ch_count;
Peak_levels.length = ch_count;
Peak_falldown.length = ch_count;
if (old_count < ch_count) {
for (var c = old_count; c < ch_count; ++c) {
Peak_levels[c] = 0;
Peak_falldown[c] = 0;
}
}
for (var c = 0; c < ch_count; ++c) {
var sum = 0, peak = 0;
for (var i = c; i < data.length; i += ch_count) {
var s = Math.abs(data[i]);
if (s > peak) peak = s;
sum += s * s;
}
RMS_levels[c] = Math.sqrt(sum/frame_len);
if (peak >= Peak_levels[c]) {
Peak_levels[c] = peak;
Peak_falldown[c] = 0;
} else {
if (++Peak_falldown[c] > peak_hold) Peak_levels[c] *= peak_fall_mul;
}
}
window.Repaint();
}
}
}
}
function to_db(num) {
return 20 * Math.log(num) / Math.LN10;
}
function clamp(value, min, max) {
if (value < min) return min;
if (value > max) return max;
return value;
}
function start_timer() {
if (!timer_id) {
timer_id = window.SetInterval(update_graph, timer_interval);
}
}
function stop_timer() {
if (timer_id) {
window.ClearInterval(timer_id);
}
timer_id = 0;
}
function on_colours_changed() {
update_colours();
window.Repaint();
}
function channel_name(ch) {
if (ch < ChannelNames.length) {
if (ch_config) {
for (var i = 0, idx = 0; i < ChannelNames.length; ++i) {
if (ch_config & (1 << i)) {
if (idx == ch) return ChannelNames[i];
idx++;
}
}
} else {
return ChannelNames[ch];
}
}
var name = "Ch" + (ch+1).toString();
return name;
}
function on_mouse_rbtn_up(x, y) {
var menu = window.CreatePopupMenu();
var colour_menu = window.CreatePopupMenu();
var style_menu = window.CreatePopupMenu();
if (!menu || !colour_menu || !style_menu) {
if (menu) menu.Dispose();
if (colour_menu) colour_menu.Dispose();
if (style_menu) style_menu.Dispose();
return false;
}
colour_menu.AppendMenuItem(MF_STRING, 1, 'UI');
colour_menu.AppendMenuItem(MF_STRING, 2, 'Rainbow');
colour_menu.CheckMenuRadioItem(1, 2, colour_mode + 1);
colour_menu.AppendTo(menu, MF_STRING, 'Bar Colours');
style_menu.AppendMenuItem(MF_STRING, 3, 'Smooth');
style_menu.AppendMenuItem(MF_STRING, 4, 'Blocks (simple)');
style_menu.AppendMenuItem(MF_STRING, 5, 'Blocks (per dB range)');
style_menu.CheckMenuRadioItem(3, 5, meter_style + 3);
style_menu.AppendTo(menu, MF_STRING, 'Meter style');
menu.AppendMenuSeparator();
menu.AppendMenuItem(MF_STRING, 10, 'Configure...');
var idx = menu.TrackPopupMenu(x, y);
menu.Dispose();
colour_menu.Dispose();
style_menu.Dispose();
switch (idx) {
case 0:
break;
case 1:
case 2:
colour_mode = idx -1;
window.SetProperty("2K3.METER.COLOUR.MODE", colour_mode);
update_colours();
window.Repaint();
break;
case 3:
case 4:
case 5:
meter_style = idx -3;
window.SetProperty("2K3.METER.STYLE", meter_style);
window.Repaint();
break;
case 10:
window.ShowConfigure();
break;
}
return true;
}
function on_paint(gr) {
gr.Clear(colours.background);
if (wh < 1 || ww < 1) return;
var hide_ch_labels = false;
var hide_db_labels = false;
var bar_pad_left = 3*8;
var bar_pad_right = 3*8;
var bar_pad_top = 5;
var bar_pad_bottom = 30;
var bar_height = 0;
var bar_width = 0;
bar_height = Math.floor((wh - bar_pad_top - bar_pad_bottom) / ch_count);
if (bar_height < 8) { // bars are too thin for channel labels, hide them
hide_ch_labels = true;
}
if (bar_height < 4) { // bars are too thin for dB scale too
hide_ch_labels = true;
hide_db_labels = true;
bar_pad_top = 0;
bar_pad_bottom = 0;
bar_pad_left = 0;
bar_pad_right = 0;
bar_height = Math.floor(wh / ch_count);
}
if (bar_height < 2 || bar_height * ch_count > wh) { // bars won't fit in the window, downmix to mono
var rms_sum = 0;
var peak_sum = 0;
for (var c = 0; c < ch_count; ++c) {
rms_sum += RMS_levels[c] * RMS_levels[c];
peak_sum += Peak_levels[c];
}
RMS_levels[0] = Math.sqrt(rms_sum/ch_count);
Peak_levels[0] = peak_sum/ch_count;
ch_count = 1;
hide_ch_labels = true;
hide_db_labels = true;
bar_pad_top = 0;
bar_pad_bottom = 0;
bar_pad_left = 0;
bar_pad_right = 0;
bar_height = Math.floor(wh / ch_count);
}
bar_width = ww - bar_pad_left - bar_pad_right;
// labels
if (!hide_db_labels) {
var db_spacing = 5;
if (dBrange < db_spacing) db_spacing = 1;
if (ww * db_spacing / dBrange < 10*8) {
db_spacing = ((10*8 * dBrange) / ww);
db_spacing -= (db_spacing % 5);
}
var y = bar_pad_top + (bar_height * ch_count) + 5;
gr.FillRectangle(bar_pad_left, y, bar_width, 1, colours.text);
for (var i = minDB, j = 0; i <= maxDB; i += db_spacing, j++) {
var x = bar_pad_left + (bar_width * j / (dBrange / db_spacing));
gr.WriteText(i + "dB", font_t, colours.text, x - (bar_pad_left / 2), wh - 20, ww, wh);
gr.DrawLine(x, y-2, x, y+2, 1, colours.text);
}
}
if (!hide_ch_labels) {
for (var c = 0; c < ch_count; ++c) {
gr.WriteText(channel_name(c), font_t, colours.text, 4, bar_pad_top + (bar_height * c) + bar_height / 2 - 8, ww, wh);
}
}
// bars
var bar_colour = solid_colour ? colours.text : brush_str;
var block_count = rms_block_count;
if (meter_style == 2 && rms_block_db > 0) block_count = Math.floor(dBrange / rms_block_db);
if (block_count < 1) block_count = 1;
var block_width = bar_width / block_count;
var block_pad = Math.ceil(block_width * 0.03);
if (block_pad < 1) block_pad = 1;
for (var c = 0; c < ch_count; ++c) {
if (RMS_levels[c]) {
var rms_db = clamp(to_db(RMS_levels[c]) + rms_db_offset, minDB, maxDB);
if (meter_style == 0) { // smooth mode
var width = Math.round(bar_width * (rms_db - minDB) / dBrange);
gr.FillRectangle(bar_pad_left, bar_pad_top + (bar_height * c), width, bar_height - 1, bar_colour);
} else { // block mode
var blocks = Math.round(block_count * (rms_db - minDB) / dBrange);
for (var i = 0; i < blocks; ++i) {
gr.FillRectangle(bar_pad_left + (i * block_width) + block_pad, bar_pad_top + (bar_height * c), block_width - block_pad*2, bar_height - 1, get_colour_for_db(i * dBrange / block_count));
}
}
}
if (peak_bar_width > 0 && Peak_levels[c] > 0) {
var peak_db = clamp(to_db(Peak_levels[c]), minDB, maxDB);
if (peak_db > minDB) {
var peak_pos = Math.round(bar_width * (peak_db - minDB) / dBrange);
gr.FillRectangle(bar_pad_left + peak_pos - peak_bar_width / 2, bar_pad_top + (bar_height * c), peak_bar_width, bar_height - 1, bar_colour);
}
}
}
}
function on_playback_new_track(handle) {
start_timer();
}
function on_playback_pause(state) {
state ? stop_timer() : start_timer();
}
function on_playback_stop(reason) {
if (reason != 2) {
stop_timer();
}
clear_graph();
}
function on_size() {
ww = window.Width;
wh = window.Height;
brush.End = [ww, 0];
brush_str = JSON.stringify(brush);
}
function get_initial_track_info() {
if (ch_count > 0) return;
var handle = fb.GetNowPlaying();
if (!handle) handle = fb.GetFocusItem();
if (!handle) return;
var info = handle.GetFileInfo();
if (info) {
var idx_ch_count = info.InfoFind("channels");
var idx_ch_config = info.InfoFind("WAVEFORMATEXTENSIBLE_CHANNEL_MASK");
if (idx_ch_count >= 0) {
ch_count = Number(info.InfoValue(idx_ch_count));
}
if (idx_ch_config >= 0) {
ch_config = Number(info.InfoValue(idx_ch_config));
}
info.Dispose();
}
handle.Dispose();
}
update_colours();
if (fb.IsPlaying) start_timer();
get_initial_track_info();
Edit: added a fallback to get_colour_for_db in case rainbow range blend fails for some reason. Changed default block mode 2 to use 2.5 dB blocks.
Edit 2: restored block mode to allow fractional pixel sizes. Added small notches to dB axle. Centered the blocks.
Thx Case, but I can't find how to change the background color
Background colors comes from the User Interface settings. If you want to use custom colors you can edit them all in update_colours() function.
I edited the previous script as I noticed the "dB" block mode didn't align correctly with the dB markers if window size wasn't ideal.
I edited the previous script as I noticed the "dB" block mode didn't align correctly with the dB markers if window size wasn't ideal.
Looks very promising! I'll have a go at it in a month or two to replace the (bugged) peakmeters I now use with this script.
Could you for now please add an option in the txt script to change the orientation of the VU meter to vertical?
@Case and marc2k3: both of your latest VU meter scripts posted here work great! For those needing a heads-up:
Both developers have switched to a 2-bar LR-RMS approach and the Peak bars have been dropped. Peak values are displayed by a single moving vertical line at the right end of the same horizontal "space;" this prevents the need to display a frantically oscillating Peak meter bar as in the first ilovefb2k version.
The two RMS bars adopt the height of the display panel and narrow or widen in accordance to its set. This can result in some pretty "thick" bars if you're using the same panel to display tabbed spectrum analyzers you normally view at a greater height. I would ask both developers that an
option could be added to assign a fixed, centered height value to the bar display portion, with only the panel background responding to manually dragging its border to different heights.
Marc2k3 and Case both give a right-click option to use rainbow or UI (blue/white) bar colors, and other user adjustments for peak hold, timer interval, dB scale, etc at the top of the script. Case adds a "Meter style" option to the right-click entry that allow choosing between smooth bars or two kinds of "blocks" display, simple or segmented per dB. In the script header, an option is provided to divide the simple blocks into a user-specifies amount, giving an "LED" appearance.
As far as performance, both are equally smooth, responsive, and accurate. If options are set identically, there is no visible difference between tabbing back and forth between the two. These comments are based on the last two tweaked scripts from each poster in this forum. Marc2k3 mentioned he had added Case's script as a new sample in his latest JSP3 3.6.7 release but I haven't had time to add it yet and see if the Case script is identical. BTW, all these new scripts require that
JSP3 version 3.6.6 or higher be installed and are for 64-bit only.
64-bit only.
That is 100% factually incorrect. What prompted you to make such an outlandish comment? :/
edit: just to be absolutely clear, the changelog or documentation did not hint at that. It would be insane of me not to mention that if any feature/script was exclusive to a certain architecture. If there was any difference, it would be a horrible bug that needs reporting and fixing.
And when I say "reporting", I mean something more meaningful than "doesn't work LOL". The quality of bug reporting in general across all fb2k core issues and other components is atrocious.
64-bit only.
That is 100% factually incorrect. What prompted you to make such an outlandish comment? :/
The fact that JSP3 3.6.6 is only available for Foobar versions 2.1 and higher, and Foobar versions older than 2.0 were all 32-bit, my poor little mind got confused for a moment--no outlandishness intended. Man relax, I'm sorry I made a mistake.
@marc2k3
VUMeter ilovefb2k + Case + marc2003 (2024-08-14)
Is it possible to change the height of the VUMeter bar according to the height of the Panel? Ideally, I would like it to fit the Panel without the blank space at the top. Thank you.
(https://i.imgur.com/QK8RXWb.png)
Case has already made that happen with the code here...
https://hydrogenaud.io/index.php/topic,110516.msg1049113.html#msg1049113
3.6.7 also contains this version as an included sample but it is missing a few fixes Case posted minutes after I released it. :P
The next version should be up to date.
"VUMeter ilovefb2k + Case + marc2003" This is a VUMeter with 4 bars (FL, FL FR, FR) in the ilovefb2k style.
-----
(https://i.imgur.com/7Xakxjx.png)
Can you add a pattern like this?
This is a low-level request from a low-level user, but I would appreciate your help.
"VUMeter ilovefb2k + Case + marc2003" This is a VUMeter with 4 bars (FL, FL FR, FR) in the ilovefb2k style.
-----
(https://i.imgur.com/7Xakxjx.png)
Can you add a pattern like this?
This is a low-level request from a low-level user, but I would appreciate your help.
I will second that request.
I would even go out on a limb and request the option to have the 4 bars display selectable in either the rainbow bars pattern that marc2k3 originally posted, or the original 4 bars with the horizontally segmented RMS bars and solid Peak bars in the blue/white scheme as posted by Air KEN above. With all the newest internal performance modifications and user options, of course :-X . I better "quit while I'm ahead", haha..
you guys are amazing i copied your code and adjusted the rainbow colors to find my own gradient of orange peaking at red fitting my own theme way better than the stock VU meter
cheers 8)
Edit: Failed to reply to Case,
If I had one small request it would be less blank space to the right of the bars or knowing what value I need to change to adjust that?
2.Edit: I figured it out, it's on line 265
Can someone tell me where to find a script to display playlists in tree?
It seems incredible to me but I can't find any component that works :(
Can someone tell me where to find a script to display playlists in tree?
It seems incredible to me but I can't find any component that works :(
If you use Columns UI you can install the Playlist switcher panel (image1).
If you use Default UI in the foobar menu View/Playlist Manager. It offers the playlists but in a popup window (image2). I don't think it can be set in a panel.
Can someone tell me where to find a script to display playlists in tree?
It seems incredible to me but I can't find any component that works :(
If you use Columns UI you can install the Playlist switcher panel (image1).
If you use Default UI in the foobar menu View/Playlist Manager. It offers the playlists but in a popup window (image2). I don't think it can be set in a panel.
thanks but I use playlist switcher and dont' work correctly :(
I can't use popup windows.
I have installed Jscript panel because I thought I would find a script for playlists :(
I have installed Jscript panel because I thought I would find a script for playlists :(
You mean "hoped".
I have installed Jscript panel because I thought I would find a script for playlists :(
Playlist Organizer (aka foo_plorg) replacement on Jscript Panel 3
https://hydrogenaud.io/index.php/topic,123820.0.html
The most recent script release is at the bottom of page 15:
https://hydrogenaud.io/index.php/topic,123820.msg1035088.html#msg1035088
What it looks like in the fb2k I use:
I have installed Jscript panel because I thought I would find a script for playlists :(
Playlist Organizer (aka foo_plorg) replacement on Jscript Panel 3
https://hydrogenaud.io/index.php/topic,123820.0.html
The most recent script release is at the bottom of page 15:
https://hydrogenaud.io/index.php/topic,123820.msg1035088.html#msg1035088
What it looks like in the fb2k I use:
[attach type=thumb]31971[/attach]
thanks
I have installed foo_jscript_panel3-3.6.9, after I have downloaded pl_organizer2.0.8.zip, extract the files and I have try to import into jscript panel pl_organizer.js but I receive this error:
JScript Panel 3.6.9 (id:1639066)
Errore di run-time di JavaScript
'_scale' non è definito
File: <main>
Line: 49, Col: 1
:(
@LauraQ
Reply #374 By: etip
https://hydrogenaud.io/index.php/topic,123820.msg1035088.html#msg1035088
Unzip the downloaded "pl_organizer2.0.8.zip".
Rename the "pl_organizer2.0.8" folder to "pl_organizer".
Standard installation: "C:\Users\username\AppData\Roaming\foobar2000-v2\pl_organizer"
Portable installation:
\profile\pl_organizer\Main.js
\profile\pl_organizer\pl_organizer.js
\profile\pl_organizer\inputbox.js
\profile\pl_organizer\scrollbar.js
Prepare a JSP 3 Panel.
Load the \pl_organizer\Main.js file.
----
This is not a Playlist Tree. It is a script for organizing playlists.
Create new folders to categorize similar playlists.
If you're using the Default UI, have you panelized the standard Album List?
If you are using Columns UI, you need an Album list panel.
https://yuo.be/album-list-panel
@LauraQ
Reply #374 By: etip
https://hydrogenaud.io/index.php/topic,123820.msg1035088.html#msg1035088
Unzip the downloaded "pl_organizer2.0.8.zip".
Rename the "pl_organizer2.0.8" folder to "pl_organizer".
Standard installation: "C:\Users\username\AppData\Roaming\foobar2000-v2\pl_organizer"
Portable installation:
\profile\pl_organizer\Main.js
\profile\pl_organizer\pl_organizer.js
\profile\pl_organizer\inputbox.js
\profile\pl_organizer\scrollbar.js
Prepare a JSP 3 Panel.
Load the \pl_organizer\Main.js file.
----
This is not a Playlist Tree. It is a script for organizing playlists.
If you're using the Default UI, have you panelized the standard Album List?
If you are using Columns UI, you need an Album list panel.
https://yuo.be/album-list-panel
Thanks :)
now it works great!
Last courtesy, do you know how to remove the #number that I see at the top and that red line that I see immediately below?
@Air KEN Thanks Air KEN.
I was in the middle of typing out a reply for LauraQ and decided to check if someone had replied with help.
This is not a Playlist Tree. It is a script for organizing playlists.
Thanks too for the correction. I knew the Playlist Organizer was a manager. But considered it to be in a
tree style.
Perhaps LauraQ is looking for someting different than this?
@LauraQ
Is this okay?
This is not a Playlist Tree.
pl_organizer:
It is a script for organizing playlists.
Create new folders to categorize similar playlists.
-----
Look around contextmenu > Setting > Appearance >.
thanks everyone. I don't think I understood the difference between the two types of playlist organizers, they seem identical to me.
When I imported the script, I don't know how, it automatically imported the playlists I had in Playlist switcher... it seems really identical and works fine for the little I've tried it.
Thanks again for the help :)
@LauraQ Playlist Organizer (Jscript Panel 3) is useful, so you should use it.
Are you using Columns UI?
What are you looking for? Album list panel or Playlist switcher
Album list panel (Columns UI panel - Tree Format)
https://yuo.be/album-list-panel
(https://i.imgur.com/JQWy28M.png)
Reply #1748 By: marc2k3
https://hydrogenaud.io/index.php/topic,110499.msg1049256.html#msg1049256
rainbow_stops = [
[ 0.0, RGB(180, 220, 255) ],
[ 0.33, RGB(45, 170, 255) ],
[ 0.66, RGB(5, 71, 219) ],
[ 1.0, RGB(0, 16, 93) ],
];
init();
JSP3 VU Meter - Blue
(https://i.imgur.com/XJcO2yW.png)
@LauraQ
Playlist Organizer (Jscript Panel 3) is useful, so you should use it.
Are you using Columns UI?
What are you looking for? Album list panel or Playlist switcher
Album list panel (Columns UI panel - Tree Format)
https://yuo.be/album-list-panel
(https://i.imgur.com/JQWy28M.png)
I use Columns UI
I was looking for a replacement for Playlist Switcher but I don't see any differences with the one that I have installed.
The only thing I would like is to have a slightly better graphic. For example, folders are indicated by two square brackets. It would be nice to have customizable icons. Then I can't make the yellow outline of the playlist disappear and I wouldn't want the numbers of the files contained in the playlists to be displayed. I saw that there is the possibility of importing themes but I don't know where to download them
@LauraQ
Maybe you should read the thread a bit more and play around with the options.
@LauraQ
Maybe you should read the thread a bit more and play around with the options.
Yes, sure :)
This playlist manager is bundled with the component itself ....
https://jscript-panel.github.io/gallery/smooth-playlist-manager/
is better looking without weird yellow/red bits, obeys your UI colours by default and has a whole bunch of features detailed below the image on that page.
But the item count is not optional.
This playlist manager is bundled with the component itself ....
https://jscript-panel.github.io/gallery/smooth-playlist-manager/
is better looking without weird yellow/red bits, obeys your UI colours by default and has a whole bunch of features detailed below the image on that page.
But the item count is not optional.
it looks nice but i dont see the link to download it :(
I said it was bundled with the component. Open the configuration window>click the samples button.
I said it was bundled with the component. Open the configuration window>click the samples button.
oh, sorry... ok I have find it but isn't so good for me.
since you are so kind I ask you another favor
I have the old foobar2000 interface, with some tabs at the top (lyrics, playlist, cover) and at the bottom the list of what to buy when I click on one of my playlists.
The songs at the bottom appear like this:
Artist name - Song title
I don't want any more info because I have them all at the top.
The only thing I would like, if possible, is to have some stars next to them that I can turn on based on the vote I give to the song and that, obviously, must be stored in some file.
Is this possible or is it science fiction? :)
I have see that, in the sample, jscript have Rating voice but I can only put a new tab and not put them next to the song titles :(
Reply #1748 By: marc2k3
https://hydrogenaud.io/index.php/topic,110499.msg1049256.html#msg1049256
rainbow_stops = [
[ 0.0, RGB(180, 220, 255) ],
[ 0.33, RGB(45, 170, 255) ],
[ 0.66, RGB(5, 71, 219) ],
[ 1.0, RGB(0, 16, 93) ],
];
init();
JSP3 VU Meter - Blue
(https://i.imgur.com/XJcO2yW.png)
rainbow_stops = [
[ 0.0, RGB(151, 196, 199) ],
[ 0.33, RGB(62, 160, 180) ],
[ 0.66, RGB(31, 80, 89)],
[ 1.0, RGB(11, 27, 31) ],
];
JSP3 VU Meter - Green
(https://i.imgur.com/E9OJZ5p.png)
Reply #1748 By: marc2k3
https://hydrogenaud.io/index.php/topic,110499.msg1049256.html#msg1049256
rainbow_stops = [
[ 0.0, RGB(180, 220, 255) ],
[ 0.33, RGB(45, 170, 255) ],
[ 0.66, RGB(5, 71, 219) ],
[ 1.0, RGB(0, 16, 93) ],
];
init();
JSP3 VU Meter - Blue
(https://i.imgur.com/XJcO2yW.png)
Thanks Air KEN for the Blue stops! Here is the marc2k3 4-bar for you using that scheme. Original stops are commented out so you can revert:
// ==PREPROCESSOR==
// @name "VU Meter"
// 4 color bars
// @author "ilovefb2k + Case + marc2003"
// @import "%fb2k_component_path%helpers.txt"
// ==/PREPROCESSOR==
var timer_interval = 60; //ms
var timer_id = 0;
var font = CreateFontString("Segoe UI", 8);
var ww = 0, wh = 0;
var minDB = -60;
var RMS_level1 = RMS_level2 = Peak_level1 = Peak_level2 = prev_time = 0;
//var stops = [
// [ 1.0, RGB(227, 9, 64) ],
// [ 0.66, RGB(231, 215, 2) ],
// [ 0.33, RGB(15, 168, 149) ],
// [ 0.0, RGB(19, 115, 232) ]
//];
var stops = [
[ 0.0, RGB(180, 220, 255) ],
[ 0.33, RGB(45, 170, 255) ],
[ 0.66, RGB(5, 71, 219) ],
[ 1.0, RGB(0, 16, 93) ],
];
var brush = {
Stops : stops,
Start : [0, 0], // x and y values
End : [0, 0], // x and y values
};
var brush_str = "";
var colours = {
text : 0,
background : 0,
};
update_colours();
if (fb.IsPlaying) start_timer();
function update_colours() {
if (window.IsDefaultUI) {
colours.text = window.GetColourDUI(ColourTypeDUI.text);
colours.background = window.GetColourDUI(ColourTypeDUI.background);
} else {
colours.text = window.GetColourCUI(ColourTypeCUI.text);
colours.background = window.GetColourCUI(ColourTypeCUI.background);
}
}
function to_db(num) {
var ret = (2000 * Math.log(num) / Math.LN10 / 100);
return clamp(ret, minDB, 0);
}
function clamp(value, min, max) {
if (value < min) return min;
if (value > max) return max;
return value;
}
function start_timer() {
if (timer_id)
return;
timer_id = window.SetInterval(function() {
var cur_time = fb.PlaybackTime;
if (cur_time) {
var chunk = fb.GetAudioChunk(cur_time - prev_time);
if (chunk) {
prev_time = cur_time;
var data = chunk.Data.toArray();
if (data) {
var ch_count = chunk.ChannelCount;
var frame_len = chunk.SampleCount;
var ch2_idx = 1;
if (ch_count < 2) ch2_idx = 0;
var sum1 = 0;
var sum2 = 0;
var peak1 = 0;
var peak2 = 0;
for (var i = 0; i < data.length; i += ch_count) {
var l = data[i];
var r = data[i + ch2_idx];
if (l > peak1) peak1 = l;
if (r > peak2) peak2 = r;
sum1 += l * l;
sum2 += r * r;
}
RMS_level1 = Math.sqrt(sum1/frame_len);
RMS_level2 = Math.sqrt(sum2/frame_len);
Peak_level1 = peak1;
Peak_level2 = peak2;
}
}
}
window.Repaint();
}, timer_interval);
}
function stop_timer(clear) {
if (timer_id)
window.ClearInterval(timer_id);
timer_id = 0;
if (clear)
clear_meter();
}
function clear_meter() {
RMS_level1 = RMS_level2 = Peak_level1 = Peak_level2 = prev_time = 0
window.Repaint();
}
function FillRectangle(gr, x, y, w, h) {
var db = to_db(w);
var rw = Math.round(ww * ((100 + db) / 65 - 40 / 65));
gr.FillRectangle(x, y, rw, h - 1, brush_str);
}
function on_colours_changed() {
update_colours();
window.Repaint();
}
function on_paint(gr) {
gr.FillRectangle(0, 0, ww, wh, colours.background);
var h = 20;
var VU_x = 20;;
var VUy = 5;
var VUw = ww - 20;
var yL = VUy + h;
var yLM = VUy + (h * 2);
var yRM = VUy + (h * 3);
var yR = VUy + (h * 4);
// labels
gr.WriteTextSimple("FL", font, colours.text, 0, yL, VU_x, h, 2, 2);
gr.WriteTextSimple("FL", font, colours.text, 0, yLM, VU_x, h, 2, 2);
gr.WriteTextSimple("FR", font, colours.text, 0, yRM, VU_x, h, 2, 2);
gr.WriteTextSimple("FR", font, colours.text, 0, yR, VU_x, h, 2, 2);
var label_width = (ww - VU_x) / 13;
var labels = [-60, -55, -50, -45, -40, -35, -30, -25, -20, -15, -10, -5, 0];
labels.forEach(function (label, i) {
gr.WriteTextSimple(label + "dB", font, colours.text, 10 + (i * label_width), yR + h + 10, label_width, h);
});
gr.DrawLine(VU_x, yR + h + 5, ww - VU_x, yR + h + 5, 1, colours.text);
// bars
FillRectangle(gr, VU_x, yLM, RMS_level1, h);
FillRectangle(gr, VU_x, yRM, RMS_level2, h);
FillRectangle(gr, VU_x, yL, Peak_level1, h);
FillRectangle(gr, VU_x, yR, Peak_level1, h);
}
function on_playback_new_track(handle) {
start_timer();
}
function on_playback_pause(state) {
state ? stop_timer() : start_timer();
}
function on_playback_stop(reason) {
if (reason != 2) {
stop_timer(true);
}
}
function on_size() {
ww = window.Width;
wh = window.Height;
brush.End = [ww, 0];
brush_str = JSON.stringify(brush);
}
For those using 3.6.9 and the included VU Meter, saving this inside your component folder\samples\js adds custom gradient support to the right click menu...
https://raw.githubusercontent.com/jscript-panel/component/main/samples/js/vu_meter.js
It will be in the next release.
(https://i.imgur.com/BH68aDn.png)
@sveakul
Hi.
The 4 color bars type is also cool.
I'm using it right away
Thanks.
@marc2k3
Good idea. Thanks.
If possible, I would also like a Reset Option.
Now, we are initializing "JScript Panel Configuration > Samples > VU Meter" by running.
Reply #1748 By: marc2k3
https://hydrogenaud.io/index.php/topic,110499.msg1049256.html#msg1049256
rainbow_stops = [
[ 0.0, RGB(180, 220, 255) ],
[ 0.33, RGB(45, 170, 255) ],
[ 0.66, RGB(5, 71, 219) ],
[ 1.0, RGB(0, 16, 93) ],
];
init();
JSP3 VU Meter - Blue
(https://i.imgur.com/XJcO2yW.png)
rainbow_stops = [
[ 0.0, RGB(151, 196, 199) ],
[ 0.33, RGB(62, 160, 180) ],
[ 0.66, RGB(31, 80, 89)],
[ 1.0, RGB(11, 27, 31) ],
];
JSP3 VU Meter - Green
(https://i.imgur.com/E9OJZ5p.png)
JSP 3 VU Meter - The three primary colors
rainbow_stops = [
[ 0.0, RGB(109, 255, 204) ],
[ 0.33, RGB(255, 255, 0) ],
[ 0.66, RGB(255, 0, 255) ],
[ 1.0, RGB(255, 0, 0) ],
];
init();
(https://i.imgur.com/E06byNP.png)
I said it was bundled with the component. Open the configuration window>click the samples button.
I'm learning to use your program and it's FANTASTIC!
I wanted to ask you two things, I added the cover, but it bothers me that when I go over it with the mouse a text with the path appears, is it possible not to make it appear?
Then, I saw that there is the rating script which is beautiful. Could we also add artist song title?
So as to see only:
Artist - Songtitle xxxxx (stars)
Is it possible?
If possible, I would also like a Reset Option.
Not specific to the VU meter but for any panel that stores persistent settings: Hold shift+win key together. Right click panel>Clear properties.
I wanted to ask you two things, I added the cover, but it bothers me that when I go over it with the mouse a text with the path appears, is it possible not to make it appear?
Open the configuration window, add this code at the start
function _tt() {}
As for rating, there is no existing option but tooltips show the selected aritst/title when you hover your mouse over it.
The next release is going to contain a combined
Text Display + Album Art + Rating like this.
(https://i.imgur.com/UXYuCHn.png)
Like the current rating script, you can choose between Playback Statistics (foo_playcount) or writing file tags.
orange to red gradient VU meter colors
rainbow_stops = [
[ 1.0, RGB(255, 0, 0) ],
[ 0.66, RGB(255, 60, 1) ],
[ 0.33, RGB(255, 128, 0) ],
[ 0.0, RGB(255, 160, 75) ]
];
how do you get it to show the full bars for screenshots have a tone that peaks or?
orange to red gradient VU meter colors
rainbow_stops = [
[ 1.0, RGB(255, 0, 0) ],
[ 0.66, RGB(255, 60, 1) ],
[ 0.33, RGB(255, 128, 0) ],
[ 0.0, RGB(255, 160, 75) ]
];
how do you get it to show the full bars for screenshots have a tone that peaks or?
Keep the custom rainbow stops you added if you want the orange tones
Colors: custom, rainbow
Meter Style: smooth
That's with the JPS3 3.6.9 meter, may have changed with 3.6.10
@marc2k3
Hi.
Reply #1760: https://hydrogenaud.io/index.php/topic,110516.msg1049320.html#msg1049320
I would like to use the color change of the JSP 3 VU Meter bar in Minimal Seekbar. Thank you in advance.
(To be able to choose the color)
orange to red gradient VU meter colors
rainbow_stops = [
[ 1.0, RGB(255, 0, 0) ],
[ 0.66, RGB(255, 60, 1) ],
[ 0.33, RGB(255, 128, 0) ],
[ 0.0, RGB(255, 160, 75) ]
];
how do you get it to show the full bars for screenshots have a tone that peaks or?
Keep the custom rainbow stops you added if you want the orange tones
Colors: custom, rainbow
Meter Style: smooth
That's with the JPS3 3.6.9 meter, may have changed with 3.6.10
that makes no sense.
If you want to fake a full bar, add this to your panel temporarily.
function to_db() {
return Math.random();
}
perfect, thanks Marc 8)
If possible, I would also like a Reset Option.
Not specific to the VU meter but for any panel that stores persistent settings: Hold shift+win key together. Right click panel>Clear properties.
I wanted to ask you two things, I added the cover, but it bothers me that when I go over it with the mouse a text with the path appears, is it possible not to make it appear?
Open the configuration window, add this code at the start
function _tt() {}
As for rating, there is no existing option but tooltips show the selected aritst/title when you hover your mouse over it.
The next release is going to contain a combined Text Display + Album Art + Rating like this.
(https://i.imgur.com/UXYuCHn.png)
Like the current rating script, you can choose between Playback Statistics (foo_playcount) or writing file tags.
thanks for the help
I created my own skin that I really like and I don't want to change it :)
I use Columns UI, I created a Horizontal splitter - Tab task - JScript Panel 3. Click on Configure - Sample and I have select Text Display
After I have edited the script and put
function _tt() {}
under
// https://jscript-panel.github.io/gallery/text-display/
but nothing has changed :(
You're next release is very good but fom me that I hate black color and horizontal still, I prefer my ^_^
(https://i.postimg.cc/fZf0hN22/Immagine-negli-appunti-20-agosto-2024.jpg)
and this is how I dream it could become. I pasted the rating stars where I would like them to be. Obviously nobody likes my idea but I wanted to say it O:)
And sorry for the space taken up, I didn't understand how to make the photos smaller
(https://i.postimg.cc/hPKF9xWm/ghhg-4.jpg)
I don't like bright colors for the VU Metter.
This is my script:
rainbow_stops = [
[ 0.003, RGB(255, 0, 0) ],
[ 0.003, RGB(15, 15, 15) ],
[ 0.66, RGB(210, 210, 210) ],
[ 1.0, RGB(255, 0, 0) ],
];
I would like to be able to remove the red bars on the left side.
orange to red gradient VU meter colors
rainbow_stops = [
[ 1.0, RGB(255, 0, 0) ],
[ 0.66, RGB(255, 60, 1) ],
[ 0.33, RGB(255, 128, 0) ],
[ 0.0, RGB(255, 160, 75) ]
];
how do you get it to show the full bars for screenshots have a tone that peaks or?
Keep the custom rainbow stops you added if you want the orange tones
Colors: custom, rainbow
Meter Style: smooth
That's with the JPS3 3.6.9 meter, may have changed with 3.6.10
that makes no sense.
Whether it makes sense or not, attached are the menu settings that show a "full bar with a tone that peaks", using a modified rainbow_stops addition to the config file. I may be misinterpreting your question "how do you get it to show the full bars for screenshots have a tone that peaks or?". Telling me what did or didn't happen would be more useful than "that makes no sense." I see marc2k3 has given you a one-line full-bar 'fake" by all means use that I'm a rank amateur but I try.
(https://i.imgur.com/cd4TNSU.png)
(https://i.imgur.com/ZP7bz90.png)
BTW, how to make the posted images smaller:
(https://i.imgur.com/OPB3Jen.png)
you don't get it at all dude that is NOT what I was asking for. Marc also already gave the right help.
I don't like bright colors for the VU Metter.
This is my script:
rainbow_stops = [
[ 0.003, RGB(255, 0, 0) ],
[ 0.003, RGB(15, 15, 15) ],
[ 0.66, RGB(210, 210, 210) ],
[ 1.0, RGB(255, 0, 0) ],
];
I would like to be able to remove the red bars on the left side.
> I would like to be able to remove the red bars on the left side.
You state it yourself in the first line.
> [ 0.003, RGB(255, 0, 0) ],
Basically it's weird.
orange to red gradient VU meter colors
rainbow_stops = [
[ 1.0, RGB(255, 0, 0) ],
[ 0.66, RGB(255, 60, 1) ],
[ 0.33, RGB(255, 128, 0) ],
[ 0.0, RGB(255, 160, 75) ]
];
how do you get it to show the full bars for screenshots have a tone that peaks or?
0 -1
You wrote it backwards.
orange to red gradient VU meter colors
rainbow_stops = [
[ 1.0, RGB(255, 0, 0) ],
[ 0.66, RGB(255, 60, 1) ],
[ 0.33, RGB(255, 128, 0) ],
[ 0.0, RGB(255, 160, 75) ]
];
how do you get it to show the full bars for screenshots have a tone that peaks or?
0 -1
You wrote it backwards.
I have copied it from Case's code and only changed the numbers so I didn't ;)
also it could be said this is the correct order since its not actually 0, 0,33 and 0,66 but minus 0 minus 0,33 and minus 0,66 and 1
> also it could be said this is the correct order since its not actually 0, 0,33 and 0,66 but minus 0 minus 0,33 and minus 0,66 and 1
Thanks for this info.
0 -1
You wrote it backwards.
You have no idea what you're talking about.
also it could be said this is the correct order since its not actually 0, 0,33 and 0,66 but minus 0 minus 0,33 and minus 0,66 and 1
You have no idea what you're talking about.
It's perfectly fine and reasonable that you don't understand stuff any of this but don't pull stuff out of your anus just to pretend that you do.
All you need to know is that for horizontal bars in this script, 0.0 is LEFT and 1.0 is RIGHT. The order is irrelevant.
Hi :)
I managed to set up the script the way I like it, the only big problem is that the lines for each song are huge, I think because of the size of the stars. Does anyone know how to resize it all?
I wish there was no space between one title and another, like in the photo I posted before
Thanks
(https://i.postimg.cc/KmBJ44QY/ok.jpg)
I can't help thinking this is what initiated the confusion:
how do you get it to show the full bars for screenshots have a tone that peaks or?
Perhaps English isn't the OP's native language? The above needs at least some punctuation, before it becomes sensible:
"How do you get it to show the full bars, for screenshots? Have a tone that peaks, or...?"
Fortunately, marc2k3 understood:
If you want to fake a full bar, add this to your panel temporarily.
function to_db() {
return Math.random();
}
0 -1
You wrote it backwards.
You have no idea what you're talking about.
also it could be said this is the correct order since its not actually 0, 0,33 and 0,66 but minus 0 minus 0,33 and minus 0,66 and 1
You have no idea what you're talking about.
It's perfectly fine and reasonable that you don't understand stuff any of this but don't pull stuff out of your anus just to pretend that you do.
All you need to know is that for horizontal bars in this script, 0.0 is LEFT and 1.0 is RIGHT. The order is irrelevant.
No stuff is pulled from my Anus, it is fine you know things but don't pull unneeded rudeness out your own anus thanks.
I can't help thinking this is what initiated the confusion:
how do you get it to show the full bars for screenshots have a tone that peaks or?
Perhaps English isn't the OP's native language? The above needs at least some punctuation, before it becomes sensible:
"How do you get it to show the full bars, for screenshots? Have a tone that peaks, or...?"
Fortunately, marc2k3 understood:
If you want to fake a full bar, add this to your panel temporarily.
function to_db() {
return Math.random();
}
exactly :D
This playlist manager is bundled with the component itself ....
https://jscript-panel.github.io/gallery/smooth-playlist-manager/
is better looking without weird yellow/red bits, obeys your UI colours by default and has a whole bunch of features detailed below the image on that page.
But the item count is not optional.
but how do you create folders and subfolders?
And then I don't see all the options to change size, visible or hidden elements.
Hi All,
I have just created a script to add 'value' to foo_youtube component by providing it with a song list.
//------------ CREDIT -----------------//
Credit goes to:
- @Wil-B (https://github.com/Wil-B) for the fantastic 'Find-and-Play' app, along with the 'Biography' and 'Library-Tree' scripts based on Spider Monkey Panel. The 'Find-and-Play' inspired me to explore [YouTube searching]. However I've tried, @Wil-B's scripts still set the benchmark.
- @Marc2003 (https://github.com/jscript-panel) for the excellent [JScript Panel 3] component. @Marc2003 actively updates this component with new features, bug fixes, and beautiful, tidy sample scripts.
# This script uses some API (web service) keys from @Wil-B and @marc2003 for trial purposes. Even though these keys are bundled with their public scripts, we should show and treat them with respect.
//---------- ABOUT this JSP3_foo_youtube_addon script ----------------------//
@1_ Sole Purpose:
- YouTube search for songs or any information.
- For others to improve and tailor to their needs (as usual, I've left many comments for easy reference).
@2_ Prerequisites:
- foo_youtube component: https://www.foobar2000.org/components/view/foo_youtube; https://fy.3dyd.com/ to play YouTube videos.
- and/or yt-dlp.exe (for YouTube search): Get it from here [https://github.com/yt-dlp/yt-dlp] if you want to search YouTube using yt-dlp.exe.
(yt_dlp.exe located under this path : {fb2k_Profile_Path}\skins\external_helper\yt-dlp.exe).
@3_ How It Works:
- Users need to feed foo_youtube with a structured list of songs that is friendly with the [foo_youtube] component. This builds a playlist from track locations (similar to foo_tags).
- Where can we get the song list?
+ Manually: Users input text to search directly on youtube.com (not limited to audio tracks).
+ Still manually: Users input an artist name (1), last.fm verifies this name and returns that artist's song list from its database (2), and then youtube.com searches for this data (artist + song title).
+ Automatically: Get the list from somewhere.
- Possible online 'databases':
* MusicBrainz (musicbrainz.org)
* lastFM (last.fm, ws.audioscrobbler.com): We prefer this database as last.fm seems to be YouTube's ally.
> Top trending tracks
> Artist's top tracks classified by locale, years, genre, etc.
* Official Charts (officialcharts.com)
@4_ How We Interact with This Script:
- Context menu via right-click.
@5_ Why YouTube Music:
- We may not get 'high-res' audio tracks from youtube.com, BUT:
- It's a huge store for audio tracks, especially the [YouTube Music] streaming platform.
- Videos often contain audio tracks.
- Some/many audio tracks were/are uploaded by artists, 'semi-artists,' and are only available on this platform (especially single versions).
- Trending.
. . .
Let's dive in!
@6_ Limitations:
- YouTube searching may return irrelevant results, such as other artists' audio tracks, instead of the ones we're looking for.
How to improve:
+ Firstly, let YouTube return an audio track list, and then we search for the 'best' or good match based on our judgment (this will slow things down).
+ Alternatively, we can grab only the first/top audio track from the pool list, hoping that YouTuBe (Google) returns the best match ranked at the top (faster approach).
- User interface/UI: Not very user-friendly.
- Bugs: this is just departure , version [1.0.0 QM] 22Aug2024.
Wish you all the best.
ilovefb2k
Ooh, what's that at the bottom. :P
(https://i.imgur.com/voHIHkG.png)
edit: obviously I stole the code. It's from foosion's Direct2D oscilloscope. :))
Text Display + Album Art + Rating
delete
function on_playback_seek() {
seekbar.playback_seek();
}
if no crash.
That bug is now fixed in the latest release. Thanks.
Here's a super-quick conversion of the VU-meter script changed to use the new audio interface in JScript Panel 3.6.6.
// ==PREPROCESSOR==
// @name "JSP3 VU Meter"
// ==/PREPROCESSOR==
var timer_SetInterval = 30; //ms
var VUMeterFb2k = false; // true: foobar2000 VU Meter style; false: free style
var font,font_t = "";
var g_text = "";
var ww = 0, wh = 0;
var colours = {
text : 0,
background : 0,
highlight : 0,
}
var color_1;
var color_2;
var color = [];
var step = 20; // more is less space between bars (cpu powers consumed) and vice versa.
var minDB = -60; //dB as Foobar2000' s built - in VU Meter
var db = [];
var ColourTypeCUI = {
text: 0,
selection_text: 1,
inactive_selection_text: 2,
background: 3,
selection_background: 4,
inactive_selection_background: 5,
active_item_frame: 6
};
var ColourTypeDUI = {
text: 0,
background: 1,
highlight: 2,
selection: 3
};
var FontTypeCUI = {
items : 0,
labels : 1,
};
var FontTypeDUI = {
defaults : 0,
tabs : 1,
lists : 2,
playlists : 3,
statusbar : 4,
console : 5,
};
function update_colours() {
if (window.IsDefaultUI) {
colours.text = window.GetColourDUI(ColourTypeDUI.text);
colours.highlight = window.GetColourDUI(ColourTypeDUI.highlight);
colours.background = window.GetColourDUI(ColourTypeDUI.background);
} else {
colours.text = window.GetColourCUI(ColourTypeCUI.text);
colours.background = window.GetColourCUI(ColourTypeCUI.background);
colours.highlight = blendColours(colours.text, colours.background, 0.4);
}
//custom colours override
// colours.text = RGB(255,255,255);
// colours.highlight = RGB(0,0,250);
// colours.background = RGB(0,0,0);
color_1 = colours.text; // or any color RGB(250,250,250);
color_2 = colours.highlight; // or any color RGB(0,0,0);
color = [];
for (var i = 0; i <= step; i++) {
color.push(blendColours(color_1, color_2, (i / step)));
db.push((minDB / step) * (step - i))
}
}
function update_font() {
if (window.IsDefaultUI) {
font = window.GetFontDUI(FontTypeDUI.defaults);
} else {
font = window.GetFontCUI(FontTypeCUI.items);
}
// adjust size
font_t = font;
var obj = JSON.parse(font_t);
obj.Size -= 4;
font_t = JSON.stringify(obj);
}
update_colours();
update_font();
function on_colours_changed() {
update_colours();
window.Repaint();
}
function on_mouse_lbtn_up(x, y) {
window.ShowConfigure();
}
function on_size() {
ww = window.Width;
wh = window.Height;
}
//------------- just an implementation /////////////
function RGB(r,g,b) { return (0xff000000|(r<<16)|(g<<8)|(b)); }
function RGBA(r, g, b, a) { return ((a << 24) | (r << 16) | (g << 8) | (b)); }
function toRGB(col) {
var a = col - 0xFF000000;
return [a >> 16, a >> 8 & 0xFF, a & 0xFF];
}
function blendColours(c1, c2, factor) { //@Marc2003
var c1 = toRGB(c1);
var c2 = toRGB(c2);
var r = Math.round(c1[0] + factor * (c2[0] - c1[0]));
var g = Math.round(c1[1] + factor * (c2[1] - c1[1]));
var b = Math.round(c1[2] + factor * (c2[2] - c1[2]));
return (0xff000000 | (r << 16) | (g << 8) | (b));
}
function on_paint(gr) {
gr.FillRectangle(0, 0, ww, wh, colours.background);
//
LM = RMS_level1; // ~ VUMeter.LeftLevel;
RM = RMS_level2; // ~ VUMeter.RightLevel;
L = Peak_level1; // ~ VUMeter.LeftPeak;
R = Peak_level2; // ~ VUMeter.RightPeak;
var h = 20; // VUh_bar;
var VUh_bar = 20; //
var VU_x = 20; //VUx;
var VUy = 5;
var VUh_off = h + 5;
var VUw = ww - 20;
var yL = (VUy + h);
var yLM = (VUy + h) + VUh_bar;
var yRM = (VUy + h) + VUh_bar + VUh_off;
var yR = (VUy + h) + VUh_bar + VUh_off + VUh_bar;
var dbLM = PctToDB(LM),
dbRM = PctToDB(RM),
dbL = PctToDB(L),
dbR = PctToDB(R);
if (VUMeterFb2k) {// foobar2000 VUMeter style
if (!(dbLM == 0 || dbLM == -Infinity)) {
// 65 : -60db- 0dB (+ 5dB offset at the end beyond 0dB ) scale
var wLM = Math.round(ww * ((100 + Number(dbLM)) / 65 - 40 / 65));
var wRM = Math.round(ww * ((100 + Number(dbRM)) / 65 - 40 / 65));
var wL = Math.round(ww * ((100 + Number(dbL)) / 65 - 40 / 65));
var wR = Math.round(ww * ((100 + Number(dbR)) / 65 - 40 / 65));
FillGradientRectangle(gr, VU_x, yLM, wLM, h - 1, 1, colours.text, colours.highlight);
FillGradientRectangle(gr, VU_x, yRM, wRM, h - 1, 1, colours.text, colours.highlight);
FillGradientRectangle(gr, VU_x, yL, wL, h - 1, 1, colours.text, colours.highlight);
FillGradientRectangle(gr, VU_x, yR, wR, h - 1, 1, colours.text, colours.highlight);
}
} else { // free style
h = 15;
var offset = Math.floor((VUw - VU_x) / (step + 1)); //step+1 : number of bars and we need 1 more bar at the end
var w = Math.floor((VUw - VU_x) / (step + 4)); // step+4 : width bar. we need some spaces between bars.
for (var i = 0; i <= step; i++) {
if (i > 0) {
dbLM = PctToDB(LM),
dbRM = PctToDB(RM),
dbL = PctToDB(L),
dbR = PctToDB(R);
}
gr.FillRectangle(VU_x + i * offset, yLM, w, h, dbLM >= db[i] ? color[i] : RGBA(0, 0, 0, 0));
gr.FillRectangle(VU_x + i * offset, yRM, w, h, dbRM >= db[i] ? color[i] : RGBA(0, 0, 0, 0));
if ((dbL > db[i] && dbL < db[i + 1])) {
var wL = i * offset + offset / Math.abs(db[i + 1] - db[i]) * Math.abs(dbL - db[i]);
gr.FillRectangle(VU_x, yL, wL, h, color[i]);
}
if ((dbR > db[i] && dbR < db[i + 1])) {
var wR = i * offset + offset / Math.abs(db[i + 1] - db[i]) * Math.abs(dbR - db[i]);
gr.FillRectangle(VU_x, yR, wR, h, color[i]);
}
}
}
// X-,Y-axis
for (var i = (65 - 5) / 5, j = 0; i >= 0; i--, j++)
gr.WriteText("-" + 5 * i + "dB", font_t, colours.text, VU_x / 2 + j * (ww - VU_x) / 13, yR + h + 10, ww, wh);
gr.WriteText("FL", font_t, colours.text, 0, yLM, ww, wh);
gr.WriteText("FL", font_t, colours.text, 0, yL, ww, wh);
gr.WriteText("FR", font_t, colours.text, 0, yRM, ww, wh);
gr.WriteText("FR", font_t, colours.text, 0, yR, ww, wh);
FillGradientRectangle(gr, VU_x, yR + h + 5, ww, 1, 1, colours.text, colours.highlight);
}
function clear_meter() {
RMS_level1 = 0;
RMS_level2 = 0;
Peak_level1 = 0;
Peak_level2 = 0;
prev_time = 0;
window.Repaint();
}
function on_playback_new_track(handler) {
VUMeter();
}
function on_playback_stop(reason) {
if (reason != 2) { // not starting another track
offVUMeterTimer();
clear_meter();
}
}
function on_playback_pause(state) {
state ? offVUMeterTimer() : onVUMeterTimer();
}
var RMS_level1 = RMS_level2 = Peak_level1 = Peak_level2 = 0; // RMS and Peak level of each 2 channels.
var timer_SetInterval_id = null;
var prev_time = 0;
function on_script_unload() {
}
function PctToDB(num) {
// input : num [0-1]
// output: dB [-100,0]
return ((2000 * Math.log(num) / Math.LN10) / 100).toFixed(2);
}
function onVUMeterTimer() {
if (!fb.IsPlaying || fb.IsPaused) return;
if (timer_SetInterval_id === null) {
timer_SetInterval_id = window.SetInterval(function() {
if (fb.PlaybackTime) {
var cur_time = fb.PlaybackTime;
var chunk = fb.GetAudioChunk(cur_time - prev_time);
if (chunk) {
prev_time = cur_time;
var data = chunk.Data.toArray();
if (data) {
var ch_count = chunk.ChannelCount;
var frame_len = chunk.SampleCount;
var ch2_idx = 1;
if (ch_count < 2) ch2_idx = 0;
var sum1 = 0;
var sum2 = 0;
var peak1 = 0;
var peak2 = 0;
for (var i = 0; i < data.length; i += ch_count) {
var l = data[i];
var r = data[i + ch2_idx];
if (l > peak1) peak1 = l;
if (r > peak2) peak2 = r;
sum1 += l * l;
sum2 += r * r;
}
RMS_level1 = Math.sqrt(sum1/frame_len);
RMS_level2 = Math.sqrt(sum2/frame_len);
Peak_level1 = peak1;
Peak_level2 = peak2;
}
}
}
//(window.RepaintRect(x, y, w, h);
window.Repaint();
}, timer_SetInterval);
}
}
function offVUMeterTimer() {
if (timer_SetInterval_id) window.ClearInterval(timer_SetInterval_id);
timer_SetInterval_id = null;
}
onVUMeterTimer();
function VUMeter() {
offVUMeterTimer(); //turn off timer
var handle = fb.IsPlaying ? fb.GetNowPlaying() : false;
if (!handle) return;
// set VUMeter timer tiktok
onVUMeterTimer();
}
function FillGradientRectangle(gr, x, y, w, h, direction, colour1, colour2) { //@Marc2003
var stops = [[0, colour1], [1, colour2]];
var brush = {
Start: [0, 0],
Stops: stops
};
if (direction == 0)
brush.End = [0, h];
else
brush.End = [w, 0];
gr.FillRectangle(x, y, w, h, JSON.stringify(brush));
}
//EOF
Edit: tiny bit cleaned up version.
Hi Case--your first version of the VU Meter implementation made possible by marc2k3's new JSP code was here, using the same meter GUI as the original Ilovefb2k release. Because the image scheme is classic, I am hoping that you wouldn't mind releasing a new version of the script?
The original has the problem of the 2 peak bars flickering out/disappearing when 0dB is reached or exceeded--have you found a way to fix that? Also, it would be great if you could add the ability to adjust peak hold ms, and the ability to specify a maxdB level. Thanks for any consideration!
(https://i.imgur.com/4Vg41Ge.png)
Case already rewrote it once. At this point, you're taking the piss.
@eurekagliese I made the final switch to 64 bit.
I noticed something strange about the radio stream.
The default custom track is automatically set in enable dynamic.
This all happens with m3u files from playlists.
(https://i.imgur.com/fx1n5iJ.png)
(https://i.imgur.com/ykpVndw.png)
Case already rewrote it once. At this point, you're taking the piss.
My request was directed at Case. By the way, the script in his post I quoted above is the only one where he used the original ilovefb2k format 4-bar meter, with the segmented RMS ones and solid peak. I'm fully aware that he posted a second rewrite, which I have, but that one used the 2-bar RMS format with the peak as an end indicator line. I won't trade insults with you, just state facts.
It is possible to adapt this Digital Clock module for JS 3 scripts?
For the Digital Clock + Calendar module, I have currently partially solved it with a version for
foo_uie_webview very simplified, manages only one language and one color:
(https://i.imgur.com/kJABleK.png)
In the Thumbs sample I was unable to find, both in the loading modules and in the Thumbs module, the instruction that allows me to change the black color that I have under the various thumbs.
(https://i.imgur.com/C6ABMz9.png)
I have the entire skin in Dark Mode with the default UI setting, and I would like that black area under the thumbs to use the default UI setting.
Feature request @mark2k3
Add genre and locale/country taggers to lastfm scripts. (Like in SMP Biography)
It would be nice to be able to fetch the fields from lastfm and write them into tags.
Also regarding the Lastfm + Bio script, perhaps adding Popular Now and removing the Tags: string would be nice.
(https://i.imgur.com/3v8Py1e.jpeg)
Thank you.
@eurekagliese
I made the final switch to 64 bit.
I noticed something strange about the radio stream.
The default custom track is automatically set in enable dynamic.
This all happens with m3u files from playlists.
(https://i.imgur.com/fx1n5iJ.png)
(https://i.imgur.com/ykpVndw.png)
Solved.
Line 1847 colour_index =1; change to colour_index = 0;
function on_playback_dynamic_info_track(type) {
if (type == 0) {
colour_index = 0;
window.Repaint();
} else {
colour_index = 0; update_album_art(fb.GetNowPlaying())
};
}
with the streaming radio, foobar2000 64 bit and exernal tag it is set by default in enable dynamc in automatic.
m3u in playlist, cover.* in folder dedicated to radio covers.
@marc2k3 ,
I just realized that you stopped supporting Windows 7/8 hence window.CreateThemeManager has disappeared (v3.4.0).
I was using this a lot to draw buttons similarly to your former sample : "SimpleThemedButton + Tooltip".
Do you know any other way to create these buttons with the latest version of JScript ?
Thanks
Replace DrawThemeBackground with DrawRectangle/FillRectangle/rounded variants. You can use utils.GetSysColour to get various default windows colours.
Perfect, thanks !
In the Thumbs sample I was unable to find, both in the loading modules and in the Thumbs module, the instruction that allows me to change the black color that I have under the various thumbs.
(https://i.imgur.com/C6ABMz9.png)
I have the entire skin in Dark Mode with the default UI setting, and I would like that black area under the thumbs to use the default UI setting.
Solved.
common.js
line158 :
// gr.FillRectangle(x, y, w, h, RGBA(0, 0, 0, alpha || 230));
gr.FillRectangle(x, y, w, h, RGBA(33, 33, 33));
(https://i.imgur.com/OiSEiVc.png)
When importing a theme the headerbar.js module of jsplaylist crashes on line 70 currently to avoid this or disabled lines 70 / 71 / 72 of headerbar.js
// var gb = this.slide_close.GetGraphics();
// gb.FillRectangle(0, 0, cScrollBar.width, this.h, g_colour_text & 0x15ffffff);
// gb.WriteTextSimple(chars.right, g_font_fluent_12, g_colour_text, 0, 1, cScrollBar.width, this.h, 2, 2);
No problems with those lines of code here.
Commenting them out means you break this indicator when the playlist manager is open. See attachments.
This is a weird bug, after upgrading 3.7.1 Properties crashes red screen if there is an empty playlist. This doesn't happen when there are albums in the playlist.
JScript Panel 3.7.1 (Properties by marc2003)
JavaScript runtime error
Unable to get property 'Path' of undefined or null reference
File: C:\Portable\foobar2000 64-bit LEGO Edition\foobar2000\profile\user-components-x64\foo_jscript_panel3\samples\js\properties.js
Line: 280, Col: 3
Oops, that's a bug that got introduced in 3.7.0, thanks for spotting.
Saving this in the foo_jscript_panel3 component folder \samples\js overwriting the original should fix it.
https://raw.githubusercontent.com/jscript-panel/component/main/samples/js/properties.js
Hi Case--your first version of the VU Meter implementation made possible by marc2k3's new JSP code was here, using the same meter GUI as the original Ilovefb2k release. Because the image scheme is classic, I am hoping that you wouldn't mind releasing a new version of the script?
The original has the problem of the 2 peak bars flickering out/disappearing when 0dB is reached or exceeded--have you found a way to fix that? Also, it would be great if you could add the ability to adjust peak hold ms, and the ability to specify a maxdB level.
Here's a quick refresh combining bits of old and semi new. Doesn't include any of the fancy menu stuff marc2k3 added.
// ==PREPROCESSOR==
// @name "JSP3 VU Meter (Stereo Mode)"
// ==/PREPROCESSOR==
// User adjustable settings:
var timer_interval = 1000 / 60; // in ms (default: 60 fps update rate)
var rms_window = 50 / 1000; // in seconds (default: 50 ms)
var peak_hold = 1; // in frames
var peak_fall_mul = 0.9;
var minDB = -60; // minimum dB on the meter (meter range)
var maxDB = 5; // maximum dB on the meter (meter range)
var rms_3db = false; // use AES +3dB RMS mode
var bar_height_static = 20; // use 0 to scale to panel size
var rms_block_count = 20; // number of blocks in meter style 1
var rms_block_db = 2.5; // dBs per block in meter style 2
var meter_style = 1; // 1: constant number of blocks, 2: dynamic block count to align with dB scale
//
// End of user adjustable settings
// -------------------------------
var RMS_level1 = RMS_level2 = Peak_level1 = Peak_level2 = Peak_falldown1 = Peak_falldown2 = 0;
var rms_db_offset = (!rms_3db) ? (0) : (20 * Math.log(Math.sqrt(2)) / Math.LN10); // 3.01029995663981 dB
var dBrange = maxDB - minDB;
var timer_id = 0;
var font,font_t = "";
var g_text = "";
var ww = 0, wh = 0;
var color_1;
var color_2;
var colours = {
text : 0,
background : 0,
highlight : 0,
}
var brush = {
Stops : [],
Start : [0, 0], // x and y values
End : [0, 0], // x and y values
};
var brush_str = "";
var ColourTypeCUI = {
text: 0,
selection_text: 1,
inactive_selection_text: 2,
background: 3,
selection_background: 4,
inactive_selection_background: 5,
active_item_frame: 6
};
var ColourTypeDUI = {
text: 0,
background: 1,
highlight: 2,
selection: 3
};
var FontTypeCUI = {
items : 0,
labels : 1,
};
var FontTypeDUI = {
defaults : 0,
tabs : 1,
lists : 2,
playlists : 3,
statusbar : 4,
console : 5,
};
function update_colours() {
if (window.IsDefaultUI) {
colours.text = window.GetColourDUI(ColourTypeDUI.text);
colours.highlight = window.GetColourDUI(ColourTypeDUI.highlight);
colours.background = window.GetColourDUI(ColourTypeDUI.background);
} else {
colours.text = window.GetColourCUI(ColourTypeCUI.text);
colours.background = window.GetColourCUI(ColourTypeCUI.background);
colours.highlight = blendColours(colours.text, colours.background, 0.4);
}
//custom colours override
// colours.text = RGB(255,255,255);
// colours.highlight = RGB(0,0,250);
// colours.background = RGB(0,0,0);
color_1 = colours.text; // or any color RGB(250,250,250);
color_2 = colours.highlight; // or any color RGB(0,0,0);
brush.Stops = [
[0.0, color_1],
[1.0, color_2],
]
brush_str = JSON.stringify(brush);
}
function update_font() {
if (window.IsDefaultUI) {
font = window.GetFontDUI(FontTypeDUI.defaults);
} else {
font = window.GetFontCUI(FontTypeCUI.items);
}
// adjust size
font_t = font;
var obj = JSON.parse(font_t);
obj.Size -= 4;
font_t = JSON.stringify(obj);
}
function RGB(r,g,b) { return (0xff000000|(r<<16)|(g<<8)|(b)); }
function RGBA(r, g, b, a) { return ((a << 24) | (r << 16) | (g << 8) | (b)); }
function toRGB(col) {
var a = col - 0xFF000000;
return [a >> 16, a >> 8 & 0xFF, a & 0xFF];
}
function blendColours(c1, c2, factor) { //@Marc2003
var c1 = toRGB(c1);
var c2 = toRGB(c2);
var r = Math.round(c1[0] + factor * (c2[0] - c1[0]));
var g = Math.round(c1[1] + factor * (c2[1] - c1[1]));
var b = Math.round(c1[2] + factor * (c2[2] - c1[2]));
return (0xff000000 | (r << 16) | (g << 8) | (b));
}
function clear_graph() {
RMS_level1 = RMS_level2 = 0;
Peak_level1 = Peak_level2 = 0;
Peak_falldown1 = Peak_falldown2 = 0;
window.Repaint();
}
function update_graph() {
if (fb.PlaybackTime > rms_window) {
var chunk = fb.GetAudioChunk(rms_window);
if (chunk) {
var data = chunk.Data.toArray();
var nch = chunk.ChannelCount;
var frame_len = chunk.SampleCount;
if (data && nch > 0 && frame_len > 0) {
var ch2_idx = (nch >= 2) ? 1 : 0;
var sum1 = sum2 = peak1 = peak2 = 0;
for (var i = 0; i < data.length; i += nch) {
var s1 = Math.abs(data[i]);
var s2 = Math.abs(data[i + ch2_idx]);
if (s1 > peak1) peak1 = s1;
if (s2 > peak2) peak2 = s2;
sum1 += s1 * s1;
sum2 += s2 * s2;
}
RMS_level1 = Math.sqrt(sum1/frame_len);
RMS_level2 = Math.sqrt(sum2/frame_len);
if (++Peak_falldown1 > peak_hold) Peak_level1 *= peak_fall_mul;
if (++Peak_falldown2 > peak_hold) Peak_level2 *= peak_fall_mul;
if (peak1 >= Peak_level1) {
Peak_level1 = peak1;
Peak_falldown1 = 0;
}
if (peak2 >= Peak_level2) {
Peak_level2 = peak2;
Peak_falldown2 = 0;
}
window.Repaint();
}
}
}
}
function start_timer() {
if (!timer_id) timer_id = window.SetInterval(update_graph, timer_interval);
}
function stop_timer() {
if (timer_id) window.ClearInterval(timer_id);
timer_id = 0;
}
function to_db(num) {
return 20 * Math.log(num) / Math.LN10;
}
function clamp(value, min, max) {
if (value < min) return min;
if (value > max) return max;
return value;
}
function get_colour_for_db(db) {
/*
if (colour_mode != 0) {
var f = db / dBrange;
for (var i = 0; i < rainbow_stops.length-1; ++i) {
var a = rainbow_stops[i][0];
var b = rainbow_stops[i+1][0];
var ca = rainbow_stops[i][1];
var cb = rainbow_stops[i+1][1];
if (b > a) {
var t = a; a = b; b = t;
var tc = ca; ca = cb; cb = tc;
}
if (a >= f && f >= b) {
return blendColours(cb, ca, (f - b) / (a - b));
}
}
}
*/
return blendColours(colours.text, colours.highlight, db / dBrange);
}
// UI callbacks
function on_colours_changed() {
update_colours();
window.Repaint();
}
function on_mouse_lbtn_up(x, y) {
window.ShowConfigure();
}
function on_size() {
ww = window.Width;
wh = window.Height;
}
function on_paint(gr) {
gr.Clear(colours.background);
if (wh < 1 || ww < 1) return;
var hide_ch_labels = false;
var hide_db_labels = false;
var bar_pad_left = 3*8;
var bar_pad_right = 3*8;
var bar_pad_top = 5;
var bar_pad_bottom = 30;
var bar_height = 0;
var bar_width = 0;
bar_height = (bar_height_static > 0) ? (bar_height_static) : (Math.floor((wh - bar_pad_top - bar_pad_bottom) / 4));
if (bar_height < 8) { // bars are too thin for channel labels, hide them
hide_ch_labels = true;
}
if (bar_height < 4) { // bars are too thin for dB scale too
hide_ch_labels = true;
hide_db_labels = true;
bar_pad_top = 0;
bar_pad_bottom = 0;
bar_pad_left = 0;
bar_pad_right = 0;
bar_height = Math.floor(wh / 4);
}
bar_width = ww - bar_pad_left - bar_pad_right;
// labels
if (!hide_db_labels) {
var db_spacing = 5;
if (dBrange < db_spacing) db_spacing = 1;
if (ww * db_spacing / dBrange < 10*8) {
db_spacing = ((10*8 * dBrange) / ww);
db_spacing -= (db_spacing % 5);
}
var y = bar_pad_top + (bar_height * 4) + 5;
gr.FillRectangle(bar_pad_left, y, bar_width, 1, colours.text);
for (var i = minDB, j = 0; i <= maxDB; i += db_spacing, j++) {
var x = bar_pad_left + (bar_width * j / (dBrange / db_spacing));
gr.WriteText(i + "dB", font_t, colours.text, x - (bar_pad_left / 2), y + 5, ww, wh);
gr.DrawLine(x, y-2, x, y+2, 1, colours.text);
}
}
if (!hide_ch_labels) {
gr.WriteText("FL", font_t, colours.text, 4, bar_pad_top + (bar_height * 0) + bar_height / 2 - 8, ww, wh);
gr.WriteText("FL", font_t, colours.text, 4, bar_pad_top + (bar_height * 1) + bar_height / 2 - 8, ww, wh);
gr.WriteText("FR", font_t, colours.text, 4, bar_pad_top + (bar_height * 2) + bar_height / 2 - 8, ww, wh);
gr.WriteText("FR", font_t, colours.text, 4, bar_pad_top + (bar_height * 3) + bar_height / 2 - 8, ww, wh);
}
// bars
var block_count = rms_block_count;
if (meter_style == 2 && rms_block_db > 0) block_count = Math.floor(dBrange / rms_block_db);
if (block_count < 1) block_count = 1;
var block_width = bar_width / block_count;
var block_pad = Math.ceil(block_width * 0.03);
if (block_pad < 1) block_pad = 1;
if (Peak_level1 > 0) {
var peak_db1 = clamp(to_db(Peak_level1), minDB, maxDB);
if (peak_db1 > minDB) {
var width1 = Math.round(bar_width * (peak_db1 - minDB) / dBrange);
gr.FillRectangle(bar_pad_left, bar_pad_top + (bar_height * 0) + 1, width1, bar_height - 3, brush_str);
}
}
if (Peak_level2 > 0) {
var peak_db2 = clamp(to_db(Peak_level2), minDB, maxDB);
if (peak_db2 > minDB) {
var width2 = Math.round(bar_width * (peak_db2 - minDB) / dBrange);
gr.FillRectangle(bar_pad_left, bar_pad_top + (bar_height * 3) + 1, width2, bar_height - 3, brush_str);
}
}
if (RMS_level1 > 0) {
var rms_db1 = clamp(to_db(RMS_level1) + rms_db_offset, minDB, maxDB);
var blocks1 = Math.round(block_count * (rms_db1 - minDB) / dBrange);
for (var i = 0; i < blocks1; ++i) {
gr.FillRectangle(bar_pad_left + (i * block_width), bar_pad_top + (bar_height * 1) + 1, block_width - block_pad, bar_height - 3, get_colour_for_db(i * dBrange / block_count));
}
}
if (RMS_level2 > 0) {
var rms_db2 = clamp(to_db(RMS_level2) + rms_db_offset, minDB, maxDB);
var blocks2 = Math.round(block_count * (rms_db2 - minDB) / dBrange);
for (var i = 0; i < blocks2; ++i) {
gr.FillRectangle(bar_pad_left + (i * block_width), bar_pad_top + (bar_height * 2) + 1, block_width - block_pad, bar_height - 3, get_colour_for_db(i * dBrange / block_count));
}
}
}
// fb2k callbacks
function on_playback_new_track(handle) {
start_timer();
}
function on_playback_stop(reason) {
if (reason != 2) stop_timer(); // not starting another track
clear_graph();
}
function on_playback_pause(state) {
state ? stop_timer() : start_timer();
}
function init() {
update_colours();
update_font();
if (fb.IsPlaying) start_timer();
}
init();
Here's a quick refresh combining bits of old and semi new. Doesn't include any of the fancy menu stuff marc2k3 added.
Many thanks Case for doing a revision based on the 4-bar "first look" you did after marc2k3 first made the direct data read possible--it fixes ALL the initial performance issues, and while the visual presentation differs slightly from the first (less space between the bars etc.) there are plenty of user configurable settings both grouped as such at the script's top, and in its body for the "daring" to experiment with. Which I will be doing for the rest of the day! Cool.
I found a way, with the sample Text Reader, to read the lyrics that are thrown into the lyrics folder by ESLyrics by inserting the following string in the custom path:
Unsynced
$if($strstr(%path%,'://'),C:\foobar2000 Portable\Apache Evolution Theme 64 BIT\foobar2000\profile\lyrics\%album artist% - %title%.txt)
(https://i.imgur.com/Rgmw0GF.png)
Synced
(https://i.imgur.com/RF2Dtq1.png)
$if($strstr(%path%,'://'),C:\foobar2000 Portable\Apache Evolution Theme 64 BIT\foobar2000\profile\lyrics\%album artist% - %title%.lrc)
Is it possible to change the font from string?
Is it possible to change the font from string?
right? It would be nicer if component developers didn't inflict their preferences on everyone but whatever.
If you choose another font in the main preferences, the panel updates itself to use that. So please go fuck yourself.
And even if it was hardcoded, it's nothing like as abhorrent as that volume changing in the other thread. I notice there was no appreciation of me finding that for you. Go fuck yourself again.
If you choose another font in the main preferences, the panel updates itself to use that. So please go fuck yourself.
And even if it was hardcoded, it's not like as abhorrent as that volume changing in the other thread. I notice there was no appreciation of me finding that for you. Go fuck yourself again.
Not abhorrent, unless someone lacked the slightest understanding of why headlines have different fonts/sizes/colors than body copy, and then insisted on burying in every sample, the opportunity for users to modify the options.
Or how about when someone decides to maintain the most excellent Smooth panels, but proceeds to immediately rip out all of the UX customizations that made them useful in the first place?
The point here is one might be more mindful about throwing stones from glass houses if they are a fragile POS.
@mjm716 while I don't find marc's replies a valid behavior on forums (and still wonder how mods simply ignore these things...), yours makes no sense.
I mean, you may not agree with the development, for sure. And I may find reasonable to criticize things if they have no logic or don't follow the dev's design or intents but... expecting a dev should do something for you just because you want it in a different way, makes zero sense. I mean, no one here is being paid.
If marc chooses to set the default font like
this in all his scripts, it would be perefectly fine... because maybe you have forgotten the first and last user of everything he does is himself. Just saying, people on these forums seem to forget that xd also with my scripts ;) You may ask in a positive way for "options" but complaining about defaults set by the developer.. what answer did you expect? XD
Also if you don't want to spend 3 min searching the line to change the font, maybe a dev doesn't want to spend 1 h creating a menu entry to set it. (not saying is you case, just something which is common around here). Just looking at the VU Meter script for ex. there have been like +10 change requests in one month xd well, maybe people think devs are slaves to fullfill others' desires. ::)
@mjm716 while I don't find marc's replies a valid behavior on forums (and still wonder how mods simply ignore these things...), yours makes no sense.
Firstly I agree with you 100% that *all* devs are entitled to work however they like and we're lucky they do.
context: https://hydrogenaud.io/index.php/topic,126042.msg1050146.html#msg1050146
For sure that applies to everyone, him too. And while that particular reply could be read as rude or a request, I would say it was a tip from a dev to another dev (with wrong wording), since Marc was not requesting anything for himself. I get the irony on your reply, obviously, but they are not the same situation.
Anyway I will not be the one defending his words, I already said this kind of behavior is not allowed on most forums and other users are banned for less. I still don't get what's going on with HA TOS, since point 2 seems to be applied in a totally arbitrary way. Not that I want anyone to be banned.
hi all a bit off the topic but any way to add coloured popup like winamp
many thanks telboy
@telboy1812
> coloured popup like winamp
Could you please be a bit more specific?
------
Flowin (foo_flowin)
https://github.com/ttsping/foo_flowin/releases
(https://i.imgur.com/xAUDbFY.png) (https://i.imgur.com/03kgTfH.png)
On the right is WebView (foo_uie_webview).
https://github.com/stuerp/foo_uie_webview/releases
like this maybe
This is possible with both Flowin (foo_flowin) or Popup Panels (foo_popup_panels).
Popup Panels (foo_popup_panels)
https://www.foobar2000.org/components/view/foo_popup_panels
Flowin:
You can create as many Panels as you like.
There are many options
(https://i.imgur.com/bdvIkD9.png)
This is not the question for this thread.
yes i know and i am sorry I have it installed but no idea how to get it work sorry
almost sorted it thank you ken :)
Hi,
I am using the "Text Display" sample and I want to achieve some specific effects:
1-How can I add a simple white stroke/border effect to the album cover in the foreground?
(Sometimes, the album cover in the foreground can lost itself and blend in the blurred album art background when the album art's colors are darker in general. So, hence why I'd like to achieve this.)
2-How can I add a colored drop shadow effect to the custom text?
Thanks!
Thanks to Case, Air Ken, marc2k3, and ilove2fbk who did the original image, I finally was able to obtain the JSP3 VU Meter design that not only has the latest technical and functional elements but maintained the graphic 4-bar meter design and color scheme of that first pre-JSP3 3.6.6 model. I did a little tweaking myself on the bar padding. Anyway, after everybody having to suffer through my VU Meter design requests here I wanted to post the script for anyone who also hoped for a re-worked version of that clunky original. Requires at least JSP3 3.6.6, working smooth here with the latest 3.7.4 release.
// ==PREPROCESSOR==
// @name "JSP3 VU Meter (Stereo Mode)"
// ==/PREPROCESSOR==
// User adjustable settings:
var timer_interval = 1000 / 60; // in ms (default: 60 fps update rate)
var rms_window = 50 / 1000; // in seconds (default: 50 ms)
var peak_hold = 1; // in frames
var peak_fall_mul = 0.9;
var minDB = -60; // minimum dB on the meter (meter range)
var maxDB = 10; // maximum dB on the meter (meter range)
var rms_3db = false; // use AES +3dB RMS mode
var bar_height_static = 17; // use 0 to scale to panel size
var rms_block_count = 30; // number of blocks in meter style 1
var rms_block_db = 3; // dBs per block in meter style 2
var meter_style = 2; // 1: constant number of blocks, 2: dynamic block count to align with dB scale
//
// End of user adjustable settings
// -------------------------------
var RMS_level1 = RMS_level2 = Peak_level1 = Peak_level2 = Peak_falldown1 = Peak_falldown2 = 0;
var rms_db_offset = (!rms_3db) ? (0) : (20 * Math.log(Math.sqrt(2)) / Math.LN10); // 3.01029995663981 dB
var dBrange = maxDB - minDB;
var timer_id = 0;
var font,font_t = "";
var g_text = "";
var ww = 0, wh = 0;
var color_1;
var color_2;
var colours = {
text : 0,
background : 0,
highlight : 0,
}
var brush = {
Stops : [],
Start : [0, 0], // x and y values
End : [0, 0], // x and y values
};
var brush_str = "";
var ColourTypeCUI = {
text: 0,
selection_text: 1,
inactive_selection_text: 2,
background: 3,
selection_background: 4,
inactive_selection_background: 5,
active_item_frame: 6
};
var ColourTypeDUI = {
text: 0,
background: 1,
highlight: 2,
selection: 3
};
var FontTypeCUI = {
items : 0,
labels : 1,
};
var FontTypeDUI = {
defaults : 0,
tabs : 1,
lists : 2,
playlists : 3,
statusbar : 4,
console : 5,
};
function update_colours() {
if (window.IsDefaultUI) {
colours.text = window.GetColourDUI(ColourTypeDUI.text);
colours.highlight = window.GetColourDUI(ColourTypeDUI.highlight);
colours.background = window.GetColourDUI(ColourTypeDUI.background);
} else {
colours.text = window.GetColourCUI(ColourTypeCUI.text);
colours.background = window.GetColourCUI(ColourTypeCUI.background);
colours.highlight = blendColours(colours.text, colours.background, 0.4);
}
//custom colours override
colours.text = RGB(255,255,255);
colours.highlight = RGB(23,179,255);
colours.background = RGB(30,30,30);
color_1 = colours.text; // RGB(250,250,250);
color_2 = colours.highlight; // RGB(0,70,250);
brush.Stops = [
[3.0, color_1],
[1.2, color_2],
]
brush_str = JSON.stringify(brush);
}
function update_font() {
if (window.IsDefaultUI) {
font = window.GetFontDUI(FontTypeDUI.defaults);
} else {
font = window.GetFontCUI(FontTypeCUI.items);
}
// adjust size
font_t = font;
var obj = JSON.parse(font_t);
obj.Size -= 4;
font_t = JSON.stringify(obj);
}
function RGB(r,g,b) { return (0xff000000|(r<<16)|(g<<8)|(b)); }
function RGBA(r, g, b, a) { return ((a << 24) | (r << 16) | (g << 8) | (b)); }
function toRGB(col) {
var a = col - 0xFF000000;
return [a >> 16, a >> 8 & 0xFF, a & 0xFF];
}
function blendColours(c1, c2, factor) { //@Marc2003
var c1 = toRGB(c1);
var c2 = toRGB(c2);
var r = Math.round(c1[0] + factor * (c2[0] - c1[0]));
var g = Math.round(c1[1] + factor * (c2[1] - c1[1]));
var b = Math.round(c1[2] + factor * (c2[2] - c1[2]));
return (0xff000000 | (r << 16) | (g << 8) | (b));
}
function clear_graph() {
RMS_level1 = RMS_level2 = 0;
Peak_level1 = Peak_level2 = 0;
Peak_falldown1 = Peak_falldown2 = 0;
window.Repaint();
}
function update_graph() {
if (fb.PlaybackTime > rms_window) {
var chunk = fb.GetAudioChunk(rms_window);
if (chunk) {
var data = chunk.Data.toArray();
var nch = chunk.ChannelCount;
var frame_len = chunk.SampleCount;
if (data && nch > 0 && frame_len > 0) {
var ch2_idx = (nch >= 2) ? 1 : 0;
var sum1 = sum2 = peak1 = peak2 = 0;
for (var i = 0; i < data.length; i += nch) {
var s1 = Math.abs(data[i]);
var s2 = Math.abs(data[i + ch2_idx]);
if (s1 > peak1) peak1 = s1;
if (s2 > peak2) peak2 = s2;
sum1 += s1 * s1;
sum2 += s2 * s2;
}
RMS_level1 = Math.sqrt(sum1/frame_len);
RMS_level2 = Math.sqrt(sum2/frame_len);
if (++Peak_falldown1 > peak_hold) Peak_level1 *= peak_fall_mul;
if (++Peak_falldown2 > peak_hold) Peak_level2 *= peak_fall_mul;
if (peak1 >= Peak_level1) {
Peak_level1 = peak1;
Peak_falldown1 = 0;
}
if (peak2 >= Peak_level2) {
Peak_level2 = peak2;
Peak_falldown2 = 0;
}
window.Repaint();
}
}
}
}
function start_timer() {
if (!timer_id) timer_id = window.SetInterval(update_graph, timer_interval);
}
function stop_timer() {
if (timer_id) window.ClearInterval(timer_id);
timer_id = 0;
}
function to_db(num) {
return 20 * Math.log(num) / Math.LN10;
}
function clamp(value, min, max) {
if (value < min) return min;
if (value > max) return max;
return value;
}
function get_colour_for_db(db) {
/*
if (colour_mode != 0) {
var f = db / dBrange;
for (var i = 0; i < rainbow_stops.length-1; ++i) {
var a = rainbow_stops[i][0];
var b = rainbow_stops[i+1][0];
var ca = rainbow_stops[i][1];
var cb = rainbow_stops[i+1][1];
if (b > a) {
var t = a; a = b; b = t;
var tc = ca; ca = cb; cb = tc;
}
if (a >= f && f >= b) {
return blendColours(cb, ca, (f - b) / (a - b));
}
}
}
*/
return blendColours(colours.text, colours.highlight, db / dBrange);
}
// UI callbacks
function on_colours_changed() {
update_colours();
window.Repaint();
}
function on_mouse_lbtn_up(x, y) {
window.ShowConfigure();
}
function on_size() {
ww = window.Width;
wh = window.Height;
}
function on_paint(gr) {
gr.Clear(colours.background);
if (wh < 1 || ww < 1) return;
var hide_ch_labels = false;
var hide_db_labels = false;
var bar_pad_left = 3*8;
var bar_pad_right = 3*8;
var bar_pad_top = 36;
var bar_pad_bottom = 30;
var bar_height = 0;
var bar_width = 0;
bar_height = (bar_height_static > 0) ? (bar_height_static) : (Math.floor((wh - bar_pad_top - bar_pad_bottom) / 4));
if (bar_height < 8) { // bars are too thin for channel labels, hide them
hide_ch_labels = true;
}
if (bar_height < 4) { // bars are too thin for dB scale too
hide_ch_labels = true;
hide_db_labels = true;
bar_pad_top = 0;
bar_pad_bottom = 0;
bar_pad_left = 0;
bar_pad_right = 0;
bar_height = Math.floor(wh / 4);
}
bar_width = ww - bar_pad_left - bar_pad_right;
// labels
if (!hide_db_labels) {
var db_spacing = 5;
if (dBrange < db_spacing) db_spacing = 1;
if (ww * db_spacing / dBrange < 10*8) {
db_spacing = ((10*8 * dBrange) / ww);
db_spacing -= (db_spacing % 5);
}
var y = bar_pad_top + (bar_height * 4) + 5;
gr.FillRectangle(bar_pad_left, y, bar_width, 1, colours.text);
for (var i = minDB, j = 0; i <= maxDB; i += db_spacing, j++) {
var x = bar_pad_left + (bar_width * j / (dBrange / db_spacing));
gr.WriteText(i + "dB", font_t, colours.text, x - (bar_pad_left / 2), y + 5, ww, wh);
gr.DrawLine(x, y-2, x, y+2, 1, colours.text);
}
}
if (!hide_ch_labels) {
gr.WriteText("FL", font_t, colours.text, 4, bar_pad_top + (bar_height * 0) + bar_height / 2 - 8, ww, wh);
gr.WriteText("FL", font_t, colours.text, 4, bar_pad_top + (bar_height * 1) + bar_height / 2 - 8, ww, wh);
gr.WriteText("FR", font_t, colours.text, 4, bar_pad_top + (bar_height * 2) + bar_height / 2 - 8, ww, wh);
gr.WriteText("FR", font_t, colours.text, 4, bar_pad_top + (bar_height * 3) + bar_height / 2 - 8, ww, wh);
}
// bars
var block_count = rms_block_count;
if (meter_style == 2 && rms_block_db > 0) block_count = Math.floor(dBrange / rms_block_db);
if (block_count < 1) block_count = 1;
var block_width = bar_width / block_count;
var block_pad = Math.ceil(block_width * 0.11);
if (block_pad < 1) block_pad = 1;
if (Peak_level1 > 0) {
var peak_db1 = clamp(to_db(Peak_level1), minDB, maxDB);
if (peak_db1 > minDB) {
var width1 = Math.round(bar_width * (peak_db1 - minDB) / dBrange);
gr.FillRectangle(bar_pad_left, bar_pad_top + (bar_height * 0) + 0, width1, bar_height - 3, brush_str);
}
}
if (Peak_level2 > 0) {
var peak_db2 = clamp(to_db(Peak_level2), minDB, maxDB);
if (peak_db2 > minDB) {
var width2 = Math.round(bar_width * (peak_db2 - minDB) / dBrange);
gr.FillRectangle(bar_pad_left, bar_pad_top + (bar_height * 3) + 3, width2, bar_height - 3, brush_str);
}
}
if (RMS_level1 > 0) {
var rms_db1 = clamp(to_db(RMS_level1) + rms_db_offset, minDB, maxDB);
var blocks1 = Math.round(block_count * (rms_db1 - minDB) / dBrange);
for (var i = 0; i < blocks1; ++i) {
gr.FillRectangle(bar_pad_left + (i * block_width), bar_pad_top + (bar_height * 1) + 1, block_width - block_pad, bar_height - 4, get_colour_for_db(i * dBrange / block_count));
}
}
if (RMS_level2 > 0) {
var rms_db2 = clamp(to_db(RMS_level2) + rms_db_offset, minDB, maxDB);
var blocks2 = Math.round(block_count * (rms_db2 - minDB) / dBrange);
for (var i = 0; i < blocks2; ++i) {
gr.FillRectangle(bar_pad_left + (i * block_width), bar_pad_top + (bar_height * 2) + 1, block_width - block_pad, bar_height - 2, get_colour_for_db(i * dBrange / block_count));
}
}
}
// fb2k callbacks
function on_playback_new_track(handle) {
start_timer();
}
function on_playback_stop(reason) {
if (reason != 2) stop_timer(); // not starting another track
clear_graph();
}
function on_playback_pause(state) {
state ? stop_timer() : start_timer();
}
function init() {
update_colours();
update_font();
if (fb.IsPlaying) start_timer();
}
init();
(https://i.imgur.com/Nm0TKUx.png)
(https://i.imgur.com/tthmvfS.jpeg)
I was looking to replicate the spotify now playing full screen. So I just did an awful attempt to the images script and text display + buttons script.
This lets us load artist images from Last.fm while still giving us the flexibility of the text display.
I'm not sure how to resize the album art from the text script, so I've just loaded a new album art on top of the text.
This layout could be useful for those who like dynamic backgrounds or for those who want to set it up with Flowin for now playing full screen.
Since I don't know how to override the properties, so I had to do the steps below manually to get the display like above.
Right click > Uncheck album art background
Right click > Text alignment (horizontal) >Left
Right click > Text alignment (vertical) >Bottom
Right click > Margin...> 140
Shift + Right click > Last.fm artist art
Shift + Right click > Crop (Focus on top) (Optional)
// ==PREPROCESSOR==
// @name "Images"
// @author "marc2003"
// @import "%fb2k_component_path%helpers.txt"
// @import "%fb2k_component_path%samples\js\lodash.min.js"
// @import "%fb2k_component_path%samples\js\common.js"
// @import "%fb2k_component_path%samples\js\panel.js"
// @import "%fb2k_component_path%samples\js\images.js"
// @import "%fb2k_component_path%samples\js\albumart.js"
// @import "%fb2k_component_path%samples\js\text_display.js"
// @import "%fb2k_component_path%samples\js\seekbar.js"
// ==/PREPROCESSOR==
var panel = new _panel({ custom_background : true });
var images = new _images();
///
var albumart = new _albumart(0, 0, 0, 0);
var text = new _text_display(LM, 0, 0, 0);
var seekbar = new _seekbar(0, 0, 0, 0);
var colours = {
slider_background : RGB(160, 160, 160),
white : RGB(255, 255, 255),
contrast : RGB(196, 30, 35),
};
var tfo = {
playback_time : fb.TitleFormat('[%playback_time%]'),
length : fb.TitleFormat('$if2(%length%,LIVE)'),
};
var font = CreateFontString('Segoe UI', 12);
var buttons = new _buttons();
var bs = _scale(24);
var bottom_y = 0;
buttons.update = function () {
var x = (panel.w - (bs * 7)) / 2
var y = seekbar.y + _scale(12);
this.buttons.stop = new _button(x, y, bs, bs, { char : chars.stop, colour: fb.StopAfterCurrent ? colours.contrast : colours.white}, null, function () { fb.Stop(); }, 'Stop');
this.buttons.previous = new _button(x + bs, y, bs, bs, { char : chars.prev, colour:colours.white }, null, function () { fb.Prev(); }, 'Previous');
this.buttons.play = new _button(x + (bs * 2), y, bs, bs, { char : !fb.IsPlaying || fb.IsPaused ? chars.play : chars.pause, colour:colours.white}, null, function () { fb.PlayOrPause(); }, !fb.IsPlaying || fb.IsPaused ? 'Play' : 'Pause');
this.buttons.next = new _button(x + (bs * 3), y, bs, bs, { char : chars.next, colour:colours.white }, null, function () { fb.Next(); }, 'Next');
this.buttons.search = new _button(x + (bs * 5), y, bs, bs, { char : chars.search, colour:colours.white }, null, function () { fb.RunMainMenuCommand('Library/Search'); }, 'Library Search');
this.buttons.preferences = new _button(x + (bs * 6), y, bs, bs, { char : chars.preferences, colour:colours.white}, null, function () { fb.ShowPreferences(); }, 'Preferences');
}
///
panel.item_focus_change();
function on_colours_changed() {
panel.colours_changed();
text.refresh(true);
window.Repaint();
}
function on_font_changed() {
panel.font_changed();
text.refresh(true);
window.Repaint();
}
function on_http_request_done(task_id, success, response_text) {
images.http_request_done(task_id, success, response_text);
}
function on_item_focus_change() {
if (panel.selection.value == 0 && fb.IsPlaying) return;
panel.item_focus_change();
}
function on_key_down(k) {
images.key_down(k);
}
function on_metadb_changed(handles, fromhook) {
if (fromhook) return;
images.metadb_changed();
if (!fromhook) {
albumart.metadb_changed();
}
text.metadb_changed();
}
function on_mouse_move(x, y) {
if (albumart.move(x, y)) {
return;
} else if (seekbar.move(x, y)) {
return;
} else if (buttons.move(x, y)) {
return;
}
text.move(x, y);
images.move(x, y);
}
function on_mouse_lbtn_dblclk(x, y) {
images.lbtn_dblclk(x, y);
}
function on_mouse_lbtn_down(x, y) {
seekbar.lbtn_down(x, y);
}
function on_mouse_lbtn_up(x, y) {
if (seekbar.lbtn_up(x, y)) {
return;
} else if (buttons.lbtn_up(x, y)) {
return;
}
text.lbtn_up(x, y);
}
function on_mouse_leave() {
buttons.leave();
}
function on_mouse_rbtn_up(x, y) {
if (buttons.buttons.stop.containsXY(x, y)) {
fb.StopAfterCurrent = !fb.StopAfterCurrent;
return true;
}
if (utils.IsKeyPressed(VK_SHIFT)) {
return panel.rbtn_up(x, y, images);
} else {
return panel.rbtn_up(x, y, text);
}
}
function on_mouse_wheel(s) {
if (albumart.wheel(s)) {
return;
} else if (seekbar.wheel(s)) {
return;
}
text.wheel(s);
images.wheel(s);
}
function on_paint(gr) {
panel.paint(gr);
images.paint(gr);
_drawOverlay(gr, 0, 0, panel.w, panel.h, 100);
text.paint(gr);
_drawImage(gr, albumart.img, 20, panel.h - 340, 150, 150, image.crop);
buttons.paint(gr);
gr.FillRoundedRectangle(seekbar.x, seekbar.y, seekbar.w, seekbar.h, _scale(2), _scale(2), colours.slider_background);
if (fb.IsPlaying) {
var time_width = seekbar.x - _scale(12);
gr.WriteText(tfo.playback_time.Eval(), font, colours.white, 0, bottom_y, time_width, _scale(12), 1, 2);
gr.WriteText(tfo.length.Eval(), font, colours.white, seekbar.x + seekbar.w + _scale(12), bottom_y, time_width, _scale(12), 0, 2);
if (fb.PlaybackLength > 0) {
gr.FillEllipse(seekbar.x + seekbar.pos(), seekbar.y + _scale(3), _scale(6), _scale(6), colours.white);
}
}
}
function on_playback_order_changed() {
buttons.update();
window.Repaint();
}
function on_playback_dynamic_info_track(type) {
if (type == 0) {
images.playback_new_track();
text.metadb_changed() ;
} else if (type == 1) albumart.metadb_changed();
}
function on_playback_new_track() {
panel.item_focus_change();
images.playback_new_track();
}
function on_playback_stop(reason) {
if (reason != 2) {
panel.item_focus_change();
}
}
function on_playback_pause() {
text.refresh();
buttons.update();
window.Repaint();
}
function on_playback_starting() {
buttons.update();
window.Repaint();
}
function on_playback_stop(reason) {
if (reason != 2) {
panel.item_focus_change();
}
buttons.update();
window.Repaint();
}
function on_playback_time() {
images.playback_time();
//
text.playback_time();
window.RepaintRect(0, bottom_y, panel.w, panel.h - bottom_y);
}
function on_playback_seek() {
seekbar.playback_seek();
}
function on_playlist_items_added() {
text.refresh();
}
function on_playlist_items_removed() {
text.refresh();
}
function on_playlist_items_reordered() {
text.refresh();
}
function on_playlist_stop_after_current_changed() {
buttons.update();
window.Repaint();
}
function on_playlist_switch() {
on_item_focus_change();
}
function on_playlists_changed() {
text.refresh();
}
function on_size() {
panel.size();
images.w = panel.w;
images.h = panel.h;
//
text.size();
seekbar.x = _scale(60);
seekbar.y = panel.h - _scale(120);
seekbar.w = panel.w - (seekbar.x * 2);
seekbar.h = _scale(6);
bottom_y = seekbar.y - _scale(4);
buttons.update();
}
Playing around with image script and text display with svg buttons.
(https://i.imgur.com/ApQsSdC.png)
Playing around with image script and text display with svg buttons.
(https://i.imgur.com/ApQsSdC.png)
Can I send a script?
Can I send a script?
Instruction:
1.
Extract the images.zip to your foobar2000 configuration folder or just Win + R and paste this
%appdata%\foobar2000-v2\
2.
Right click > Uncheck album art background
Right click > Text alignment (horizontal) >Right
Right click > Text alignment (vertical) >Bottom
Right click > Margin...> 40
Shift + Right click > Last.fm artist art
Shift + Right click > Crop (Focus on top) (Optional)
// ==PREPROCESSOR==
// @name "Images + Text Display + Album Art + Custom SVG and PNG Buttons"
// @author "marc2003"
// @import "%fb2k_component_path%helpers.txt"
// @import "%fb2k_component_path%samples\js\lodash.min.js"
// @import "%fb2k_component_path%samples\js\common.js"
// @import "%fb2k_component_path%samples\js\panel.js"
// @import "%fb2k_component_path%samples\js\images.js"
// @import "%fb2k_component_path%samples\js\albumart.js"
// @import "%fb2k_component_path%samples\js\text_display.js"
// ==/PREPROCESSOR==
var panel = new _panel({ custom_background : true });
var images = new _images();
var albumart = new _albumart(0, 0, 0, 0);
var text = new _text_display(LM, 0, 0, 0);
//.svg files
var folder = utils.LoadSVG(fb.ProfilePath + 'images\\folder.svg');
var youtube = utils.LoadSVG(fb.ProfilePath + 'images\\youtube.svg');
var spotify = utils.LoadSVG(fb.ProfilePath + 'images\\spotify.svg');
var wikipedia = utils.LoadSVG(fb.ProfilePath + 'images\\wikipedia.svg');
var lastfm = utils.LoadSVG(fb.ProfilePath + 'images\\lastfm.svg');
var search = utils.LoadSVG(fb.ProfilePath + 'images\\search.svg');
var settings = utils.LoadSVG(fb.ProfilePath + 'images\\settings.svg');
//.png files
var guitar = utils.LoadImage(fb.ProfilePath + 'images\\guitar.png');
var tfo = {
artist: fb.TitleFormat('%artist%'),
title: fb.TitleFormat('%title%'),
playback_time : fb.TitleFormat('[%playback_time%]'),
length : fb.TitleFormat('$if2(%length%,LIVE)'),
}
var colours = {
slider_background : RGB(160, 160, 160),
white : RGB(255, 255, 255),
contrast : RGB(196, 30, 35),
};
var font = CreateFontString('Segoe UI', 12);
var buttons = new _buttons();
var bs = _scale(24);
var mg = _scale(4);
var bottom_y = 0;
buttons.update = function () {
var x = (panel.w - (bs * 9)) / 2
var y = bottom_y;
var handle_list = fb.GetFocusItem();
this.buttons.folder = new _button(x + (bs * 5 + mg * 5), y, bs, bs, { img : folder }, null, function () { _explorer(handle_list.path); }, 'folder');
this.buttons.youtube = new _button(x, y, bs, bs, { img : youtube }, null, function () { utils.Run('http://www.youtube.com/results?search_query=' + encodeURIComponent(tfo.artist.Eval() + " " + tfo.title.Eval())); }, 'youtube');
this.buttons.spotify = new _button(x + bs + mg, y, bs, bs, { img : spotify}, null, function () { utils.Run('https://open.spotify.com/search/' + encodeURIComponent(tfo.artist.Eval() + " " + tfo.title.Eval())); }, 'spotify');
this.buttons.wikipedia = new _button(x + (bs * 2 + mg * 2), y, bs, bs, { img : wikipedia }, null, function () { utils.Run('http://en.wikipedia.org/wiki/Special:Search?search=' + encodeURIComponent(tfo.artist.Eval())); }, 'wikipedia');
this.buttons.lastfm = new _button(x + (bs * 3 + mg * 3), y, bs, bs, { img : lastfm }, null, function () { utils.Run('https://www.last.fm/search?q=' + encodeURIComponent(tfo.artist.Eval())); }, 'lastfm');
this.buttons.guitar = new _button(x + (bs * 4 + mg * 4), y, bs, bs, { img : guitar }, null, function () { utils.Run('https://www.ultimate-guitar.com/search.php?search_type=title&value=' + encodeURIComponent(tfo.artist.Eval() + " " + tfo.title.Eval())); }, 'Ultimate Guitar');
this.buttons.search = new _button(x + (bs * 6 + mg * 6), y, bs, bs, { img : search }, null, function () { fb.ShowLibrarySearchUI('artist IS ' + tfo.artist.Eval()); }, 'Search');
this.buttons.preferences = new _button(x + (bs * 7 + mg * 7), y, bs, bs, { img : settings}, null, function () { fb.ShowPreferences(); }, 'Preferences');
}
panel.item_focus_change();
function on_colours_changed() {
panel.colours_changed();
text.refresh(true);
window.Repaint();
}
function on_font_changed() {
panel.font_changed();
text.refresh(true);
window.Repaint();
}
function on_http_request_done(task_id, success, response_text) {
images.http_request_done(task_id, success, response_text);
}
function on_item_focus_change() {
if (panel.selection.value == 0 && fb.IsPlaying) return;
panel.item_focus_change();
}
function on_key_down(k) {
images.key_down(k);
}
function on_metadb_changed(handles, fromhook) {
if (fromhook) return;
images.metadb_changed();
if (!fromhook) {
albumart.metadb_changed();
}
text.metadb_changed();
}
function on_mouse_move(x, y) {
text.move(x, y);
images.move(x, y);
buttons.move(x, y);
_.forEach(buttons.buttons, function (button) {
if (button.containsXY(x, y)) {
window.SetCursor(IDC_HAND);
return;
}
});
}
function on_mouse_lbtn_dblclk(x, y) {
images.lbtn_dblclk(x, y);
}
function on_mouse_lbtn_up(x, y) {
if (buttons.lbtn_up(x, y)) {
return;
}
// text.lbtn_up(x, y);
}
function on_mouse_leave() {
buttons.leave();
}
function on_mouse_rbtn_up(x, y) {
if (utils.IsKeyPressed(VK_SHIFT)) {
return panel.rbtn_up(x, y, images);
} else {
return panel.rbtn_up(x, y, text);
}
}
function on_mouse_wheel(s) {
text.wheel(s);
images.wheel(s);
}
function on_paint(gr) {
panel.paint(gr);
images.paint(gr);
//_drawOverlay(gr, 0, panel.h - 190, panel.w, panel.h, 100);
_drawOverlay(gr, 0, 0, panel.w, panel.h, 100);
text.paint(gr);
_drawImage(gr, albumart.img, 20, panel.h - _scale(130), 100, 100, image.crop);
buttons.paint(gr);
}
function on_playback_order_changed() {
buttons.update();
window.Repaint();
}
function on_playback_dynamic_info_track(type) {
if (type == 0) {
images.playback_new_track();
text.metadb_changed() ;
} else if (type == 1) albumart.metadb_changed();
}
function on_playback_new_track() {
panel.item_focus_change();
images.playback_new_track();
}
function on_playback_stop(reason) {
if (reason != 2) {
panel.item_focus_change();
}
}
function on_playback_pause() {
text.refresh();
buttons.update();
window.Repaint();
}
function on_playback_starting() {
buttons.update();
window.Repaint();
}
function on_playback_stop(reason) {
if (reason != 2) {
panel.item_focus_change();
}
buttons.update();
window.Repaint();
}
function on_playback_time() {
images.playback_time();
text.playback_time();
window.RepaintRect(0, bottom_y, panel.w, panel.h - bottom_y);
}
function on_playlist_items_added() {
text.refresh();
}
function on_playlist_items_removed() {
text.refresh();
}
function on_playlist_items_reordered() {
text.refresh();
}
function on_playlist_stop_after_current_changed() {
buttons.update();
window.Repaint();
}
function on_playlist_switch() {
on_item_focus_change();
}
function on_playlists_changed() {
text.refresh();
}
function on_size() {
panel.size();
images.w = panel.w;
images.h = panel.h;
text.size();
bottom_y = panel.h - _scale(36);
buttons.update();
}
My old script "Peak meter" for WSH. Maybe useful for someone.
// ==PREPROCESSOR==
// @name "Peak meter"
// @author "kgena_ua"
// @version "06082017"
// ==/PREPROCESSOR==
function RGB(r,g,b) { return (0xff000000|(r<<16)|(g<<8)|(b)); }
var font = gdi.Font("Arial",9,1);
var font2 = gdi.Font("Arial",11,0);
DT_CENTER = 0x00000001;
DT_VCENTER = 0x00000004;
DT_SINGLELINE = 0x00000020;
DT_WORD_ELLIPSIS = 0x00040000;
var ww = window.Width, wh = window.Height;
var on_mouse = false;
var color = [];
var combinedColor1 = [];
var combinedColor2 = [];
var separator;
var offset, w, offset_l, w_l;
var pos_x = 0, pos_y = 0;;
var VUMOffset_t, t_height, t_width;
var wheel = false;
var tooltip_timer;
ColorTypeCUI = {
text: 0,
selection_text: 1,
inactive_selection_text: 2,
background: 3,
selection_background: 4,
inactive_selection_background: 5,
active_item_frame: 6
}
function get_color(){
bgcolor = window.GetColorCUI(ColorTypeCUI.background);
c1 = window.GetColorCUI(ColorTypeCUI.text);
c2 = window.GetColorCUI(ColorTypeCUI.inactive_selection_text);
c3 = window.GetColorCUI(ColorTypeCUI.inactive_selection_background);
color1 = [ c3, c1 ];
color2 = [ c2, c3 ];
window.Repaint();
}
get_color();
function on_colors_changed(){
get_color();
}
var dll;
var is_dll = utils.CheckComponent("\\user-components\\foo_vis_vumeter\\foo_vis_vumeter");
if (is_dll) {dll = false} else {dll = true};
if (dll) {VUMeter = new ActiveXObject("VUMeter")};
if (dll) {VUMeter.RegisterWindow(window.ID)}; // do not use for transparent mode
function ToDB(Level){
return Math.round(2000*Math.log(Level)/Math.LN10)/100;
}
var db = [-25,-22.5,-20,-17.5,-15,-12.5,-10,-7.5,-5,-4.5,-4,-3.5,-3,-2.5,-2,-1.5,-1,-0.5,0,0.5,1,1.5,2,2.5,3,3.5,4];
var db_l = [-92.5,-90,-87.5,-85,-82.5,-80,-77.5,-75,-72.5,-70,-67.5,-65,-62.5,-60,-57.5,-55,-52.5,-50,-47.5,-45,-42.5,-40,-37.5,-35,-32.5,-30,-27.5];
for (var i = 0; i <= db.length; i++) {
if (db[i] == 0) {separator = i};
}
var points = db.length;
var s1 = separator;
var s2 = points - s1;
var points_l = db_l.length;
for(var j = 0; j < s1; j++) {
combinedColor1.push(combineColors(color1[0], color1[1], j / s1));
}
for(var j = 0; j < s2; j++) {
combinedColor2.push(combineColors(color2[0], color2[1], j / s2));
}
color = combinedColor1.concat(combinedColor2);
var col = 0;
var ytext = 5;
var h = 2;
var hM = 5;
var yL = ytext + 15;
var yLM = yL + h + 4;
var hM_l = 1;
var yLM_l = yLM + hM + 4;
var yRM_l = yLM_l + hM_l + 1;
var yRM = yRM_l + hM_l + 4;
var yR = yRM + hM + 4;
var wL = 0, wR = 0;
var xLanim = 0, xRanim = 0;
var xL = 0, xR = 0;
var xLManim = 0, xRManim = 0;
var xLM = 0, xRM = 0;
var kLM = 0, kRM = 0;
var kLM2 = 0, kRM2 = 0;
var xLManim2 = 0, xRManim2 = 0;
var kL = 0, kR = 0;
var wLanim = 0, wRanim = 0;
var oldwL = 0, oldwR = 0;
function on_paint(gr) {
gr.FillSolidRect(0, 0, ww, wh, bgcolor);
if (panel_on && dll) {
L = VUMeter.LeftLevel;
R = VUMeter.RightLevel;
LM = VUMeter.LeftPeak;
RM = VUMeter.RightPeak;
}
if (panel_on && fb.IsPlaying && dll) {
for (var i = 0; i <= points_l; i++) {
if (ToDB(LM) > db_l[i]) gr.FillSolidRect(col + i * offset_l, yLM_l, w_l, hM_l, color[0]);
if (ToDB(RM) > db_l[i]) gr.FillSolidRect(col + i * offset_l, yRM_l, w_l, hM_l, color[0]);
}
for (var i = 0; i <= points; i++) {
if ((ToDB(L) > db[i] && ToDB(L) < db[i+1])) {wL = i * offset + offset / Math.abs(db[i + 1]-db[i]) * Math.abs(ToDB(L) - db[i]) }
if (ToDB(L) > db[i]) gr.FillSolidRect(col, yL, wL, h, color[1]);
if ((ToDB(R) > db[i] && ToDB(R) < db[i+1])) {wR = i * offset + offset / Math.abs(db[i + 1]-db[i]) * Math.abs(ToDB(R) - db[i]) }
if (ToDB(R) > db[i]) gr.FillSolidRect(col, yR, wR, h, color[1]);
if (xLanim <= wL) {xLanim = wL; kL = 0; wLanim = wL - oldwL < 1 ? wLanim : wL - oldwL + 10} else {oldwL = wL};
if (ToDB(L) > db[i]) gr.FillSolidRect(col + xLanim + 2, yL, wLanim <= 0 ? 2 : wLanim, h, color[1]);
if (xRanim <= wR) {xRanim = wR; kR = 0; wRanim = wR - oldwR < 1 ? wRanim : wR - oldwR + 10} else {oldwR = wR};
if (ToDB(R) > db[i]) gr.FillSolidRect(col + xRanim + 2, yR, wRanim <= 0 ? 2 : wRanim, h, color[1]);
var overL = col + xLanim + 2 + wLanim - ww - 10;
if (overL > 0) gr.FillSolidRect(ww - overL, yL - h - 1, ww - 10, h, color[10]);
var overR = col + xRanim + 2 + wRanim - ww - 10;
if (overR > 0) gr.FillSolidRect(ww - overR, yR + h + 1, ww - 10, h, color[10]);
if (ToDB(LM) > db[i]) gr.FillSolidRect(col + i * offset, yLM, w, hM, color[i]);
if (ToDB(RM) > db[i]) gr.FillSolidRect(col + i * offset, yRM, w, hM, color[i]);
if (ToDB(LM) > db[i] && ToDB(LM) < db[i+1]) {xLM = i * offset};
if (xLManim <= xLM) {xLManim = xLM; xLManim2 = xLM; kLM = 0; kLM2 = 0};
if (ToDB(LM) > db[i]) gr.FillSolidRect(col + xLManim + offset, yLM, w * 0.8, hM , color[Math.round(xLManim/offset)]);
if (ToDB(RM) > db[i] && ToDB(RM) < db[i+1]) {xRM = i * offset};
if (xRManim <= xRM) {xRManim = xRM; xRManim2 = xRM; kRM = 0; kRM2 = 0};
if (ToDB(RM) > db[i]) gr.FillSolidRect(col + xRManim + offset, yRM, w * 0.8, hM, color[Math.round(xRManim/offset)]);
if (ToDB(LM) > db[i]) gr.FillSolidRect(col + xLManim2 + offset + w, yLM, w * 0.3, hM, color[Math.round(xLManim/offset)]);
if (ToDB(RM) > db[i]) gr.FillSolidRect(col + xRManim2 + offset + w, yRM, w * 0.3, hM, color[Math.round(xRManim/offset)]);
}
anim();
}
for (var i = 0; i <= points; i++) {
var text_w = gr.CalcTextWidth(db[i], font);
if (i > 2) gr.GdiDrawText( db[i]% 2 == 0 ? db[i] : "" , font, color1[0], col + offset * i - text_w / 2, ytext, ww, wh);
}
gr.GdiDrawText( "db", font, color1[0], col, ytext, ww, wh);
VUMOffset_t = Math.round(VUMeter.Offset) + " db";
t_height = gr.CalcTextHeight(VUMOffset_t, font2) + 2;
t_width = gr.CalcTextWidth(VUMOffset_t, font2) + 10;
wheel && gr.FillSolidRect(pos_x - t_width, pos_y - t_height + 0, t_width, t_height, bgcolor);
wheel && gr.GdiDrawText(VUMOffset_t, font2, color2[0], pos_x - t_width, pos_y - t_height + 0, t_width, t_height, DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_WORD_ELLIPSIS );
}
function anim() {
kLM = kLM + Math.pow(0.3, 2);
kRM = kRM + Math.pow(0.3, 2);
xLManim = xLManim - kLM;
xRManim = xRManim - kRM;
kLM2 = kLM2 + Math.pow(1.1, 2);
kRM2 = kRM2 + Math.pow(1.1, 2);
xLManim2 = xLManim2 + kLM2;
xRManim2 = xRManim2 + kRM2;
kL = kL + Math.pow(0.3, 2);
kR = kR + Math.pow(0.3, 2);
xLanim = xLanim - kL;
xRanim = xRanim - kR;
wLanim = wLanim - kL * 2; //2
wRanim = wRanim - kR * 2;
}
function on_size() {
ww = window.Width;
wh = window.Height;
offset = (ww - col) / points;
w = offset - 1;
offset_l = (ww - col) / points_l;
w_l = offset_l - 1;
}
function on_mouse_move(x,y) {
on_mouse = true;
pos_x = x <= t_width ? col + t_width : col + x;
pos_y = y <= t_height ? t_height : y;
window.SetCursor(32649);
window.Repaint();
}
function on_mouse_leave() {
on_mouse = false;
window.SetCursor(32512);
window.Repaint();
}
function on_mouse_wheel(step) {
wheel = true;
VUMeter.Offset = VUMeter.Offset + step;
window.Repaint();
tooltip_timer && window.ClearTimeout(tooltip_timer);
tooltip_timer = window.SetTimeout(function() {
wheel = false;
tooltip_timer && window.ClearTimeout(tooltip_timer);
tooltip_timer = false;
}, 2000);
}
function combineColors(c1, c2, f){ // When fraction is 0, result is 100% color1, when f is 1, result is 100% color2.
var c1 = toRGB(c1);
var c2 = toRGB(c2);
var r = Math.round(c1[0] + f * (c2[0] - c1[0]));
var g = Math.round(c1[1] + f * (c2[1] - c1[1]));
var b = Math.round(c1[2] + f * (c2[2] - c1[2]));
return (0xff000000 | (r << 16) | (g << 8) | (b));
}
function toRGB(d){ // convert back to RGB values
var d = d-0xff000000;
var r = d >> 16;
var g = d >> 8 & 0xFF;
var b = d & 0xFF;
return [r,g,b];
}
panel_on = true;
function on_notify_data(name, info) {
if (name == "panel vis") {
if (info == "Peak meter"){
panel_on = true;
} else {
panel_on = false;
}
}
}
Thanks kgena_ua, will give this a workout tomorrow! Air Ken, I hope you also mod it up and we'll see what we come up with ;)
Hello marc2k3, I wanted to know if there is a callback which gets triggered when the last item in a playlist gets played completely and then starts from first?
I am trying to execute a command so that when the final item in the playlist is finished the next item in the playlist starts from 0/1 (whatever is the beginning index of an item) so instead of stopping the playlist execute a command in between.
Currently,
plman.GetPlaylistItemCount(plman.FindPlaylist("LRP + LPC"))
shows the total items in a playlist. Using this I suppose there could be a way to track/increment the current item which is being played in the playlist? So basically whenever a command gets executed (suppose refresh playlist or whatever) the plman.GetPlaylistItemCount will run and store it in a variable.
Hi All,
I have just created a script to add 'value' to foo_youtube component by providing it with a song list.
//------------ CREDIT -----------------//
Credit goes to:
- @Wil-B (https://github.com/Wil-B) for the fantastic 'Find-and-Play' app, along with the 'Biography' and 'Library-Tree' scripts based on Spider Monkey Panel. The 'Find-and-Play' inspired me to explore [YouTube searching]. However I've tried, @Wil-B's scripts still set the benchmark.
- @Marc2003 (https://github.com/jscript-panel) for the excellent [JScript Panel 3] component. @Marc2003 actively updates this component with new features, bug fixes, and beautiful, tidy sample scripts.
# This script uses some API (web service) keys from @Wil-B and @marc2003 for trial purposes. Even though these keys are bundled with their public scripts, we should show and treat them with respect.
//---------- ABOUT this JSP3_foo_youtube_addon script ----------------------//
@1_ Sole Purpose:
- YouTube search for songs or any information.
- For others to improve and tailor to their needs (as usual, I've left many comments for easy reference).
@2_ Prerequisites:
- foo_youtube component: https://www.foobar2000.org/components/view/foo_youtube; https://fy.3dyd.com/ to play YouTube videos.
- and/or yt-dlp.exe (for YouTube search): Get it from here [https://github.com/yt-dlp/yt-dlp] if you want to search YouTube using yt-dlp.exe.
(yt_dlp.exe located under this path : {fb2k_Profile_Path}\skins\external_helper\yt-dlp.exe).
@3_ How It Works:
- Users need to feed foo_youtube with a structured list of songs that is friendly with the [foo_youtube] component. This builds a playlist from track locations (similar to foo_tags).
- Where can we get the song list?
+ Manually: Users input text to search directly on youtube.com (not limited to audio tracks).
+ Still manually: Users input an artist name (1), last.fm verifies this name and returns that artist's song list from its database (2), and then youtube.com searches for this data (artist + song title).
+ Automatically: Get the list from somewhere.
- Possible online 'databases':
* MusicBrainz (musicbrainz.org)
* lastFM (last.fm, ws.audioscrobbler.com): We prefer this database as last.fm seems to be YouTube's ally.
> Top trending tracks
> Artist's top tracks classified by locale, years, genre, etc.
* Official Charts (officialcharts.com)
@4_ How We Interact with This Script:
- Context menu via right-click.
@5_ Why YouTube Music:
- We may not get 'high-res' audio tracks from youtube.com, BUT:
- It's a huge store for audio tracks, especially the [YouTube Music] streaming platform.
- Videos often contain audio tracks.
- Some/many audio tracks were/are uploaded by artists, 'semi-artists,' and are only available on this platform (especially single versions).
- Trending.
. . .
Let's dive in!
@6_ Limitations:
- YouTube searching may return irrelevant results, such as other artists' audio tracks, instead of the ones we're looking for.
How to improve:
+ Firstly, let YouTube return an audio track list, and then we search for the 'best' or good match based on our judgment (this will slow things down).
+ Alternatively, we can grab only the first/top audio track from the pool list, hoping that YouTuBe (Google) returns the best match ranked at the top (faster approach).
- User interface/UI: Not very user-friendly.
- Bugs: this is just departure , version [1.0.0 QM] 22Aug2024.
Wish you all the best.
ilovefb2k
Hi @
All ,
Please find the following:
1. _
'JSP3 foo_youtube_addon' script attached hereafter. This script reflects Air KEN’s feedback {https://hydrogenaud.io/index.php/topic,104379.msg1050940.html#msg1050940}
Change log:
- 23Aug24: YouTube searching.
- 20Sep24:
+ YouTube channel management
2. _
‘JSP3 Now playing 64bit (text display)’ Change log:
. . .
- 20Sep24:
+ YouTube download (please pay attention to YouTube clip IP ): audio only, video best by size.
+ Favorite list (aka fb2k playlist): maintain a favorite song/clip list.
note: 1.
youtube download is based on the yt_dlp.exe , ffmpeg.exe - yt_dlp path: {fb.ProfilePath} \skins\external_helper\yt-dlp.exe
- ffmpeg path : {fb.ProfilePath} \skins\external_helper\ffmpeg.exe
2.
about yt-dlp, ffmpeg.
_ yt-dlp : is a feature-rich command-line audio/video downloader with support for thousands of sites [ https://github.com/yt-dlp/yt-dlp/blob/master/supportedsites.md]. The project is a fork of youtube-dl [https://github.com/ytdl-org/youtube-dl] based on the now inactive youtube-dlc [https://github.com/blackjack4494/yt-dlc]
- ffmpeg: information as @marc2003's sample > https://jscript-panel.github.io/gallery/spectrogram-seekbar/.
Wish you all a nice weekend. @Ilovefb2k
Hi @All,
The weekend is coming, FriYAY!
Let’s have some fun with text, color, and music: JSP3_playbacktime_dancing. I combined scripts from @TomPro (text, color), @Case (VU Meter), and @Marc2003 (font): the script ‘draws’ playback time.
- Text, color: any color we can think of. {@TomPro's script: https://foobar-users.de/index.php?topic=2000.165 }
- VU Meter: smooth, bar, or galaxy.
- WYSIWYG font: we can select a font based on that ‘true’ rendering.
Wish you all a nice weekend.
@Ilovefb2k
@ilovefb2k
Thanks.
ilovefb2k"s Script folder (skin folder):
https://mega.nz/file/BaEDDbDB#kgnnKjLclWcUVTFZpz9LcPdCx9P8dtnzloBSZJlUh7Y
'JSP3 foo_youtube_addon'
(https://i.imgur.com/u0QchIm.png)
‘JSP3 Now playing 64bit (text display)’
(https://i.imgur.com/mI7s1fX.png)
I wanted to know if there is a callback which gets triggered when the last item in a playlist gets played completely and then starts from first?
I am trying to execute a command so that when the final item in the playlist is finished the next item in the playlist starts from 0/1 (whatever is the beginning index of an item) so instead of stopping the playlist execute a command in between.
Currently, plman.GetPlaylistItemCount(plman.FindPlaylist("LRP + LPC"))
shows the total items in a playlist. Using this I suppose there could be a way to track/increment the current item which is being played in the playlist? So basically whenever a command gets executed (suppose refresh playlist or whatever) the plman.GetPlaylistItemCount will run and store it in a variable.
Hello,
@marc2k3 any idea if this would be possible?
I'm using JSP3 "text display" sample.
In the "custom text" configuration, what do I need to do to display "[" and "]" characters?
Thank you.
what do I need to do to display "[" and "]" characters?
custom chars always in single hyphens '['
hyphen -
apostrophe '
hyphen -
apostrophe '
thanks, fingers faster than brain... do as I do, not as I say
what do I need to do to display "[" and "]" characters?
custom chars always in single hyphens '['
Cool, thanks man! It works!!
Hello!
First of all, i want to thank you
@marc2k3 for this component!
And i have a small question: is there a way to draw polygons and if not, do you plan on implementing it?
Hey,
I'm trying to style the last.fm bio + images sample snippet, but I do not know where to start. None of the sample snippets have any documentation/comments to help me grasp what each function is doing. There doesn't seem to be any CSS involved either, just pure javascript?
So, how can I style this (not modify the actual functions, just the outlook of the panel)?
What I want to do: Change the font, remove the image backgrounds, have same colors as other UI elements and otherwise try to make it as "native" looking as possible and bare-bones rather than "fancy".
It would already help if anyone could point out to me where these styling things are in the code.
Hello!
First of all, i want to thank you @marc2k3 for this component!
And i have a small question: is there a way to draw polygons and if not, do you plan on implementing it?
There is a way to draw a polygons. You have to use SVG :
https://jscript-panel.github.io/docs/namespaces/utils/#utilsloadsvgpath_or_xml-max_width
In the given example a file is used but you can use xml as a string :
https://www.w3schools.com/graphics/svg_polygon.asp
Best
There is a way to draw a polygons. You have to use SVG :
https://jscript-panel.github.io/docs/namespaces/utils/#utilsloadsvgpath_or_xml-max_width
In the given example a file is used but you can use xml as a string :
https://www.w3schools.com/graphics/svg_polygon.asp
I guess this will suffice!
Previously i was loading local png's, thank you (:
Is it possible to update the tagging properties like $artist$ or $album$ inside jsp3 ?
To fill the field inside an input box ? Thanks ....
would like to make a suggestion for the "Properties + Other Info" sample item. When you click on this item, it will create a new library. It would be really nice if you could edit the tag.
can you add text display with buttons and seekbar as my foot samples has got so very small and I don't know how to increase it
here what I see very small font now I am sure it used to be larger than that but me and the mouse don't get on so how do i increase the text size
how do i increase the text size
Ctrl+ Mouse Scroll Up/Down
okay thank you that worked :) now to add buttons heh now I can see the text
i tried but cannot add buttons to text display :'(
any body know what the script would be to add text display and buttons in jscipt panel please
many thanks in advance
Okay, this has been driving me crazy for a few days now:
// ==PREPROCESSOR==
// @name "Test"
// ==/PREPROCESSOR==
function RGB(r, g, b) {return (0xff000000 | (r << 16) | (g << 8) | (b));}
Button = {State:0};
ButtonColors = {0:RGB(0, 0, 0), 1: RGB(155, 155, 155), 2: RGB(255, 255, 255)};
function on_paint(gr) {gr.FillRectangle(0, 0, window.Width, window.Height, ButtonColors[Button.State]);}
function on_mouse_leave() {Button.State = 0; window.Repaint();}
function on_mouse_move(x, y) {Button.State = 1; window.Repaint();}
function on_mouse_lbtn_down(x, y) {Button.State = 2; window.Repaint();}
function on_mouse_lbtn_dblclk(x, y, mask) {on_mouse_lbtn_down(x, y)}
function on_mouse_lbtn_down(x, y) {Button.State = 2; window.Repaint();}
function on_mouse_lbtn_up(x, y) {Button.State = 1; window.Repaint();}
function on_focus(IsFocused) {if (!IsFocused) {Button.State = 0;}; window.Repaint();};
in my mind,
function on_mouse_lbtn_dblclk(x, y, mask) {on_mouse_lbtn_down(x, y)} should make double clicks behave like normal clicks...
To test, single click and drag your mouse outside the foobar window, then try doing the same but double clicking ~
(https://i.imgur.com/tmLjf53.gif)
Is ES5 at fault? Is foobar at fault? I'd really appreciate if someone can explain what is happening!
Hi All,
I have just created a script to add 'value' to foo_youtube component by providing it with a song list.
//------------ CREDIT -----------------//
Credit goes to:
- @Wil-B (https://github.com/Wil-B) for the fantastic 'Find-and-Play' app, along with the 'Biography' and 'Library-Tree' scripts based on Spider Monkey Panel. The 'Find-and-Play' inspired me to explore [YouTube searching]. However I've tried, @Wil-B's scripts still set the benchmark.
- @Marc2003 (https://github.com/jscript-panel) for the excellent [JScript Panel 3] component. @Marc2003 actively updates this component with new features, bug fixes, and beautiful, tidy sample scripts.
# This script uses some API (web service) keys from @Wil-B and @marc2003 for trial purposes. Even though these keys are bundled with their public scripts, we should show and treat them with respect.
//---------- ABOUT this JSP3_foo_youtube_addon script ----------------------//
@1_ Sole Purpose:
- YouTube search for songs or any information.
- For others to improve and tailor to their needs (as usual, I've left many comments for easy reference).
@2_ Prerequisites:
- foo_youtube component: https://www.foobar2000.org/components/view/foo_youtube; https://fy.3dyd.com/ to play YouTube videos.
- and/or yt-dlp.exe (for YouTube search): Get it from here [https://github.com/yt-dlp/yt-dlp] if you want to search YouTube using yt-dlp.exe.
(yt_dlp.exe located under this path : {fb2k_Profile_Path}\skins\external_helper\yt-dlp.exe).
@3_ How It Works:
- Users need to feed foo_youtube with a structured list of songs that is friendly with the [foo_youtube] component. This builds a playlist from track locations (similar to foo_tags).
- Where can we get the song list?
+ Manually: Users input text to search directly on youtube.com (not limited to audio tracks).
+ Still manually: Users input an artist name (1), last.fm verifies this name and returns that artist's song list from its database (2), and then youtube.com searches for this data (artist + song title).
+ Automatically: Get the list from somewhere.
- Possible online 'databases':
* MusicBrainz (musicbrainz.org)
* lastFM (last.fm, ws.audioscrobbler.com): We prefer this database as last.fm seems to be YouTube's ally.
> Top trending tracks
> Artist's top tracks classified by locale, years, genre, etc.
* Official Charts (officialcharts.com)
@4_ How We Interact with This Script:
- Context menu via right-click.
@5_ Why YouTube Music:
- We may not get 'high-res' audio tracks from youtube.com, BUT:
- It's a huge store for audio tracks, especially the [YouTube Music] streaming platform.
- Videos often contain audio tracks.
- Some/many audio tracks were/are uploaded by artists, 'semi-artists,' and are only available on this platform (especially single versions).
- Trending.
. . .
Let's dive in!
@6_ Limitations:
- YouTube searching may return irrelevant results, such as other artists' audio tracks, instead of the ones we're looking for.
How to improve:
+ Firstly, let YouTube return an audio track list, and then we search for the 'best' or good match based on our judgment (this will slow things down).
+ Alternatively, we can grab only the first/top audio track from the pool list, hoping that YouTuBe (Google) returns the best match ranked at the top (faster approach).
- User interface/UI: Not very user-friendly.
- Bugs: this is just departure , version [1.0.0 QM] 22Aug2024.
Wish you all the best.
ilovefb2k
Hi @
All ,
Please find the following:
1. _
'JSP3 foo_youtube_addon' script attached hereafter. This script reflects Air KEN’s feedback {https://hydrogenaud.io/index.php/topic,104379.msg1050940.html#msg1050940}
Change log:
- 23Aug24: YouTube searching.
- 20Sep24:
+ YouTube channel management
2. _
‘JSP3 Now playing 64bit (text display)’ Change log:
. . .
- 20Sep24:
+ YouTube download (please pay attention to YouTube clip IP ): audio only, video best by size.
+ Favorite list (aka fb2k playlist): maintain a favorite song/clip list.
note: 1.
youtube download is based on the yt_dlp.exe , ffmpeg.exe - yt_dlp path: {fb.ProfilePath} \skins\external_helper\yt-dlp.exe
- ffmpeg path : {fb.ProfilePath} \skins\external_helper\ffmpeg.exe
2.
about yt-dlp, ffmpeg.
_ yt-dlp : is a feature-rich command-line audio/video downloader with support for thousands of sites [ https://github.com/yt-dlp/yt-dlp/blob/master/supportedsites.md]. The project is a fork of youtube-dl [https://github.com/ytdl-org/youtube-dl] based on the now inactive youtube-dlc [https://github.com/blackjack4494/yt-dlc]
- ffmpeg: information as @marc2003's sample > https://jscript-panel.github.io/gallery/spectrogram-seekbar/.
Wish you all a nice weekend. @ilovefb2k
Hi @all,
Another weekend is coming, friYay!!! And we have an update for the foo_youtube_addon.
//file: {deployed} foo_youtube_addon.txt
Let’s see what this script has done for us so far:
- Manually: Search YouTube clips by employing yt-dlp.exe or web.
- Automatically: Grab playlists/charts/(radio) from online audio track databases such as last.fm.
That is all.
As we may know, the better the song database, the more updated charts/playlists/top treandings we have. Therefore, we need to look for those charts, which should be based on an in-house streaming platform.
In saying so, this 1.0.1 PD 19oct24 version:
I: Updated with charts from (and should be enough for us to keep updated with trending, as these top trending/charts/playlists are quite the same worldwide):
- YouTube
- Tidal
- Apple Music
- Billboard
II. AND some changes in look and feel:
II.1 Employing Wil-B’s ‘YouTube Track Manager’ (now ‘Find and Play’): (https://hydrogenaud.io/index.php/topic,105522.50.html, wiki: https://hydrogenaud.io/index.php/topic,111059.0.html)
// file: {deployed} foo_youtube_addon_YTTM_lite.txt
1. Features:
Remaining only a few functions of the ALBUM MANAGER section of the ‘Find and Play’ app (originally named ‘YouTube Track Manager’ based on WSH, now based on package SMP).
- Employ audio track lists from MusicBrainz or last.fm to build playlists from YouTube clips.
- MusicBrainz: Search, load, and play a wide range of release types including albums, compilations, singles, and remixes.
- Last.fm: Search, load, and play last.fm TOP albums, TOP artist tracks, and TOP similar songs.
**Refer to Wil-B's 'Find and Play' app at https://github.com/Wil-B/Find-and-Play for full and rich features, including huge options to play around with the local library as well as YouTube clips.
**This script was refactored to work alongside the JSP3 {foo_youtube_addon} script by @ilovefb2k. They communicate with each other via file configuration (File User Interface - FUI, vs DUI/CUI) or JSP3 window interface.
2 How it works:
- Initially, grabs the artist name from the now-playing audio track.
- Gathers the artist’s album names and track titles from last.fm.
- Further, can pull similar song titles and related/similar artist names (solidly based on last.fm algorithm).
- Finally, searches for clips (by artist name, song title) from youtube.com.
- Adds YouTube links to fb2k’s current playlist.
- Almost the same steps apply to the MusicBrainz repository.
3. Set-up for DUI environment:
- Step 1: Insert 1 UI panel.
- Step 2: Insert 2 child UI panels into the above panel.
- Step 3: Insert JSP3 plugin (UI element) into each panel.
- Step 4: Copy and paste JSP 3 ‘foo_youtube_addon’ into 1 JSP3 panel. Copy this script into the other JSP3 panel.
- Step 5:
+ Play an audio track that has ‘artist’ metadata to enable this script.
+ From the ‘foo_youtube_addon’ context menu, select [YouTube search addon/1~ top tracks per artist/1.1~ select current album artist…].
+ This script panel will pop up to overlay the ‘foo_youtube_addon’ panel. If NOT, move the mouse over the bottom of the ‘foo_youtube_addon’ panel to resize this script panel (just do it once to set up).
+ Once this script panel is shown, click the icon on the top-right corner to return to the ‘foo_youtube_addon’ panel.
II.2 YouTube clip management:
Those favorite video clips we have added so far may end up in a long list, so a base list (credit @marc2003 for the list object) would be convenient for us.
- Load individual/whole clip list.
- Download audio/video (we need yt-dlp.exe, ffmpeg as mentioned in the previous post). //please pay attention to video clip's IP
- Add, rename, remove clip list.
- Set rating level.
And that is all.
Hoping you all enjoy and have a great weekend.
Wish you all the best,
@ilovefb2k
P.S.
I have bundled zip files to retain the folder structure and some supporting files (plain text).
please copy them to 'profile' folder or root folder of foobar2000.
download yt-dlp.exe and ffmpeg to [skins\external_helper\] as said beforehand.
again, i have left lot of comments for your convenient reference and tailoring this script.
Hi @all,
As recently posted [https://hydrogenaud.io/index.php/topic,126733.msg1052729.html#msg1052729], we have come up with a JSP3 ‘pseudo beat audio’ script, which helps us visualize music by making light dance with the music, similar to enjoying a water-music festival where light and water dance together with the music.
That said, while BPM is ideal for guiding light to follow the beat, utilizing RMS/peak audio data should be sufficient to give the light a clue to dance.
Therefore, we have turned to @case and @marc2003’s “VU meter script” as a shortcut. Credit goes to both of them for this JSP3 feature and the beautiful VU meter sample. [https://jscript-panel.github.io/gallery/vu-meter/]
With all that in mind, we have released the JSP3 ‘Pseudo Beat Audio’ script, version “1.0.0 QP,” on the beautiful date 24-10-24. Details are as follows:
//How to add a beat skin to this ‘Pseudo Beat Audio’ script:
1.Search for/download free beat audio/3D clips, e.g.:
- Round Rotating Neon Lights 3D Illustration VJ Loop [https://www.vecteezy.com/video/1909072-round-rotating-neon-lights-3d-illustration-vj-loop]
- Futuristic 3D Video Animation of Passing Spaceship Tunnel with Square Light Lamps [https://www.vecteezy.com/video/17744905-futuristic-3d-video-animation-of-passing-spaceship-tunnel-with-square-light-lamps-between-]
- Empty Dark Room Modern Futuristic Sci-Fi Background [https://www.vecteezy.com/video/7635216-empty-dark-room-modern-futuristic-sci-fi-background]
2. Convert these clips into pictures (PNG), e.g., via this site [https://ezgif.com/video-to-png] or by your software/app.
These pictures will be loaded into memory (cache) and rendered one by one as animation (at least 24 pictures/frames per second is best).
Note: Try to select at least one full cycle/loop of smooth motion.
3. Copy these pictures into a folder created under the [beat_skin_set_path] directory.
We can edit this variable to make it convenient. This folder will be shown as the ‘beat skin’ name to interact with via the context menu.
4. Reload this script and select that ‘beat skin’.
//How this ‘Pseudo Beat Audio’ script works:
1. Get only one channel RMS/Peak level and treat this data as pseudo-beat audio.
Why: We do not focus on math to consider this data as exactly as Beats Per Minute, which is absolutely necessary for DJs.
Instead, we just focus on visualization and an acceptable level of accuracy, at which we can feel joy while enjoying music along with watching a ‘dancing’ light.
2. The script renders pictures one by one per internal timer to give us a 3D animation. Then several cycles are drawn, with their diameters based on RMS/peak level and panel/window dimensions.
Note: We can let these pictures dance by uncommenting two lines as noted and shown in the scripts.
Final note:
We have zip bundle files to retain folder structure and its files. You can find some folders' content as follows:
- beat_audio: 2 sample skins (due to 30MB quota limit/post)
- jsp3: this ‘Pseudo Beat Audio’ script.
Please unzip this file into the fb2k root folder or ‘profile’ folder.
Hope you all enjoy this humble ‘Pseudo Beat Audio’ script and have a nice weekend.
@ilovefb2k
Hi @all,Please find 2 more skin sets herein attached of ‘Pseudo Beat Audio’ script [
https://hydrogenaud.io/index.php/topic,110516.msg1052760.html#msg1052760].
unzip this file into [beat_audio] folder.
regards
@ilovefb2k P/s.
Sorry @marc2003 for spamming your thread due to quota limited per post as 30 MB max.
Hi @all,
Please find 1 more last skin set herein attached of ‘Pseudo Beat Audio’ script [https://hydrogenaud.io/index.php/topic,110516.msg1052760.html#msg1052760].
please unzip this file into [beat_audio] folder.
regards
@ilovefb2k
Looks pretty great! Now that there is a 64 SMP, will look into your code and probably recreate something similar for the waveform visualizer mode (which currently works only by BPM), really like what you did. Thank you :)
Looks pretty great! Now that there is a 64 SMP, will look into your code and probably recreate something similar for the waveform visualizer mode (which currently works only by BPM), really like what you did. Thank you :)
Hi @
regor,
It is my honor to receive your positive feedback.
Last time diving into your scripts but did not realize that you already dealt with BPM. That said, exploring your BPM-related codes is high on my to-do list to "borrow your algorithm" to finish this beat-audio puzzle.
I am glad that SMP is expanded to x64, and therefore, may come with the latest ECMA. This may inspire you to bring us more valuable widgets.
Wish you all the best,
@ilovefb2k.
The logic is that higher BPM tracks require less steps to complete an animation, while a lower BPM will add more steps. So the animation goes faster or slower depending on the BPM. The animation itself is a random variation of the waveform.
The gif shows the real waveform and also a simple visualizer preset. I used a 52 and 172 BPM tracks as example.
Currently there is only a pretty simple single preset (because my script was focused on waveform displaying and seekbar usage), and that's the thing I would want to improve seeing yours. I'm sure TT will be interested on that too.

You have the relevant code at:
https://github.com/regorxxx/Not-A-Waveform-Seekbar-SMP/blob/main/main/seekbar/seekbar_xxx.js#L553
Then multiple places using 'this.maxStep'.
The logic is that higher BPM tracks require less steps to complete an animation, while a lower BPM will add more steps. So the animation goes faster or slower depending on the BPM. The animation itself is a random variation of the waveform.
The gif shows the real waveform and also a simple visualizer preset. I used a 52 and 172 BPM tracks as example.
Currently there is only a pretty simple single preset (because my script was focused on waveform displaying and seekbar usage), and that's the thing I would want to improve seeing yours. I'm sure TT will be interested on that too.
[attach type=image]33158[/attach]
You have the relevant code at:
https://github.com/regorxxx/Not-A-Waveform-Seekbar-SMP/blob/main/main/seekbar/seekbar_xxx.js#L553
Then multiple places using 'this.maxStep'.
Hi
@regor ,
Thank you for your prompt reply and for pointing me to the right place, illustrated by a typical example.
This is absolutely saving me time. Let’s see how far I can digest your codes.
Regards,
@ilovefb2k
You have the relevant code at:
https://github.com/regorxxx/Not-A-Waveform-Seekbar-SMP/blob/main/main/seekbar/seekbar_xxx.js#L553
Just finding that seekbar - nice!
Any plans for mouse scroll wheel support?
I want to isolate all the Radio Playlists and to only display them ?
I'am looking a way to check if my playlist is a radio playlist ( in JSP3 of course ) ?
length : fb.TitleFormat('$if2(%length%,LIVE)'), return LIVE if it's a stream ( mp3 or else ) .
I could also name all the Radio Playlists with : ' RADIO ....... ' and check by name after that ?
thanks a lot if U have a solution ?
Hi @all,
As recently posted [https://hydrogenaud.io/index.php/topic,126733.msg1052729.html#msg1052729], we have come up with a JSP3 ‘pseudo beat audio’ script, which helps us visualize music by making light dance with the music, similar to enjoying a water-music festival where light and water dance together with the music.
That said, while BPM is ideal for guiding light to follow the beat, utilizing RMS/peak audio data should be sufficient to give the light a clue to dance.
Therefore, we have turned to @case and @marc2003’s “VU meter script” as a shortcut. Credit goes to both of them for this JSP3 feature and the beautiful VU meter sample. [https://jscript-panel.github.io/gallery/vu-meter/]
With all that in mind, we have released the JSP3 ‘Pseudo Beat Audio’ script, version “
1.0.0 QP,” on the beautiful date 24-10-24. Details are as follows:
//
How to add a beat skin to this ‘Pseudo Beat Audio’ script:1.Search for/download free beat audio/3D clips, e.g.:
- Round Rotating Neon Lights 3D Illustration VJ Loop [https://www.vecteezy.com/video/1909072-round-rotating-neon-lights-3d-illustration-vj-loop]
- Futuristic 3D Video Animation of Passing Spaceship Tunnel with Square Light Lamps [https://www.vecteezy.com/video/17744905-futuristic-3d-video-animation-of-passing-spaceship-tunnel-with-square-light-lamps-between-]
- Empty Dark Room Modern Futuristic Sci-Fi Background [https://www.vecteezy.com/video/7635216-empty-dark-room-modern-futuristic-sci-fi-background]
2. Convert these clips into pictures (PNG), e.g., via this site [https://ezgif.com/video-to-png] or by your software/app.
These pictures will be loaded into memory (cache) and rendered one by one as animation (at least 24 pictures/frames per second is best).
Note: Try to select at least one full cycle/loop of smooth motion.
3. Copy these pictures into a folder created under the [beat_skin_set_path] directory.
We can edit this variable to make it convenient. This folder will be shown as the ‘beat skin’ name to interact with via the context menu.
4. Reload this script and select that ‘beat skin’.
//
How this ‘Pseudo Beat Audio’ script works:
1. Get only one channel RMS/Peak level and treat this data as pseudo-beat audio.
Why: We do not focus on math to consider this data as exactly as Beats Per Minute, which is absolutely necessary for DJs.
Instead, we just focus on visualization and an acceptable level of accuracy, at which we can feel joy while enjoying music along with watching a ‘dancing’ light.
2. The script renders pictures one by one per internal timer to give us a 3D animation. Then several cycles are drawn, with their diameters based on RMS/peak level and panel/window dimensions.
Note: We can let these pictures dance by uncommenting two lines as noted and shown in the scripts.
Final note:
We have zip bundle files to retain folder structure and its files. You can find some folders' content as follows:
- beat_audio: 2 sample skins (due to 30MB quota limit/post)
- jsp3: this ‘Pseudo Beat Audio’ script.
Please unzip this file into the fb2k root folder or ‘profile’ folder.
Hope you all enjoy this humble ‘Pseudo Beat Audio’ script and have a nice weekend.@ilovefb2k
Hi @all,A weekend away is ahead, and I have a quick update to ‘
JSP3 Pseudo Beat Audio’ to make it ‘true’ 3D, as well as easy to tailor.
While watching MilkDrop2/3, I had a vague idea to add an icon at the center, and here we go.
Basically, to make a shape look 3D, simply turn it into perspective. Since @marc2003 actively keeps JSP3 updated , rendering images is no problem for this component.
Then, our job is just to place objects on the virtual layers: The background should be on layer 0, and the topmost layer is suitable for that icon. So far, we have come up with 3 layers, and maybe the next one will be for something more attractive.
How it works:- step 1: Obtain a free PNG image (transparent background) from Vecteezy [(
https://www.vecteezy.com] (e.g., for 'Mandala' subject :
https://www.vecteezy.com/free-png/mandala)]. You can also let AI generate these images. (Attached are several images for quick samples.)
- step 2: Copy these images into the [beat_audio_icon] folder. Its path is in the script file attached.
- step 3: Select an icon via the context menu. These images/files names should be under the ‘beat icon’ sub-menu.
I am still pretty sour on BPM, as the component foo_bpm [
https://www.foobar2000.org/components/view/foo_bpm] is for x32 only. I am thinking of porting it to x64 and, therefore, hope that old-school C++ helps me survive against this giant.
Wish you all a nice weekend.
@ilovefb2k P/s. Please unzip this file into the fb2k root folder or ‘profile’ folder.
I am still pretty sour on BPM, as the component foo_bpm [https://www.foobar2000.org/components/view/foo_bpm] is for x32 only.
I have posted a 64-bit enabled update about a year ago: https://foobar.hyv.fi/?view=foo_bpm (https://foobar.hyv.fi/?view=foo_bpm).
I am still pretty sour on BPM, as the component foo_bpm [https://www.foobar2000.org/components/view/foo_bpm] is for x32 only.
I have posted a 64-bit enabled update about a year ago: https://foobar.hyv.fi/?view=foo_bpm (https://foobar.hyv.fi/?view=foo_bpm).
Hi
@Case ,
Wow, thank you so much! Now I understand why there is some text regarding the 64-bit version, but the component from foobar2000.org is only 32-bit (https://wiki.hydrogenaud.io/index.php?title=Foobar2000:Components/BPM_Analyser_(foo_bpm)).
Regards,
@ilovefb2k
I think there is a bug at the JS Smooth Playlist.js sample,
js\jssp.js
Line 610
this.playlist_info += plman.GetPlaylistName(g_active_playlist) + ", " + this.list.count + " track";
if (this.list.count != 1) this.playlist_info += "s";
Should be .Count
But there is no visible bug when using the script. :o
It works exactly as expected because component method/property names are not case sensitive. I actually wish they were but there's nothing I can do about it.
I will correct it and thanks for spotting.
Another example would be console Log being uppercase here...
https://github.com/jscript-panel/Core/blob/6fac0c8dbd9110851a1ac886d53f11c630e9e3b4/JScriptPanel.idl#L261
but called using console.log in every script since forever.
Oh, didn't know. I was working on a translation layer between JSP and SMP and saw that error xd then it makes sense why it was only visible on SMP then.
Will have that in mind.
Hi @all,
Me again, and another weekend is coming—friYAY.
As yesterday posted [https://hydrogenaud.io/index.php/topic,126733.msg1053239.html#msg1053239], we have come up with a JSP3 ‘AIMP Analog VU Meter’ script.
This is just an attempt to see how far we can tune the AIMP analog VU Meter (especially needle movement) and its accurate meter range. As pointed out by @oops, and a quick observation (by me) confirmed the point that the AIMP VU meter may follow its own algorithm in terms of needle decay/raise speed and VU meter scale.
However, this approach can bring us some advantages:
- Free allocation of the VU Meter in the panel.
- Easy tuning of the needle speed.
- Other look & feel effects.
- Combining this VU Meter with other 'things' within a [JSP3 UI] panel.
So, here we go in detail:
- AIMP VU Meter types covered: analog needle only, horizon, V shape.
+ Type 1: 1 image set skin for both channels.
+ Type 2: 2 images, each for each channel.
- How to:
+ Download the AIMP VU Meter skin file (e.g. https://www.aimp.ru/forum/index.php?topic=52865.0).
+ Unzip the AIMP VU Meter skin into a folder and copy this [folder] to the specific directory as indicated by this script.
+ Load this script into the JSP3 panel.
- Limitations:
+ Options: MobilityNegative, MobilityPositive > could not take these into account.
+ Meter range (in the skin) is quite inaccurate based on fb2k's audio engine.
+ LED VU Meter is currently not supported.
Note: Refer to fb2k, @oops's, Analog VU Meter Visualisation/foo_vis_vumeter component for more options and information [https://www.foobar2000.org/components/view/foo_vis_vumeter].
Final note: We have zipped bundle files to retain folder structure and its files. You can find some folders' content as follows:
- beat_audio_vu_meter: several AIMP analog VU Meters attached and 1-customized skin to illustrate.
- jsp3: this ‘AIMP Analog VU Meter’ script.
Please unzip this file into the fb2k root folder or ‘profile’ folder.
If you prefer fb2k's VU meter skin, then simply unzip the BIN file, that AFAIK is index images, and utilize the 'JSP3 pseudo beat audio' script to manage as animation but dictated by RMS/Peak level.
Hope you all enjoy this humble ‘AIMP Analog VU Meter’ script and have a nice weekend.
@ilovefb2k
@ilovefb2k
thank you as always.
\profile\skins\viking\scripts\jsp3\{deployed} AIMP Analog VU Meter.txt
Skin folder: \profile\skins\viking\images\vnav_fb2k\beat_audio_vu_meter\
(The folder where you unzipped AIMP Analog VU Meter.zip)
(https://i.imgur.com/q4E6NDP.png) (https://i.imgur.com/dET9VXG.png)
These meter screenshots need a health warning. "May cause eye cancer". They're hideous. :/
Really? Do I need eye drops? 8)
These meter screenshots need a health warning. "May cause eye cancer". They're hideous. :/
Hi @
marc2k3,
thank you for your feedback, may i consider this as a compliment !?
wish you a nice weekend and give us more valuable features of JSP3.
regards,
@ilovefb2k
@ilovefb2k
thank you as always.
\profile\skins\viking\scripts\jsp3\{deployed} AIMP Analog VU Meter.txt
Skin folder: \profile\skins\viking\images\vnav_fb2k\beat_audio_vu_meter\
(The folder where you unzipped AIMP Analog VU Meter.zip)
(https://i.imgur.com/q4E6NDP.png) (https://i.imgur.com/dET9VXG.png)
Hi @
Air KEN,
Thank you for your positive feedback, as always.
It is said that this script can not handle those AIMP VU Meter, which are
not equal in width.
It makes sense cause yesterday evening, i did not think that such Vu meter exists. i will soon have a look at this metrics regression error and update script (if any).
Wish you a nice weekend,
@ilovefb2k
Text Reader
Automatic refresh of the text upon track selection and also with the previous and next commands.
@ilovefb2k
thank you as always.
\profile\skins\viking\scripts\jsp3\{deployed} AIMP Analog VU Meter.txt
Skin folder: \profile\skins\viking\images\vnav_fb2k\beat_audio_vu_meter\
(The folder where you unzipped AIMP Analog VU Meter.zip)
(https://i.imgur.com/q4E6NDP.png) (https://i.imgur.com/dET9VXG.png)
Hi @Air KEN,
Thank you for your positive feedback, as always.
It is said that this script can not handle those AIMP VU Meter, which are not equal in width.
It makes sense cause yesterday evening, i did not think that such Vu meter exists. i will soon have a look at this metrics regression error and update script (if any).
Wish you a nice weekend,
@ilovefb2k
hi @
all,
ref: AIMP Analog VU Meter, 1.0.1 - 01Nov24just a quick update to address metrics regression error where both channel background images are not equal in width, and high CPU-load.
regards,
@ilovefb2k
Hi :)
I have update withe the last version foo_jscript_panel3-3.8.2 but now, at the start of foobar2000 I received an error msg:
JScript Panel 3.8.2 (Last.fm Bio by marc2003)
Errore di run-time di JavaScript
'_text' non è definito
File: <main>
Line: 16, Col: 1
What I must do? :(
my pc crashed and when it went up again, for some reasons my foobar is starting totally fresh and my component are all greyed out.
Is there any way to retrieve a script that i had in a panel ? (i'm quite desperate tbh)
Panel configurations/code are stored inside
profile\theme.fth for DUI users and
profile\configuration\foo_ui_columns.dll.cfg for CUI users. But if those files are lost/reset/corrupted, you're stuffed.
On a working layout, it's perfectly safe to remove the component and you'll see this message in the Console when restarting Default UI.
UI Element instantiation failure: UI Element Not Found
This means fb2k is holding on to the configuration and it will be fully restored if the component is restored. Obviously you must not insert another UI element in the blank space that is left behind. If you did that, configuration would be lost.
But this does depend on the integrity of the theme file I mentioned.
edit: none of this is specific to JScript Panel. It applies to any component.
Ok my foo_ui_columns.dll.cfg looks like below. I guess i'm stuffed.
I cant uninstall any components. the only option is "about".
Oh well :( thanks anyway for your help

EDIT : Got it back. Well, it was my bad. I had created a profile folder in my Foobar directory and i had forgotten about that.
Deleting that folder got it to work !
pffff
Hi :)
I have update withe the last version foo_jscript_panel3-3.8.2 but now, at the start of foobar2000 I received an error msg:
Probably just have to do this ...
https://github.com/jscript-panel/release/releases/tag/latest
<!> Warning
If an update causes a script error from an included sample, simply re-import using the Samples button in the Configuration Window.
Hi :)
I have update withe the last version foo_jscript_panel3-3.8.2 but now, at the start of foobar2000 I received an error msg:
Probably just have to do this ...
https://github.com/jscript-panel/release/releases/tag/latest
<!> Warning
If an update causes a script error from an included sample, simply re-import using the Samples button in the Configuration Window.
tHANKS :)
I have reload the scrip, I see a msg about "right click to set API key.
I have no idea what to enter, so I clicked on some random numbers and the script started working...mystery ^_^
People always get offended when I ask if they're blind or stupid. What else am I supposed to think?
It's impossible to download this component without seeing this text. :/
(https://i.imgur.com/W6UYdnI.png)
People always get offended when I ask if they're blind or stupid. What else am I supposed to think?
It's impossible to download this component without seeing this text. :/
(https://i.imgur.com/W6UYdnI.png)
your post says three things, that you don't consider that many people don't understand English, that many people don't read the info that is associated with a download and that you are not able to empathize with others
your post says three things, that you don't consider that many people don't understand English, that many people don't read the info that is associated with a download and that you are not able to empathize with others
#1 & #3, all Marc.
#2 is on you.
If you're motivated enough to post here, then you should be motivated enough to actually read about what you install?
I have no idea what to enter, so I clicked on some random numbers and the script started working...mystery ^_^
Not crashing does not mean it is doing anything meaningful. You need to put your own LastFM API code in if you actually want your own data.
your post says three things, that you don't consider that many people don't understand English, that many people don't read the info that is associated with a download and that you are not able to empathize with others
#1 & #3, all Marc.
#2 is on you.
If you're motivated enough to post here, then you should be motivated enough to actually read about what you install?
I have no idea what to enter, so I clicked on some random numbers and the script started working...mystery ^_^
Not crashing does not mean it is doing anything meaningful. You need to put your own LastFM API code in if you actually want your own data.
I didn't think I asked for anyone else's opinion and I don't think the thread needs useless discussions. But, please, I'll answer you.
1 I'd like to see you if you were to go to a site written in Chinese and needed an update for a program you already use, if you would start translating the info, which usually tells you about the changes made since the latest version.
2 Your motivation comes from the problem that arose, not from installing a program you already use and know. Many people have a lot to do in life and only get involved when a problem arises. Maybe you don't have commitments and responsibilities and then you have time to read all the manuals you find around
The ability to empathize is exactly what I described and that you don't have either, but don't worry, it's not a quality that many people have. However, you will have made Marc happy by showing that you rushed to his aid, even though he was wrong but, for some, right or wrong doesn't matter :)
Now let's end here because I've wasted too much time.
If it hasn't blocked, it's fine with me because the singer's info appears.
People always get offended when I ask if they're blind or stupid. What else am I supposed to think?
It's impossible to download this component without seeing this text. :/
You can think what you want, but you don't have to write it!? ::)
For example, you could write "Please read
! Important notice carefully."
And skipped the insults... just my 2 cents.
“A little kindness goes a long way”
Thanks for your words:)
moreover we are in a forum, places born precisely to help each other in our small or big, stupid or intelligent questions. Evidently there are people who "have only this"
Just my 2 cents: Be careful not to bite the hand that feeds.
The "elders" who contribute so much that the rest of us freeload on, purely from personal interest and with no recompense, should be forgiven the occasional lack of patience when obliged to answer the same question for the umpteenth time.
The point about the comprehension of English is irrelevant. English is the official language of the forum, and there are adequate translation facilities available these days. If somebody doesn't feel able to communicate in English, then they have the option not to use the software. Nobody's forced to, take it or leave it.
The only suggestion I might make is to not dive in with a reply every time; if the question niggles then let somebody else answer it. And yes, it does niggle when people ignore what's in front of them.
The only suggestion I might make is to not dive in with a reply every time...
Look who's talking...
Just my 2 cents: Be careful not to bite the hand that feeds.
The "elders" who contribute so much that the rest of us freeload on, purely from personal interest and with no recompense, should be forgiven the occasional lack of patience when obliged to answer the same question for the umpteenth time.
The point about the comprehension of English is irrelevant. English is the official language of the forum, and there are adequate translation facilities available these days. If somebody doesn't feel able to communicate in English, then they have the option not to use the software. Nobody's forced to, take it or leave it.
The only suggestion I might make is to not dive in with a reply every time; if the question niggles then let somebody else answer it. And yes, it does niggle when people ignore what's in front of them.
I would like to remind you that no one is obliged to respond, if a person helps another (as I do in my field) they do it out of education, generosity or vanity. No one does something without having a personal gain, unless we are talking about saints.
Your considerations are superficial (to be good) and the only thing I feel like telling you is to stop LICK. I believe there is a tail and I do not believe that Marc needs it, above all, it is not useful for his human growth.
Stop talking about me
@ilovefb2k
Hi.
JSP AIMP analog VU Meter:
context menu > Setting > check setting > FL > FR OK → OK
Is this automatic?
Is there any real advantage of the JSP3 script VU meter over the recent and terrific re-work of foo_vis_vumeter by oops? With all due respect to ilovefb2k, I did get a meter to show up, but that script is a nightmare.
Is there any real advantage of the JSP3 script VU meter over the recent and terrific re-work of foo_vis_vumeter by oops? With all due respect to ilovefb2k, I did get a meter to show up, but that script is a nightmare.
It runs (with modification) with transparant background and under CUI. So it is promising.
Is there any real advantage of the JSP3 script VU meter over the recent and terrific re-work of foo_vis_vumeter by oops? With all due respect to ilovefb2k, I did get a meter to show up, but that script is a nightmare.
Is there any real advantage of the JSP3 script VU meter over the recent and terrific re-work of foo_vis_vumeter by oops? With all due respect to ilovefb2k, I did get a meter to show up, but that script is a nightmare.
It runs (with modification) with transparant background and under CUI. So it is promising.
hi @sveakul,
thank you for your feedback. It is just an attempt for us to play around and tune it to suit our specific look & feel. e.g. we may construct ourself a fb2k theme/skin and let this help us in manipulating a VU Meter.
It is in no way can compared with well-coded, beautiful and rich-feature one of @oops' or the 32x version.
hi @Defender,
yeah, you are totally right.
wish you both a nice day.
@ilovefb2k
@ilovefb2k
Hi.
JSP AIMP analog VU Meter:
context menu > Setting > check setting > FL > FR OK → OK
Is this automatic?
hi @
Air KEN,
What i have tried to 'try' there is to mimic something that i do not fully understand at all, in terms of AIMP_VU_Mete-literate background: Some parameters /
MobilityNegative, MobilityPositive/ are ignored or they are not applicable in other audio engine than native AIMP !? If we arbitrarily to replicate some parameter (e.g. ZeroLevel, which i guess is always 0 dB ?), then !? but, i thinks they are there because they are needed.
we may get back to this later on, if have more information.
in saying so,
1- that function (
context menu > Setting > check setting > FL > FR OK → OK )will retrieve parameters from INI file, which belong to each skin, and calculated based on the standard formular found here (by @
Black_AVP_Bim //
https://www.aimp.ru/forum/index.php?topic=52865.msg325066#msg325066):
A = Am * (0.5 - 10^((L - Lm)/20)) + 90, where
Am is the full angle of the scale based on the fact that it is symmetrical (MinAngle and MaxAngle are equal in modulus);
L is the calculated level in dB;
Lm is the same MaxLevel - the extreme mark of the scale.
10^((L - Lm)/20)) : convert dB to decimal.
I, then, quickly adapted to JSP3's @marc2003 to render image (DrawImage()):
A = Am* ( 10^((L - Lm)/20)) - 0.5) but, it should be:
A= Am* ( 10^((L - Lm)/20)) - MinAngle/Am) 2- and, let the peak needle on show: cause i do not know the native AIMP VU Meter follows peak or RMS. as my observation, native analog AIMP VU Meter is very sensitive to tempo, or they are quick in terms of decay/attack or fall/rise.
3- the needle arrow seems to not follow/point exactly at the skin curve where the meter signal ( -~ , -20, -10, -5, . . 0, 1,2,3, +~ ). this may be that curve line is calculated by one base while the needle cycle by a another (3,14) base !?
Having sad that, it is for
look & feel only or we have to create skin for ourself. that is , maybe, the most outcome of this script along with the case as @Defeneder pointed out in previous post.
i will have a look at this over the weekend to make the script cover the other skins where the needles are upside down.
wish you al the best,
@Air KEN @ilovefb2k
Thanks.
@ilovefb2k : I didn't know that responding "OK" to the two error messages about FL/FR actually "did" anything to the movement, thanks for that info; I just thought "dang, starting with 2 error messages is not good!"
I find the needle response very "stiff" on most of the supplied meters. while seeming to correctly point at RMS, comparing it to the JSP3 bar meters by Case and marc2k3. That "peak" needle hanging off the bottom really threw me, seems to only serve a purpose with the BMW 750 skin (lovely colors there BTW). Suggestions after my first use of the script would be:
1. Please provide a way to toggle a reading for "RMS" or "Peak" from the normal single needle meters without requiring that second "hanging ghost needle"
2. Change the two "check setting" error messages to indicate something has been adjusted, not that "it's screwed up"
3. Please point to the places in the script where users that can make manual changes to adjust speed of needle response and decay, layout, gain, etc. if these cannot be added to the GUI context menu
BTW the script *.txt can be imported into the JSP3 panel from anywhere, it doesn't need to reside first on the path given in the "// import@" line. You can change the path of the skin folder to outside fb2k and without all the "viking", etc. on line 69 of the script. For example, mine is set to
var aimp_path = "c:\\beat_audio_vu_meter\\";
I didn't change the actual folder name in case that was referred to elsewhere in the script. I dumped all the skins from both the "HA_aimp_Vu_meter_1.0.1.rar" and "HA_aimp_Vu_meter.rar" files into it. On first run, it complains about not being able to find the default skin, but then goes on to display the first skin from alphabetical order in the folder, and never complains again. All the skins appear and are selectable from the context menu, and it remembers the last skin used.
While I do have foo_uie_jsplitter installed (Foobar v2.24 x64), the whole panel creation/config import operation here was done just with JSP3.
Thanks ilovefb2k for this promising "proof of concept" addition to the fb2k meter display group and I look forward to a revised version soon!!
@ilovefb2k : I didn't know that responding "OK" to the two error messages about FL/FR actually "did" anything to the movement, thanks for that info; I just thought "dang, starting with 2 error messages is not good!"
I find the needle response very "stiff" on most of the supplied meters. while seeming to correctly point at RMS, comparing it to the JSP3 bar meters by Case and marc2k3. That "peak" needle hanging off the bottom really threw me, seems to only serve a purpose with the BMW 750 skin (lovely colors there BTW). Suggestions after my first use of the script would be:
1. Please provide a way to toggle a reading for "RMS" or "Peak" from the normal single needle meters without requiring that second "hanging ghost needle"
2. Change the two "check setting" error messages to indicate something has been adjusted, not that "it's screwed up"
3. Please point to the places in the script where users that can make manual changes to adjust speed of needle response and decay, layout, gain, etc. if these cannot be added to the GUI context menu
BTW the script *.txt can be imported into the JSP3 panel from anywhere, it doesn't need to reside first on the path given in the "// import@" line. You can change the path of the skin folder to outside fb2k and without all the "viking", etc. on line 69 of the script. For example, mine is set to var aimp_path = "c:\\beat_audio_vu_meter\\";
I didn't change the actual folder name in case that was referred to elsewhere in the script. I dumped all the skins from both the "HA_aimp_Vu_meter_1.0.1.rar" and "HA_aimp_Vu_meter.rar" files into it. On first run, it complains about not being able to find the default skin, but then goes on to display the first skin from alphabetical order in the folder, and never complains again. All the skins appear and are selectable from the context menu, and it remembers the last skin used.
While I do have foo_uie_jsplitter installed (Foobar v2.24 x64), the whole panel creation/config import operation here was done just with JSP3.
Thanks ilovefb2k for this promising "proof of concept" addition to the fb2k meter display group and I look forward to a revised version soon!!
hi @
sveakul ,
Thank you for your feedback.
The script is just there for us to see how far we can, via JSP3's @marc2003, play around with 'VU meter' and, as such, it can not serve all cases as we want , not to saying, in no way compared with
@oops' vu_meter in any aspects.
It is not mentioned that script is based on little understanding of VU meter. So please accept my apology.
with regard to needle speed, please navigate to the the following scrip, which is originally setup and created by
@Case and @marc2003.i have just made a very little modification.
function AIMP_VU_Meter_update() { //@case, @marc2003
if (!aimp_skin_check) return;
var cur_time = fb.PlaybackTime;
if (cur_time > rms_window) {
var chunk = fb.GetAudioChunk(rms_window);
if (chunk) {
var data = chunk.Data.toArray(); //data.length = chunk.ChannelCount * chunk.SampleCount
var frame_len = chunk.SampleCount; // 4410 per 100ms, 44100 per 1s
if (data && chunk.ChannelCount > 0 && frame_len > 0) {
// we get data for 2 channels only : FL, FR or vice versa !?
for (var c = 0; c < channels_count; c++) {
var sum = 0, peak = 0, peak_rms =0;
for (var i = c; i < data.length; i += chunk.ChannelCount) {
var s = Math.abs(data[i]);
sum += s * s;
if (properties.peak_needle && s > peak) peak = s;
}
// RMS level
peak_rms = Math.sqrt(sum/frame_len);
if (peak_rms > RMS_levels[c]) RMS_levels[c] = peak_rms;
else RMS_levels[c] *= peak_fall_mul;
// peak level
if (properties.peak_needle)
if (peak > Peak_levels[c]) Peak_levels[c] = peak;
else Peak_levels[c] *= peak_fall_mul;
}
window.Repaint();
}
}
}
}
I have well noted your suggestions and may have them revised to next updates, if any.
Once again, thank you very much for your feedback.
@ilovefb2k.
@ilovefb2k
Hi.
JSP AIMP analog VU Meter:
context menu > Setting > check setting > FL > FR OK → OK
Is this automatic?
Hi @
Air KEN and @
all,
As per some feedback and suggestions , please find the JSP3 "
AIMP Analog VU Meter" update attached, version named "
1.0.1 QM 05-11-24" for convenient reference.
This update addresses some points:
- High CPU load.
- Covering some very special cases, which were not easy to find a skin for, but they are there, finally. We also attached some for your quick loading:
+ The needle is upside down. Technically, the y_needle coordinates can be in (>=0) or outside (<0) the background area.
+ The needle is horizontal.
We find it very interesting as, to some extent, we could not think of such skins existing early on. Wow, what creativity from us as an audio lovers community.
On the way back home, I also thought of an option (as per @Air KEN's feedback of 'check setting'), where we can adjust a little bit the Max/MinLevel to let the needle follow fb2k's audio engine (tweak): push the MaxLevel straight up to +3dB, and pull the MinLevel back to earth at -60dB. This, as my quick observation, has very little impact on the needle movement. But, it is there, so why not give it a try.
Consequently, I am quite confident that this update covers almost 99% of analog/needle (not LED) AIMP VU meter skins as listed here [
https://www.aimp.ru/forum/index.php?topic=52865.0].
As noted, please unzip the attached file to retain the folder structure, then copy them to the root or 'profile' folder of fb2k (or we can make some changes as suggested by @
sveakul https://hydrogenaud.io/index.php?msg=1053489)
Thank you to those who have given us positive and constructive feedback to keep the light going on. I hope this brings you all a little bit more joy.
Important: Please note that this is for look & feel only, not real VU meter. and, the formula is as following:
function dbToAngle(db,c){
var angle= 0;
var scaleAngle = MaxAngle[c] - MinAngle[c]; //symmetric on the VU Meter scale
var ratio = MinAngle[c]/scaleAngle;
ratio = Math.abs(ratio);
// @Black_AVP : May 06, 2016, 15:25:42
// https://www.aimp.ru/forum/index.php?topic=52865.msg325067#msg325067
// adpated for JSP3 DrawImage()
angle = scaleAngle * ( dBToPct(db - MaxLevel[c]) - ratio ) ;
/*/
console.log("aimp VU Meter needle angle:",'db=',db,',angle=',angle);
if (db <= MinLevel) angle = MinAngle;
if (db >= MaxLevel) angle = MaxAngle;
/*/
return angle;
}
function dBToPct(dB){
return Math.pow(10,(dB/20));
}
and those script to adapt AIMP Vu Meter into @marc2003's JSP3 [
now, i have no idea why some text is there]
function AIMP_VU_Meter_seting() {
ww = window.Width;
wh = window.Height;
if (!aimp_skin_check) return;
for (var c = 0; c < channels_count; c++) {
// 1 -- rescale size to retain the ratio as AIMP does. we do not scale VU meter as fb2k does.
// assuming : both left & right panel is equal in height
ww_[c] = (ww - LM)/2, wh_[c]= wh-TM;
var scaleAangle1 = ww_[c]/wh_[c];
if (scaleAangle1 > scaleAangle[c]) ww_[c] = wh_[c]*scaleAangle[c];
else wh_[c] = ww_[c]/scaleAangle[c];
// 2 -- x,y coords scale
x_[c] = LM ; y_[c] = TM ;
if (c >0) {
x_[c]=ww_[c-1]+x_[c-1];
y_[c]=y_[c-1];
// shift the right channel panel towards left if it is wider than left channel panel
if (channel_short.channel == 0) {
x_[c]=ww_[c-1]*channel_short.ratio + x_[c-1];
}
x_[c] --; // 1px to the left to hide the gab between Left and Right panel due to calculation
}
/*/ 3 -- width, height needle scaled : we have to create a needle image, then scale per actual panel size
[+] analog VU Meter:
|-- x_needle > 0:
|-- y_needle > 0:
|-- arrow_dir = other {vertical needle}
|-- arrow_dir = other {horizontal vertical} <== for left panel only
|-- arrow_dir = down
|-- y_needle <= 0:
|-- arrow_dir = down
X|-- arrow_dir = other {not practical!}
|-- x_needle <= 0:
|-- y_needle > 0:
|-- arrow_dir = other {horizon}
X|-- arrow_dir = down {not practical!}
|-- y_needle <= 0:
X|-- arrow_dir = other {not practical!}
X|-- arrow_dir = down {not practical!}
* x_needle : x_needle coords per INI file; y_needle : y_needle coords per INI file; X : Not existed/not practical VU Meter.
/*/
var xs_ = 0,ys_ = 0;
var nxs_= 0,nys_ = 0;
var wws_ =0, whs_= 0;
var nw_ = aimp_needle_img1[c].Width, nh_ = aimp_needle_img1[c].Height;
// 3.1-- analog, x_needle > 0, y_needle > 0, arrow_dir = other {vertical }[0 111]
if (aimp_type.type[c] == 0 && aimp_type.sub_type[c] == 0
&& aimp_type.x_needle_coords[c] == 1 && aimp_type.y_needle_coords[c] == 1
&& aimp_type.arrow_dir[c] ==1 ) {
ws[c] = (ww_[c]/scaleWidth[c])*2; hs[c] = (wh_[c]/scaleHeight[c])*2;
wws_ = ww_[c]; whs_ = wh_[c];
xs_ = 0; ys_ = 0 ;
nxs_ = 0; nys_ = 0;
xn_[c] = x_[c]; yn_[c] = y_[c];
}
// 3.1.1-- analog, x_needle > 0, y_needle > 0, arrow_dir = other {horizon} [0/1 111]
if (c==0 && aimp_type.type[c] == 0 && aimp_type.sub_type[c] == 1
&& aimp_type.x_needle_coords[c] == 1 && aimp_type.y_needle_coords[c] == 1
&& aimp_type.arrow_dir[c] ==1 ) {
ws[c] = (ww_[c] - ww_[c]/scaleWidth[c])*2; hs[c] = (wh_[c]/scaleHeight[c])*2;
wws_ = ww_[c]; whs_ = wh_[c];
xs_ = ws[c]/2-ww_[c]/scaleWidth[c]; ys_ = 0 ;
nxs_ = 0; nys_ = 0;
xn_[c] = x_[c] - ws[c]/2+ww_[c]/scaleWidth[c]; yn_[c] = y_[c];
}
// 3.2-- analog, x_needle <= 0, y_needle > 0, arrow_dir = other {horizon} [0 011]
if (aimp_type.type[c] == 0
&& aimp_type.x_needle_coords[c] == 0 && aimp_type.y_needle_coords[c] == 1
&& aimp_type.arrow_dir[c] ==1 ) {
ws[c] = (ww_[c]+ ww_[c]/scaleWidth[c])*2; hs[c] = (wh_[c]/scaleHeight[c])*2;
wws_ = ww_[c]; whs_ = wh_[c];
xs_ = ws[c]/2+ww_[c]/scaleWidth[c]; ys_ = 0;
nxs_ = 0; nys_ = 0;
xn_[c] = x_[c] - ws[c]/2-ww_[c]/scaleWidth[c]; yn_[c] = y_[c];
}
// 3.3-- analog, x_needle > 0, y_needle <= 0, arrow_dir = down [0 100]
if (aimp_type.type[c] == 0
&& aimp_type.x_needle_coords[c] == 1 && aimp_type.y_needle_coords[c] == 0
&& aimp_type.arrow_dir[c] == 0 ) {
ws[c] = (ww_[c]/scaleWidth[c])*2; hs[c]= (wh_[c]+ wh_[c]/scaleHeight[c] ) *2 ;
wws_ = ww_[c]; whs_ = wh_[c];
xs_ = 0; ys_ = wh_[c] + 2*wh_[c]/scaleHeight[c];
nxs_ = 0; nys_ = 0;
xn_[c] = x_[c]; yn_[c]= y_[c]- ys_;
}
// 3.4-- analog, x_needle > 0, y_needle > 0, arrow_dir = down [0 110]
if (aimp_type.type[c] == 0
&& aimp_type.x_needle_coords[c] == 1 && aimp_type.y_needle_coords[c] == 1
&& aimp_type.arrow_dir[c] == 0 ) {
ws[c] = (ww_[c]/scaleWidth[c])*2; hs[c] = (wh_[c] - wh_[c]/scaleHeight[c] ) *2 ;
wws_ = ww_[c]; whs_ = hs[c]/2;
xs_ = 0; ys_ = hs[c]/2;
nxs_ = 0; nys_ = aimp_needle_img1[c].Height/scaleHeight[c]
xn_[c] = x_[c]; yn_[c] = y_[c]-hs[c]/2 + wh_[c]/scaleHeight[c];
}
// 4-- needle scaled
// aimp_needle_img
if (aimp_needle_img[c]) aimp_needle_img[c].Dispose();
aimp_needle_img[c] = utils.CreateImage( ws[c], hs[c] );
var gb = aimp_needle_img[c].GetGraphics();
gb.DrawImage(aimp_needle_img1[c],
xs_,ys_,wws_,whs_,
nxs_,nys_,nw_,nh_);
aimp_needle_img[c].ReleaseGraphics(); gb = null;
// aimp_needle_peak_img
if (aimp_needle_peak_img[c]) aimp_needle_peak_img[c].Dispose();
aimp_needle_peak_img[c] = utils.CreateImage(ws[c], hs[c]);
var gb = aimp_needle_peak_img[c].GetGraphics();
gb.DrawImage(aimp_needle_peak_img1[c],
xs_,ys_,wws_,whs_,
nxs_,nys_,nw_,nh_);
aimp_needle_peak_img[c].ReleaseGraphics(); gb = null;
// aimp_needle_peak_peak_img
if (aimp_needle_peak_peak_img[c]) aimp_needle_peak_peak_img[c].Dispose();
aimp_needle_peak_peak_img[c] = utils.CreateImage(ws[c], hs[c]);
var gb = aimp_needle_peak_peak_img[c].GetGraphics();
gb.DrawImage(aimp_needle_peak_peak_img1[c],
xs_,ys_,wws_,whs_,
nxs_,nys_,nw_,nh_);
aimp_needle_peak_peak_img[c].ReleaseGraphics(); gb = null;
}
/*/ for testing only
window.MaxWidth = window.MinWidth = LM+aimp_needle_img1[c].Width*2;
window.MaxHeight = window.MinHeight = TM+aimp_needle_img1[c].Height;
/*/
}
due to my limited-resource, i am sorry in advance for later reply, if any.
And now, I have to rush for a 4P pizza as my lovely wife is right behind me.
Regards,
@ilovefb2k
Thank you for the quick update. Enjoy your pizza.
As per some feedback and suggestions , please find the JSP3 "AIMP Analog VU Meter" update attached, version named "1.0.1 QM 05-11-24" for convenient reference.
@ilovefb2k
Thx.
Can you add an option to the right click menu for Background color? Option No fill or Transparent. Which effectively disables the painting of the background which is being done in line 503 and 504.
Can you add an option to the right click menu to set the margins (properties HA.METER.Left Margin and HA.METER.Top margin)?
The original VUmeter stretches to fill the window/panel it lives in. Your script fills from top/left until it reaches bottom/right margin but keeps aspect ratio. Would it be possible to add an option so your script stretches too?
How do you get the base images and needle for a VU meter? Is there a tool to rip them from an existing VUmeter BIN file?
...
How do you get the base images and needle for a VU meter? Is there a tool to rip them from an existing VUmeter BIN file?
You can go to the AIMP forum (https://www.aimp.ru/forum/index.php?topic=52865.msg324293#msg324293) and use the ZIP-Files containing the AIMP VU-Meters, in these Zip's you'll find the pics.
sorry for being off topic but is it possible to get a sound level in the taskbar like in the picture
...
How do you get the base images and needle for a VU meter? Is there a tool to rip them from an existing VUmeter BIN file?
You can go to the AIMP forum (https://www.aimp.ru/forum/index.php?topic=52865.msg324293#msg324293) and use the ZIP-Files containing the AIMP VU-Meters, in these Zip's you'll find the pics.
Thx. There's quite a lot. Unfortunately not the ones I really like.
I have those in BIN format. The VU Editor (that creates the BIN files for foo_vis_vumeter) can not open/read its own BIN files. It opens VU project files. When you are done you can export a project to a BIN file which uses either No Compression, BZIP2 or LZMA.
One of my BIN files start with a BZh91 header so I guess it is BZIP2 compressed. Unfortunately I cannot open the file with RAR/7-Zip.
Does anyone have a bright idea to extract the files from a VU meter BIN file?
As per some feedback and suggestions , please find the JSP3 "AIMP Analog VU Meter" update attached, version named "1.0.1 QM 05-11-24" for convenient reference.
@ilovefb2k
Thx.
Can you add an option to the right click menu for Background color? Option No fill or Transparent. Which effectively disables the painting of the background which is being done in line 503 and 504.
Can you add an option to the right click menu to set the margins (properties HA.METER.Left Margin and HA.METER.Top margin)?
The original VUmeter stretches to fill the window/panel it lives in. Your script fills from top/left until it reaches bottom/right margin but keeps aspect ratio. Would it be possible to add an option so your script stretches too?
How do you get the base images and needle for a VU meter? Is there a tool to rip them from an existing VUmeter BIN file?
hi @
Defender,
your fb2k theme/skin looks very promising.
regarding your feedback, may i humbly raise my points as follows, in hoping that helps:
1.
add an option to the right click menu for Background color :
Done. please find the script attached and 2 screenshots illustrated thereafter.2.
properties HA.METER.Left Margin and HA.METER.Top margin adjustment:
As you have already pointed out. /SHIFT + right click/ on the panel to bring the context menu up front, which should have item allowing us to access window properties. These properties should be there. 3.
Would it be possible to add an option so your script stretches [skin] too :
Yes, in principal.
we may try the following pseudo_script, which is whithin on_paint() callback to refresh per internal timer. The point is that we create an instance\image of the VU Meter every internal timer, then it is too fast to rapidly consume CPU-power and Memory, which , consequently, may cause computer to memory leak and crash.
as such, my approach is to leave it aside till we can have better solution. function on_paint(gr) {
/*/ note:
- aimp_bg_img : background image
- aimp_needle_img : needle image
- aimp_needle_img : cover image
/*/
. . .
var aimp = utils.CreateImage(aimp_bg_img.Width,aimp_bg_img.Height);
var gb = aimp.GetGraphics();
// paint background
gb.DrawImage(aimp_bg_img,0,0,aimp_bg_img.Width,aimp_bg_img.Height,0,0,aimp_bg_img.Width,aimp_bg_img.Height);
// paint needle adjusted by angle per db_RMS/peak levell
gb.DrawImage(aimp_needle_img,
0,0,aimp_needle_img.Width,aimp_needle_img.Height,
0,0,aimp_needle_img.Width,aimp_needle_img.Height/scaleHeight,
1,
dbToAngle(dB_RMS)
) ;
// paint cover
gb.DrawImage(aimp_bg_cover,0,0,aimp_bg_cover.Width,aimp_bg_cover.Height,0,0,aimp_bg_cover.Width,aimp_bg_cover.Height);
// garbage collection
aimp.ReleaseGraphics();
// draw image to the panel and LET the JSP3 scale image per panel dimension /width, height/
gr.DrawImage(aimp,0,0,ww/2,wh/2,0,0,aimp.Width,aimp.Height);
. . .
}
4-
base images and needle for a VU meter :
the script is solely based on AIMP VU Meter skins, which are compressed by standard method. In principal, we may let javascript to un-zip that files or utilize 3rd command-line tools to do it. I well noted this suggestion.
however, follow some of your later posts, it seems you want the script to play around with fb2k's VU Meter skin, which are zipped by its or component's method. so far, i have had no idea to give it a try cause i do not have any clue about that format and, therefore, the script has no feature to deal with fb2k VU Meter skins.
however, based on @oops's comments during developing vu_vis_meter, i do think that that BIN should have at least a background, cover and a sheet list of data that help component to paint the needle. but, that is a guess.hope this helps,
regards
@ilovefb2k
sorry for being off topic but is it possible to get a sound level in the taskbar like in the picture
VERY off-topic. A one-off reply: right-click the taskbar (not the tool bar) and choose "Show volume". It will then appear in the lower right corner as a dB value; mouse over and center wheel will adjust up/down, or, click on it and you'll get a slider.
thank you for the reply say no more
I have those in BIN format. The VU Editor (that creates the BIN files for foo_vis_vumeter) can not open/read its own BIN files. It opens VU project files. When you are done you can export a project to a BIN file which uses either No Compression, BZIP2 or LZMA.
Does anyone have a bright idea to extract the files from a VU meter BIN file?
I'll second that. Could someone please make a tool that can both export the image components from a BIN file, and re-import them into the same BIN, overwriting the originals? Then a user could make say a color change to a meter body using an image editor and then re-save the BIN with that change. With VUEditor you can only do this by starting with "*.vu project files," not the BIN file.
@ilovefb2k : I loaded your newly posted 1.011 script completely as-is with just the skin folder path mod, and the meter movements are MUCH more reactive and seem more accurate. Thanks for clarifying the "check setting" prompts! What I have been doing when I load a new skin is do the "check setting" procedure, and keep the "tweak min/max level" option checked--I am assuming that the latter is performing an additional refinement to using the "check setting" buttons--is that correct?
I did not add the portion of script to 1.01 you posted a day earlier in response to my concerns about needle movement, as I am guessing those changes are addressed in the new 1.011 QM 05-11-24 version.
1. add an option to the right click menu for Background color : Done. please find the script attached and 2 screenshots illustrated thereafter.
2. properties HA.METER.Left Margin and HA.METER.Top margin adjustment: As you have already pointed out. /SHIFT + right click/ on the panel to bring the context menu up front, which should have item allowing us to access window properties. These properties should be there.
3. Would it be possible to add an option so your script stretches [skin] too : Yes, in principal.
we may try the following pseudo_script, which is whithin on_paint() callback to refresh per internal timer. The point is that we create an instance\image of the VU Meter every internal timer, then it is too fast to rapidly consume CPU-power and Memory, which , consequently, may cause computer to memory leak and crash.
as such, my approach is to leave it aside till we can have better solution.
4- base images and needle for a VU meter : the script is solely based on AIMP VU Meter skins, which are compressed by standard method. In principal, we may let javascript to un-zip that files or utilize 3rd command-line tools to do it. I well noted this suggestion.
however, follow some of your later posts, it seems you want the script to play around with fb2k's VU Meter skin, which are zipped by its or component's method. so far, i have had no idea to give it a try cause i do not have any clue about that format and, therefore, the script has no feature to deal with fb2k VU Meter skins.
however, based on @oops's comments during developing vu_vis_meter, i do think that that BIN should have at least a background, cover and a sheet list of data that help component to paint the needle. but, that is a guess.
Ad 1) Works. Thx. The reason I like to have it in the rightclickmenu and as a property is when you release a new version I do not have to outcomment the background paintcode everytime.
Ad 2) I noticed that sometimes the properties reset themselves loading different skins or changing rightclick options.
Another thing is that it is a bit inconsistent to only set left and top margins. If you set a top and left option I would expect these margins to be also applied to the right and bottom which they are not. So please add separate padding options for right and for bottom or apply the setting for left also to right and the setting for top also to bottom.
Ad 3) Ok. I will look into it later.
Ad 4) The idea I have is to extract the images from a BIN file, create an appropiate skin.ini and use your script to display the results.
As a proof of concept I have been experimenting with recreating stuff from a BIN file. If you rightclick on a running foo_vis_vumeter BIN skin you can see the native resolution. Then I define a panel in my skin with this exact size in which I run the BIN. Make a screenshot when not playing anything and make a screenshot at full level with replaygain off. Merge the two screenshots to get rid off the needle. Which leaves you with the base png of the particular skin.
Then paint the needle (I use lunapic) in a separate png. Very hard to determine the correct length needed for the needle.
Then experiment with changing values in a skin.ini until it more or less resembles the behavior of the original BIN.
I find it is very difficult to determine settings for PivotPointX and PivotPointY. Also changing settings for MobilityNegative and
MobilityPositive do not change behavior as far as I can see.
All in all very timeconsuming.
It would help a lot if the values of PivotPointX and PivotPointY could be calculated automatically. If you have those values it is far more easy to determine the needed length for the needle.
I attached the results of my experiment including the AIMP skin I created and the original BIN file.
The lower large VU meter is the BIN file running. The upper large VU meter is run by your script. The left part runs with the original needle of Line Magnetic 501 and the right part runs with my recreated needle.
Both are running in their native resolution.
AIMP skin
In case somebody wants to experiment with my 7inch_3 rip without the ugly red needle on the left here are two working versions.
First is a vanilla version and the second works with an upgraded gradient background.
It is quite easy to change colors and backgrounds if you have the underlying png files.
@Defender
(https://i.imgur.com/1hzYkuY.png)
I set it to (30-30-30) to match the dark mode.
It's originally a color for DarkOne, right?
The needle vibration is also nice.
I also use 7inch_3.bin with foo_vis_vumeter.
I like that it's simple and easy to see.
Thank you.
how do you install the vu meter
@telboy1812
Reply #1867 By ilovefb2k: https://hydrogenaud.io/index.php/topic,110516.msg1053272.html#msg1053272
or
foo_vis_vumeter
https://hydrogenaud.io/index.php/topic,126733.0.html
thank you :)
@Defender
(https://i.imgur.com/1hzYkuY.png)
I set it to (30-30-30) to match the dark mode.
It's originally a color for DarkOne, right?
The needle vibration is also nice.
I also use 7inch_3.bin with foo_vis_vumeter.
I like that it's simple and easy to see.
Thank you.
You are welcome.
My skin is based on the original DarkOne v4. All my colors are derived from the original background color 19-30-38.
All panels I paint have optional external padding, an optional bezel, optional accent, optional gradient, optional internal padding and selectable background art. On top of such a painted panel with transparency enabled I display plugins.
I played around a bit more with the AIMP skins and when scaling is implemented in this script as it is in foo_vis_vumeter you can do things like the left VU panel from the screenshot with has a namelogo of the playing artist as background.
I also attached a version of my AIMP skin that is supposed to live in a panel with activated transparency. You might want to try that one as well.
@telboy1812
Reply #1867 By ilovefb2k: https://hydrogenaud.io/index.php/topic,110516.msg1053272.html#msg1053272
or
foo_vis_vumeter
https://hydrogenaud.io/index.php/topic,126733.0.html
@telboy1812 Follow the above instructions.
Then extract my skins under the following folder.
%APPDATA%\foobar2000-v2\skins\viking\images\vnav_fb2k\beat_audio_vu_meter
Should give you something like the attached screenshot.
Then rightclick on the panel with the component and choose a skin ...
I have those in BIN format. The VU Editor (that creates the BIN files for foo_vis_vumeter) can not open/read its own BIN files. It opens VU project files. When you are done you can export a project to a BIN file which uses either No Compression, BZIP2 or LZMA.
Does anyone have a bright idea to extract the files from a VU meter BIN file?
I'll second that. Could someone please make a tool that can both export the image components from a BIN file, and re-import them into the same BIN, overwriting the originals? Then a user could make say a color change to a meter body using an image editor and then re-save the BIN with that change. With VUEditor you can only do this by starting with "*.vu project files," not the BIN file.
Hmm, there are quite a few skins for the AIMP Analog VU Meter that I would like to do something about, or have someone do something about.
Sharp GF-9000
(https://i.imgur.com/nXAg3ct.png)
thank you for the help but my nephew will sort it tomorrow as I am to old for pcs heh
how do you install the vu meter
There are three "types."
1. The AIMP-only ilovefb2k JSP3 meters should be installed using the latest script ("1.0.11 QM 05-11-24") here: https://hydrogenaud.io/index.php?action=dlattach;topic=110516.0;attach=33395 (https://hydrogenaud.io/index.php?action=dlattach;topic=110516.0;attach=33395) (No meters are included). You can use the same instructions that Defender and Air KEN posted, which are mostly repeated at the beginning of the script file itself. Sample meters are include with the 1.0 and 1.0.1 version packages attached to earlier posts.
The above script works ONLY with AIMP analog meters (not LVU) that do not have LEDs and requires Javascript Panel 3 to be installed.
2. The re-written plugin foo_vis_vumeter will display all three main types--AIMP analog (with or without LEDs), AIMP "LVU", and the Foobar BIN meters. JSP3 is not required. https://hydrogenaud.io/index.php/topic,126733.0.html (https://hydrogenaud.io/index.php/topic,126733.0.html)
3. The JSP3 horizontal bar variety, discussed in detail earlier, easiest tried by installing the built-in "VU Meter" sample from later versions of Javascript Panel 3 (mine is from 3.79 but it's in the newest version also). This is not a representation of an AIMP or BIN style meter face, but extremely accurate double bars (there are 4-bar mods) that are tied to the JSP3 ability to get raw audio data right from the Foobar interface.
Enjoy, but have lots of time on your hands first ;)
@ilovefb2k : I loaded your newly posted 1.011 script completely as-is with just the skin folder path mod, and the meter movements are MUCH more reactive and seem more accurate. Thanks for clarifying the "check setting" prompts! What I have been doing when I load a new skin is do the "check setting" procedure, and keep the "tweak min/max level" option checked--I am assuming that the latter is performing an additional refinement to using the "check setting" buttons--is that correct?
I did not add the portion of script to 1.01 you posted a day earlier in response to my concerns about needle movement, as I am guessing those changes are addressed in the new 1.011 QM 05-11-24 version.
Hi @
sveakul,
[Just a quick reply cause i got a deadline, so sorry about this].
as per your yesterday feedback, i thought there was something to do with MobilityNegative option: The needle speed is sensitive to CPU-power.
consequently, there must be somewhere to dictate this, and as you pointed out: we just let the RMS level roll back gently by applying it some tasks to do. i just name the variable after 'rms_decay_speed', which can be adjusted via JSP3's properties window [
HA.RMS.decay.speed (0-1)] to suit our system.
We just get the
MobilityNegative value from INI file and assign this to the script.
peak_rms = Math.sqrt(sum/frame_len);
//instantly react: RMS_levels[c] = peak_rms;
// or: gently
if (peak_rms > RMS_levels[c]) RMS_levels[c] = peak_rms;
else RMS_levels[c] *= rms_decay_speed;
note: this method was already done by
@Marc2003's VU meter script. we just figure out how to bind this with the MobilityNegative option.
And, as such, ' "check setting" option is just there to show the MaxLevel/MinLevel and angle. Based on these information, we may know how accurate INI data is and make some changes or calibrate, if nay.
regards,
@ilovefb2k
1. add an option to the right click menu for Background color : Done. please find the script attached and 2 screenshots illustrated thereafter.
2. properties HA.METER.Left Margin and HA.METER.Top margin adjustment: As you have already pointed out. /SHIFT + right click/ on the panel to bring the context menu up front, which should have item allowing us to access window properties. These properties should be there.
3. Would it be possible to add an option so your script stretches [skin] too : Yes, in principal.
we may try the following pseudo_script, which is whithin on_paint() callback to refresh per internal timer. The point is that we create an instance\image of the VU Meter every internal timer, then it is too fast to rapidly consume CPU-power and Memory, which , consequently, may cause computer to memory leak and crash.
as such, my approach is to leave it aside till we can have better solution.
4- base images and needle for a VU meter : the script is solely based on AIMP VU Meter skins, which are compressed by standard method. In principal, we may let javascript to un-zip that files or utilize 3rd command-line tools to do it. I well noted this suggestion.
however, follow some of your later posts, it seems you want the script to play around with fb2k's VU Meter skin, which are zipped by its or component's method. so far, i have had no idea to give it a try cause i do not have any clue about that format and, therefore, the script has no feature to deal with fb2k VU Meter skins.
however, based on @oops's comments during developing vu_vis_meter, i do think that that BIN should have at least a background, cover and a sheet list of data that help component to paint the needle. but, that is a guess.
Ad 1) Works. Thx. The reason I like to have it in the rightclickmenu and as a property is when you release a new version I do not have to outcomment the background paintcode everytime.
Ad 2) I noticed that sometimes the properties reset themselves loading different skins or changing rightclick options.
Another thing is that it is a bit inconsistent to only set left and top margins. If you set a top and left option I would expect these margins to be also applied to the right and bottom which they are not. So please add separate padding options for right and for bottom or apply the setting for left also to right and the setting for top also to bottom.
Ad 3) Ok. I will look into it later.
Ad 4) The idea I have is to extract the images from a BIN file, create an appropiate skin.ini and use your script to display the results.
As a proof of concept I have been experimenting with recreating stuff from a BIN file. If you rightclick on a running foo_vis_vumeter BIN skin you can see the native resolution. Then I define a panel in my skin with this exact size in which I run the BIN. Make a screenshot when not playing anything and make a screenshot at full level with replaygain off. Merge the two screenshots to get rid off the needle. Which leaves you with the base png of the particular skin.
Then paint the needle (I use lunapic) in a separate png. Very hard to determine the correct length needed for the needle.
Then experiment with changing values in a skin.ini until it more or less resembles the behavior of the original BIN.
I find it is very difficult to determine settings for PivotPointX and PivotPointY. Also changing settings for MobilityNegative and
MobilityPositive do not change behavior as far as I can see.
All in all very timeconsuming.
It would help a lot if the values of PivotPointX and PivotPointY could be calculated automatically. If you have those values it is far more easy to determine the needed length for the needle.
I attached the results of my experiment including the AIMP skin I created and the original BIN file.
The lower large VU meter is the BIN file running. The upper large VU meter is run by your script. The left part runs with the original needle of Line Magnetic 501 and the right part runs with my recreated needle.
Both are running in their native resolution.
Hi @
Defender,
[Just a quick reply, so sorry about this].
1- (1) Works. : Thank you
2 -1: sometimes the properties reset themselves : I did utilize
window.Reload(option), where
option = false. this should not trigger any properties reset to default. i will check it over the weekend.
2-2: add separate padding options for right and for bottom : Done. please find the script attached. There may be likely bugs cause i am in a rush.
3- Thank you. I am looking forwards to your script.
4- It is fantastic that you can play around with that. I humbly raise an idea to calculate x0,y0 as per image attached. It should be easy for you to catch up.
regards,
@ilovefb2k
2 -1: sometimes the properties reset themselves : I did utilize window.Reload(option), where option = false. this should not trigger any properties reset to default. i will check it over the weekend.
2-2: add separate padding options for right and for bottom : Done. please find the script attached. There may be likely bugs cause i am in a rush.
4- It is fantastic that you can play around with that. I humbly raise an idea to calculate x0,y0 as per image attached. It should be easy for you to catch up.
@ilovefb2k 2-1) Properties still reset sometimes.
2-2) Thanks for adding margin properties for top and bottom. I asked this just for consistency since I always set them to 0.
The alignment option works great. I always put it to Center. It rises an issue though. When the available height is greater than needed the vu meter is aligned correctly. However (after adjusting PivotPointX and PivotPointY) at high output the needle displays under the allotted space for the VU meter. and under the opaque L_2 png. See attached screenshot (needles in red to show the issue).
As you can see in the screenshot the original VU meter resizes automatically to use full available space.
Is this functionality you are going to look into as well?
I realize that angle calculations will become more complicated.
Another nice feature of the original VU meter is that you can adjust sensibility my using control mousewheel. which would be a great feature instead of entering a fixed value in properties.
Thx
Def
okay i give up :'( i don't see \profile\skins\viking\scripts\jsp3\{deployed} AIMP Analog VU Meter.txt here what I see
@telboy1812
AIMP Analog VU Meter.7z (beat_audio_vu_meter, {deployed} AIMP Analog VU Meter.txt)
https://mega.nz/file/4TslWCzT#qexjdlX0j_jjET072IPwo-_iDqUHik86j-8HedGVdbU
Place the skin folder in:
\profile\skins\viking\images\vnav_fb2k\beat_audio_vu_meter\
Prepare JScript Panel 3 Panel and load "{deployed} AIMP Analog VU Meter.txt". JScript Panel 3 Panel context menu > Configure... >Tools > Import
my foobar folder
It's standard installation. You specified the installation folder yourself, not the standard installation folder.
The configuration folder is as follows.
"C:\Users\UserName\AppData\Roaming\foobar2000-v2"
Launch foobar2000. Shift key + menu "File" > Browse configuration folder will open.
The foobar2000-v2 folder will open.
skins.7z
https://mega.nz/file/8L9XSRDJ#S1tH53eoNSbIMh8ujNKEXphb3uH7LehSeGXRl5F-eJo
Unzip the skins.7z file.
Place the skin folder as follows:
"foobar2000-v2"
Prepare JScript Panel 3 Panel and load "{deployed} AIMP Analog VU Meter.txt". JScript Panel 3 Panel context menu > Configure... >Tools > Import
my app data sorry it took me so long
This is the configuration folder "foobar2000-v2" folder. Place the Skin folder you downloaded there. The Skin folder is included. Then, start foobar2000 and load the Script file ({deployed} AIMP Analog VU Meter.txt).
(https://i.imgur.com/JoUE9OE.png)
(https://i.imgur.com/t9Xjyw0.png)
(https://i.imgur.com/KDhQGAK.png)
This is sounding harder than it is; if you have used JSP3 before it's easy.
1. First, download the latest script, version "
1.0.12 QM 06-11-24," inside the rar posted here: https://hydrogenaud.io/index.php?action=dlattach;topic=110516.0;attach=33430 (https://hydrogenaud.io/index.php?action=dlattach;topic=110516.0;attach=33430)
2. Create a folder for the skins anywhere on your PC, like "C:\beat_audio_vu_meter". Extract the *.txt script from the rar, go to line 92 and change the path of the skins folder to where you made it, e.g.
var aimp_path = "c:\\beat_audio_vu_meter\\";
The latest "{deployed} AIMP Analog VU Meter....." rar file you downloaded above contains no skins but the earlier ones do, check the earlier posts from ilovefb2k, and drop in your skins folder the ones from those.
3. Go into Layout Editing mode in fb2k, create a JSP3 panel, and add the meter script via the standard Configure/Tools/Import method.
4. The first time it opens it will complain about not being able to find the default skin, but that happens only once.
5. Use the context menu to select the skins, make settings adjustments, etc,
The {deployed} "AIMP Analog VU Meter_1.0.12_6Nov24" script has added user-adjustable alignment padding, and via the JSP3 "Properties" panel the ability to set RMS/Peak Decay Speed and RMS Gain.
grr i can't find my appdata folder to import aimp folder so sorry
skins.7z
https://mega.nz/file/8L9XSRDJ#S1tH53eoNSbIMh8ujNKEXphb3uH7LehSeGXRl5F-eJo
Unzip the skins.7z file.
Place the skin folder as follows:
"foobar2000-v2"
This is the configuration folder "foobar2000-v2" folder. Place the Skin folder you downloaded there. The Skin folder is included. Then, start foobar2000 and load the Script file ({deployed} AIMP Analog VU Meter.txt).
Everything is included.
Just place the "Skin" folder you downloaded and unzipped. It's easy.
This is a JScript Panel script. Once you have set the folder, all you have to do is load the script.
Please take your time and read carefully. Reading carefully is the best way to understand.
skins.7z
https://mega.nz/file/8L9XSRDJ#S1tH53eoNSbIMh8ujNKEXphb3uH7LehSeGXRl5F-eJo
Unzip the skins.7z file.
Place the skin folder as follows:
"foobar2000-v2"
This is the configuration folder "foobar2000-v2" folder. Place the Skin folder you downloaded there. The Skin folder is included. Then, start foobar2000 and load the Script file ({deployed} AIMP Analog VU Meter.txt).
Everything is included.
Just place the "Skin" folder you downloaded and unzipped. It's easy.
This is a JScript Panel script. Once you have set the folder, all you have to do is load the script.
Please take your time and read carefully. Reading carefully is the best way to understand.
And if one has a portable installation, now I understand why it gives me an error.
i get error after i apply i am very sorry
grr i can't find my appdata folder to import aimp folder so sorry
By default in Windows the folder where foobar stores its the configuration data is hidden.
You need to enable show hidden files in Windows Explorer to be able to browse to the foobar configuration folder.
And if one has a portable installation, now I understand why it gives me an error.
As far as I can see line 7 is obsolete since it is the current file.
In line 92 you can set a different path if you don't like aimp_path = fb.ProfilePath + "skins\\viking\\images\\vnav_fb2k\\beat_audio_vu_meter\\"
@ApacheReal
Is this an error about "{deployed} album_art [properties].txt"? How about this one?
It has nothing to do with the AIMP Analog VU Meter. The questioner already has it.
AIMP Analog VU Meter.7z
https://mega.nz/file/hblXxQqY#B8B4aMLlD3187_-yYvVrtrAblaxkYqnrD_hIbSW_kg8
@telboy1812
It's not an error, but rather the skin that is loaded first. Can't you press OK and select the skin by right-clicking?
It's already done.
Could you please show me the foobar2000 AIMP Analog VU Meter Panel?
grr i can't find my appdata folder to import aimp folder so sorry
By default in Windows the folder where foobar stores its the configuration data is hidden.
You need to enable show hidden files in Windows Explorer to be able to browse to the foobar configuration folder.
@Defender Thanks.
I have just described a simple way to do it.
Reply #1926: https://hydrogenaud.io/index.php/topic,110516.msg1053632.html#msg1053632
Launch foobar2000. Shift key + menu "File" > Browse configuration folder will open.
The
foobar2000-v2 folder will open.
The Skin List is sorted by alphabet, so I put the ones that are easiest to read first.
7inch_3 gradient
7inch_3 transparent
7inch_3 vanilla
And if one has a portable installation, now I understand why it gives me an error.
As far as I can see line 7 is obsolete since it is the current file.
In line 92 you can set a different path if you don't like aimp_path = fb.ProfilePath + "skins\\viking\\images\\vnav_fb2k\\beat_audio_vu_meter\\"
Thank you. I didn't want to waste time, because as you can see from the image, I'm busy on various modules with foo uei webview.
(https://i.imgur.com/YAPJx9F.png)
@ilovefb2k : with your next AIMP Analog VU Meter script, is there any chance of adding:
1. Vertical layout for separate L/R meters?
2. Support for non-LVU AIMP analog skins that have "LEDs" and dual needles? (skin attached)
sorry for the long reply but not sure if I have the right idea or what line you are looking at but I do appropriate your help
2 -1: sometimes the properties reset themselves : I did utilize window.Reload(option), where option = false. this should not trigger any properties reset to default. i will check it over the weekend.
2-2: add separate padding options for right and for bottom : Done. please find the script attached. There may be likely bugs cause i am in a rush.
4- It is fantastic that you can play around with that. I humbly raise an idea to calculate x0,y0 as per image attached. It should be easy for you to catch up.
@ilovefb2k
2-1) Properties still reset sometimes.
2-2) Thanks for adding margin properties for top and bottom. I asked this just for consistency since I always set them to 0.
The alignment option works great. I always put it to Center. It rises an issue though. When the available height is greater than needed the vu meter is aligned correctly. However (after adjusting PivotPointX and PivotPointY) at high output the needle displays under the allotted space for the VU meter. and under the opaque L_2 png. See attached screenshot (needles in red to show the issue).
As you can see in the screenshot the original VU meter resizes automatically to use full available space.
Is this functionality you are going to look into as well?
I realize that angle calculations will become more complicated.
Another nice feature of the original VU meter is that you can adjust sensibility my using control mousewheel. which would be a great feature instead of entering a fixed value in properties.
Thx
Def
Hi @
Defender,
Thank you for your feedback.
I have tried some approaches tonight to get the
skin stretching (as
@oops does with vu_vis_meter
'unlock aspect ratio') but ended up with almost nothing but a small progress. How hard we have tried, we could consume a lot of CPU power. I will have more details later on in the hope that someone will help.
Regarding your feedback:
1- Properties still reset sometimes:
We removed the window.Reload() method but alert users to restart fb2k.2- Adding margin properties for top and bottom:
It is very nice to know that. I have just refactored the script as I did it in a rush last time.3- The needle displays under the allotted space for the VU meter:
I also noted this early on, as a weird tail. This is a set combined of INI, background, and cover, and it is there because I do not fully understand the algorithm drawing the needle curve. For now, we have to erase the needle's 'tail' a little bit. I tried, and it worked. Well-noted this point. As you pointed out, a stretching layout will address this problem, and I tried to add that feature to the script. Please refer to my next post for more detail.4- Adjust sensitivity by using the control mouse wheel:
As needle decay speed is dictated by AIMP VU Meter's INI file, I would leave it as it is supposed to be, in my humble opinion. User input is needed only if the MobilityNegative option is missing from INI.
Regards and wish you a nice weekend.
@ilovefb2k
skins.7z
https://mega.nz/file/8L9XSRDJ#S1tH53eoNSbIMh8ujNKEXphb3uH7LehSeGXRl5F-eJo
Unzip the skins.7z file.
Place the skin folder as follows:
"foobar2000-v2"
This is the configuration folder "foobar2000-v2" folder. Place the Skin folder you downloaded there. The Skin folder is included. Then, start foobar2000 and load the Script file ({deployed} AIMP Analog VU Meter.txt).
Everything is included.
Just place the "Skin" folder you downloaded and unzipped. It's easy.
This is a JScript Panel script. Once you have set the folder, all you have to do is load the script.
Please take your time and read carefully. Reading carefully is the best way to understand.
Hi @
Air KEN ,
It is very nice of you, thank you.
wish you a nice weekend.
@ilovefb2k
@ilovefb2k : with your next AIMP Analog VU Meter script, is there any chance of adding:
1. Vertical layout for separate L/R meters?
2. Support for non-LVU AIMP analog skins that have "LEDs" and dual needles? (skin attached)
hi @
sveakul,
these features are very nice, we will surely consider them in the next update.
thank your for your nice suggestions and positive feedbacks so far.
it is true that, we alone can go fast, but we together can go further.
regards
@ilovefb2k.
Is there any real advantage of the JSP3 script VU meter over the recent and terrific re-work of foo_vis_vumeter by oops? With all due respect to ilovefb2k, I did get a meter to show up, but that script is a nightmare.
Is there any real advantage of the JSP3 script VU meter over the recent and terrific re-work of foo_vis_vumeter by oops? With all due respect to ilovefb2k, I did get a meter to show up, but that script is a nightmare.
It runs (with modification) with transparant background and under CUI. So it is promising.
hi @sveakul,
thank you for your feedback. It is just an attempt for us to play around and tune it to suit our specific look & feel. e.g. we may construct ourself a fb2k theme/skin and let this help us in manipulating a VU Meter.
It is in no way can compared with well-coded, beautiful and rich-feature one of @oops' or the 32x version.
hi @Defender,
yeah, you are totally right.
wish you both a nice day.
@ilovefb2k
@ilovefb2k
Hi.
JSP AIMP analog VU Meter:
context menu > Setting > check setting > FL > FR OK → OK
Is this automatic?
[/spoiler]
Hi @Air KEN and @all,
As per some feedback and suggestions , please find the JSP3 "AIMP Analog VU Meter" update attached, version named "1.0.1 QM 05-11-24" for convenient reference.
This update addresses some points:
- High CPU load.
- Covering some very special cases, which were not easy to find a skin for, but they are there, finally. We also attached some for your quick loading:
+ The needle is upside down. Technically, the y_needle coordinates can be in (>=0) or outside (<0) the background area.
+ The needle is horizontal.
We find it very interesting as, to some extent, we could not think of such skins existing early on. Wow, what creativity from us as an audio lovers community.
On the way back home, I also thought of an option (as per
@Air KEN's feedback of 'check setting'), where we can adjust a little bit the Max/MinLevel to let the needle follow fb2k's audio engine (tweak): push the MaxLevel straight up to +3dB, and pull the MinLevel back to earth at -60dB. This, as my quick observation, has very little impact on the needle movement. But, it is there, so why not give it a try.
Consequently, I am quite confident that this update covers almost 99% of analog/needle (not LED) AIMP VU meter skins as listed here [
https://www.aimp.ru/forum/index.php?topic=52865.0].
As noted, please unzip the attached file to retain the folder structure, then copy them to the root or 'profile' folder of fb2k (or we can make some changes as suggested by @
sveakul https://hydrogenaud.io/index.php?msg=1053489)
Thank you to those who have given us positive and constructive feedback to keep the light going on. I hope this brings you all a little bit more joy.
Important: Please note that this is for look & feel only, not real VU meter. and, the formula is as following:
function dbToAngle(db,c){
var angle= 0;
var scaleAngle = MaxAngle[c] - MinAngle[c]; //symmetric on the VU Meter scale
var ratio = MinAngle[c]/scaleAngle;
ratio = Math.abs(ratio);
// @Black_AVP : May 06, 2016, 15:25:42
// https://www.aimp.ru/forum/index.php?topic=52865.msg325067#msg325067
// adpated for JSP3 DrawImage()
angle = scaleAngle * ( dBToPct(db - MaxLevel[c]) - ratio ) ;
/*/
console.log("aimp VU Meter needle angle:",'db=',db,',angle=',angle);
if (db <= MinLevel) angle = MinAngle;
if (db >= MaxLevel) angle = MaxAngle;
/*/
return angle;
}
function dBToPct(dB){
return Math.pow(10,(dB/20));
}
and those script to adapt AIMP Vu Meter into @marc2003's JSP3 [
now, i have no idea why some text is there]
function AIMP_VU_Meter_seting() {
ww = window.Width;
wh = window.Height;
if (!aimp_skin_check) return;
for (var c = 0; c < channels_count; c++) {
// 1 -- rescale size to retain the ratio as AIMP does. we do not scale VU meter as fb2k does.
// assuming : both left & right panel is equal in height
ww_[c] = (ww - LM)/2, wh_[c]= wh-TM;
var scaleAangle1 = ww_[c]/wh_[c];
if (scaleAangle1 > scaleAangle[c]) ww_[c] = wh_[c]*scaleAangle[c];
else wh_[c] = ww_[c]/scaleAangle[c];
// 2 -- x,y coords scale
x_[c] = LM ; y_[c] = TM ;
if (c >0) {
x_[c]=ww_[c-1]+x_[c-1];
y_[c]=y_[c-1];
// shift the right channel panel towards left if it is wider than left channel panel
if (channel_short.channel == 0) {
x_[c]=ww_[c-1]*channel_short.ratio + x_[c-1];
}
x_[c] --; // 1px to the left to hide the gab between Left and Right panel due to calculation
}
/*/ 3 -- width, height needle scaled : we have to create a needle image, then scale per actual panel size
[+] analog VU Meter:
|-- x_needle > 0:
|-- y_needle > 0:
|-- arrow_dir = other {vertical needle}
|-- arrow_dir = other {horizontal vertical} <== for left panel only
|-- arrow_dir = down
|-- y_needle <= 0:
|-- arrow_dir = down
X|-- arrow_dir = other {not practical!}
|-- x_needle <= 0:
|-- y_needle > 0:
|-- arrow_dir = other {horizon}
X|-- arrow_dir = down {not practical!}
|-- y_needle <= 0:
X|-- arrow_dir = other {not practical!}
X|-- arrow_dir = down {not practical!}
* x_needle : x_needle coords per INI file; y_needle : y_needle coords per INI file; X : Not existed/not practical VU Meter.
/*/
var xs_ = 0,ys_ = 0;
var nxs_= 0,nys_ = 0;
var wws_ =0, whs_= 0;
var nw_ = aimp_needle_img1[c].Width, nh_ = aimp_needle_img1[c].Height;
// 3.1-- analog, x_needle > 0, y_needle > 0, arrow_dir = other {vertical }[0 111]
if (aimp_type.type[c] == 0 && aimp_type.sub_type[c] == 0
&& aimp_type.x_needle_coords[c] == 1 && aimp_type.y_needle_coords[c] == 1
&& aimp_type.arrow_dir[c] ==1 ) {
ws[c] = (ww_[c]/scaleWidth[c])*2; hs[c] = (wh_[c]/scaleHeight[c])*2;
wws_ = ww_[c]; whs_ = wh_[c];
xs_ = 0; ys_ = 0 ;
nxs_ = 0; nys_ = 0;
xn_[c] = x_[c]; yn_[c] = y_[c];
}
// 3.1.1-- analog, x_needle > 0, y_needle > 0, arrow_dir = other {horizon} [0/1 111]
if (c==0 && aimp_type.type[c] == 0 && aimp_type.sub_type[c] == 1
&& aimp_type.x_needle_coords[c] == 1 && aimp_type.y_needle_coords[c] == 1
&& aimp_type.arrow_dir[c] ==1 ) {
ws[c] = (ww_[c] - ww_[c]/scaleWidth[c])*2; hs[c] = (wh_[c]/scaleHeight[c])*2;
wws_ = ww_[c]; whs_ = wh_[c];
xs_ = ws[c]/2-ww_[c]/scaleWidth[c]; ys_ = 0 ;
nxs_ = 0; nys_ = 0;
xn_[c] = x_[c] - ws[c]/2+ww_[c]/scaleWidth[c]; yn_[c] = y_[c];
}
// 3.2-- analog, x_needle <= 0, y_needle > 0, arrow_dir = other {horizon} [0 011]
if (aimp_type.type[c] == 0
&& aimp_type.x_needle_coords[c] == 0 && aimp_type.y_needle_coords[c] == 1
&& aimp_type.arrow_dir[c] ==1 ) {
ws[c] = (ww_[c]+ ww_[c]/scaleWidth[c])*2; hs[c] = (wh_[c]/scaleHeight[c])*2;
wws_ = ww_[c]; whs_ = wh_[c];
xs_ = ws[c]/2+ww_[c]/scaleWidth[c]; ys_ = 0;
nxs_ = 0; nys_ = 0;
xn_[c] = x_[c] - ws[c]/2-ww_[c]/scaleWidth[c]; yn_[c] = y_[c];
}
// 3.3-- analog, x_needle > 0, y_needle <= 0, arrow_dir = down [0 100]
if (aimp_type.type[c] == 0
&& aimp_type.x_needle_coords[c] == 1 && aimp_type.y_needle_coords[c] == 0
&& aimp_type.arrow_dir[c] == 0 ) {
ws[c] = (ww_[c]/scaleWidth[c])*2; hs[c]= (wh_[c]+ wh_[c]/scaleHeight[c] ) *2 ;
wws_ = ww_[c]; whs_ = wh_[c];
xs_ = 0; ys_ = wh_[c] + 2*wh_[c]/scaleHeight[c];
nxs_ = 0; nys_ = 0;
xn_[c] = x_[c]; yn_[c]= y_[c]- ys_;
}
// 3.4-- analog, x_needle > 0, y_needle > 0, arrow_dir = down [0 110]
if (aimp_type.type[c] == 0
&& aimp_type.x_needle_coords[c] == 1 && aimp_type.y_needle_coords[c] == 1
&& aimp_type.arrow_dir[c] == 0 ) {
ws[c] = (ww_[c]/scaleWidth[c])*2; hs[c] = (wh_[c] - wh_[c]/scaleHeight[c] ) *2 ;
wws_ = ww_[c]; whs_ = hs[c]/2;
xs_ = 0; ys_ = hs[c]/2;
nxs_ = 0; nys_ = aimp_needle_img1[c].Height/scaleHeight[c]
xn_[c] = x_[c]; yn_[c] = y_[c]-hs[c]/2 + wh_[c]/scaleHeight[c];
}
// 4-- needle scaled
// aimp_needle_img
if (aimp_needle_img[c]) aimp_needle_img[c].Dispose();
aimp_needle_img[c] = utils.CreateImage( ws[c], hs[c] );
var gb = aimp_needle_img[c].GetGraphics();
gb.DrawImage(aimp_needle_img1[c],
xs_,ys_,wws_,whs_,
nxs_,nys_,nw_,nh_);
aimp_needle_img[c].ReleaseGraphics(); gb = null;
// aimp_needle_peak_img
if (aimp_needle_peak_img[c]) aimp_needle_peak_img[c].Dispose();
aimp_needle_peak_img[c] = utils.CreateImage(ws[c], hs[c]);
var gb = aimp_needle_peak_img[c].GetGraphics();
gb.DrawImage(aimp_needle_peak_img1[c],
xs_,ys_,wws_,whs_,
nxs_,nys_,nw_,nh_);
aimp_needle_peak_img[c].ReleaseGraphics(); gb = null;
// aimp_needle_peak_peak_img
if (aimp_needle_peak_peak_img[c]) aimp_needle_peak_peak_img[c].Dispose();
aimp_needle_peak_peak_img[c] = utils.CreateImage(ws[c], hs[c]);
var gb = aimp_needle_peak_peak_img[c].GetGraphics();
gb.DrawImage(aimp_needle_peak_peak_img1[c],
xs_,ys_,wws_,whs_,
nxs_,nys_,nw_,nh_);
aimp_needle_peak_peak_img[c].ReleaseGraphics(); gb = null;
}
/*/ for testing only
window.MaxWidth = window.MinWidth = LM+aimp_needle_img1[c].Width*2;
window.MaxHeight = window.MinHeight = TM+aimp_needle_img1[c].Height;
/*/
}
due to my limited-resource, i am sorry in advance for later reply, if any.
And now, I have to rush for a 4P pizza as my lovely wife is right behind me.
Regards,
@ilovefb2k
Hi @
Defender , @
sveakul, @
Air KEN and @
all,
A week has gone by too fast, like the wind. Please find the updated JSP3 '
AIMP Analog VU Meter' script attached, named version '
1.0.13 DT-K 08-Nov-24' for convenient reference, details as following:
Just one feature was added:
unlock aspect ratio, as per @
Defender's suggestion.
A free night weekend allowed me to play around with this feature, which I also think is a must-try if we want the script to move on to 'animation' VU Meters, which contain pre-calculated data/images per needle angle.
Please note that once this option is on, CPU load may be
boosted up to Mars and won't come back, so fasten your computer's belt for a safe trip.What happens behind the scenes:
The script will create around 200 x 2 channels = 400 needle images (we may tune this number per the hard-coded variable stepCache, for now), which are number of screenshots of needles per angle along the meter range, then load them into 'heap' memory. We will instantly note an increase in RAM consumption in less than 1 second, then it will return to normal.
Later on, we just retrieve each needle image by its index-converted angle as real-time calculated. To do this, we have to do a trick, just jotting it down here for those who want to make it better:
-Step 1:
Allocate memory for hundreds of images.-Step 2:
Draw needles, 1 needle per 1 image, per 1 angle. This takes about 1 ms each.
-Step 3:
Garbage collection. As we allocate stack memory, we have to clear it ourselves or soon end up crashing. This will also take more than 1 ms each, which is time-consuming.
So, we have to make an async task, which will transfer the clearance job (step 3) to another thread, and we can move on. In principle, we can reuse some async methods of JSP3 to do this job in a very 'strange' manner. For example:
fb.AddLocationsAsync(window_id, [""]);
on_locations_added(task_id, handle_list) { do clearing job, which is not related to this native function}
Or, simply, leave this mess for
window.SetTimeout({do clearing job}, 1)
=> We move on, and this method, on another thread, will do the clearing job after 1 ms and not bother us.
As such, we will experience a frozen-screen instance (not core audio engine) for a very short time. To save CPU power, just do this one time per current panel size until we move to another skin. Consequently, the resolution will not be nice if we enlarge the panel size, or we will have to switch forward and back just 1 skin to update the needle images caching for the current panel size.
If something seems wrong (e.g. needles are not on show), then a '
hard reset' via context menu [shift +right click] will bring back default setting and may help.
And that is all. Wish you all the very best and a very nice weekend.
Regards,
@ilovefb2k
Just one feature was added: unlock aspect ratio, as per @Defender's suggestion.
@ilovefb2k Just a quick reaction. It works fine and is the way I am going to use it.
To clarify ... I don't want to stretch the VU meter (BIN or yours) more than either a maximum horizontal scaling or a maximum vertical scaling so I recalculate the VU meter coordinates using these maximum scaling factors. If that means there's either some horizontal or vertical space left I display a bezel around the VU meter, which I don't do with my transparent skin that I made for your script since it doesn't look better. For reference I attached the relevant code for calculating VU coordinates.
I now applied this code also to your script. As you can see your VU meter looks slightly larger than the original BIN. Reason for that is that I slightly cut the original bezel from the BIN before making the remaining bezel transparent.
// plug.x - initial VU panel x-coordinate
// plug.y - initial VU panel y-coordinate
// plug.w - initial VU panel width
// plug.h - initial VU panel height
$ifgreater($get(dbg.vu),0, $puts(dbg1,STEP|1:|plug.xywh=$get(plug.x).$get(plug.y).$get(plug.w).$get(plug.h)) ,)
// VU panel standard settings
$puts(vu.x_fact, 400) // VU default proportion - X
$puts(vu.y_fact, 100) // VU default proportion - Y
$puts(vu.acc, $mul(%on.accent.vu%,%def.accent%)) // VU - Accent padding
$puts(vu.acc_limit, $muldiv(0,%scale%,100)) // Limit to trigger accent padding - 0= Always full on, otherwise either horizontal only or vertical only
// VU panel specific padding
$puts(vu.l_pad, 0) // VU - Left padding
$puts(vu.r_pad, $get(vu.l_pad)) // VU - Right padding
$puts(vu.t_pad, 0) // VU - Top padding
$puts(vu.b_pad, $get(vu.t_pad)) // VU - Bottom padding
// VU panel specific width and scaling settings
$puts(vu.w_min, $muldiv( 250,%scale%,100)) // VU minimum width - when less width available do not display VUmeter
$puts(vu.w_max, $muldiv(10000,%scale%,100)) // VU maximum width - set very high to use full available width
$puts(vu.w_scale, $max(175, 100)) // VU maximum width scale percentage related to original vu dimensions vu.x_fact en vu.y_fact. Minimum value 100
$puts(vu.h_scale, $max(150, 100)) // VU maximum height scale percentage related to original vu dimensions vu.x_fact en vu.y_fact. Minimum value 100
// Calculate initial VU height and width using available width/height and above settings
$puts(vu.w, $sub($min($get(vu.w_max),$get(plug.w)),$get(vu.l_pad),$get(vu.r_pad)))
$puts(vu.h, $sub($get(plug.h),$get(vu.t_pad),$get(vu.b_pad)))
$puts(vu.h, $min($get(vu.h), $muldiv($muldiv($get(vu.w),$get(vu.y_fact),$get(vu.x_fact)), $get(vu.h_scale), 100)))
$puts(vu.w, $min($get(vu.w), $muldiv($muldiv($get(vu.h),$get(vu.x_fact),$get(vu.y_fact)), $get(vu.w_scale), 100)))
// Calculate final VU coordinates adjusted for padding and painted accent
$ifgreater($get(vu.w_min),$get(vu.w),
$puts(vu.w, 0)
,
$puts(vu.y, $add($get(plug.y), $div($sub($get(plug.h),$get(vu.h)),2))) // Vcenter alignment
$puts(vu.x, $add($get(plug.x), $div($sub($get(plug.w),$get(vu.w)),2))) // Hcenter alignment
$ifgreater($get(dbg.vu),0, $puts(dbg2,STEP|2:|||vu.xywh=$get(vu.x).$get(vu.y).$get(vu.w).$get(vu.h)) ,)
// Paint accent and adjust VU coordinates accordingly
$ifgreater($get(vu.acc),0,
$ifgreater($get(vu.acc_limit),0,
$puts(vu.x_pad, $sub($get(vu.x),$get(plug.x)))
$puts(vu.y_pad, $sub($get(vu.y),$get(plug.y)))
$ifgreater($get(vu.acc_limit),$get(vu.x_pad),
$puts(vu.x_pad, 0)
,)
$ifgreater($get(vu.acc_limit),$get(vu.y_pad),
$puts(vu.y_pad, 0)
,)
,
$puts(vu.x_pad, 1)
$puts(vu.y_pad, 1)
)
$ifgreater($add($get(vu.x_pad),$get(vu.y_pad)),0,
// $drawrect($get(vu.x), $get(vu.y), $get(vu.w), $get(vu.h), %cola.at%, %cola.at%)
$puts(i,0)
$ifgreater($get(vu.acc),$get(i), $drawrect($add($get(vu.x),$get(i)), $add($get(vu.y),$get(i)), $sub($get(vu.w),$mul($get(i),2)), $sub($get(vu.h),$mul($get(i),2)), 0-0-0-0, %cola.at%) $puts(i, $add($get(i),1)) ,)
$ifgreater($get(vu.acc),$get(i), $drawrect($add($get(vu.x),$get(i)), $add($get(vu.y),$get(i)), $sub($get(vu.w),$mul($get(i),2)), $sub($get(vu.h),$mul($get(i),2)), 0-0-0-0, %cola.at%) $puts(i, $add($get(i),1)) ,)
$ifgreater($get(vu.x_pad),0,
$puts(vu.x, $add($get(vu.x), $get(vu.acc)))
$puts(vu.w, $sub($get(vu.w), $mul($get(vu.acc),2)))
,)
$ifgreater($get(vu.y_pad),0,
$puts(vu.y, $add($get(vu.y), $get(vu.acc)))
$puts(vu.h, $sub($get(vu.h), $mul($get(vu.acc),2)))
,)
,)
,)
)
$ifgreater($get(dbg.vu),0, $puts(dbg3,STEP|3:|||vu.xywh=$get(vu.x).$get(vu.y).$get(vu.w).$get(vu.h)) ,)
// vu.x - final VU x-coordinate
// vu.y - final VU y-coordinate
// vu.w - final VU width - do not show/display VU panel when value is 0
// vu.h - final VU height
One thing I noticed is that your skin does not look as sharp as the original BIN, which is very noticeable with larger sized VU meters.
Do you use an internal smaller rendered image before rescaling and displaying to the allotted panel?
EDIT: Sorry, just noticed you already mentioned this.
Is there any real advantage of the JSP3 script VU meter over the recent and terrific re-work of foo_vis_vumeter by oops? With all due respect to ilovefb2k, I did get a meter to show up, but that script is a nightmare.
Is there any real advantage of the JSP3 script VU meter over the recent and terrific re-work of foo_vis_vumeter by oops? With all due respect to ilovefb2k, I did get a meter to show up, but that script is a nightmare.
It runs (with modification) with transparant background and under CUI. So it is promising.
hi @sveakul,
thank you for your feedback. It is just an attempt for us to play around and tune it to suit our specific look & feel. e.g. we may construct ourself a fb2k theme/skin and let this help us in manipulating a VU Meter.
It is in no way can compared with well-coded, beautiful and rich-feature one of @oops' or the 32x version.
hi @Defender,
yeah, you are totally right.
wish you both a nice day.
@ilovefb2k
@ilovefb2kHi.
JSP AIMP analog VU Meter:
context menu > Setting > check setting > FL > FR OK → OK
Is this automatic?
[/spoiler]
Hi @Air KEN and @all,
As per some feedback and suggestions , please find the JSP3 "AIMP Analog VU Meter" update attached, version named "1.0.1 QM 05-11-24" for convenient reference.
This update addresses some points:
- High CPU load.
- Covering some very special cases, which were not easy to find a skin for, but they are there, finally. We also attached some for your quick loading:
+ The needle is upside down. Technically, the y_needle coordinates can be in (>=0) or outside (<0) the background area.
+ The needle is horizontal.
We find it very interesting as, to some extent, we could not think of such skins existing early on. Wow, what creativity from us as an audio lovers community.
On the way back home, I also thought of an option (as per
@Air KEN's feedback of 'check setting'), where we can adjust a little bit the Max/MinLevel to let the needle follow fb2k's audio engine (tweak): push the MaxLevel straight up to +3dB, and pull the MinLevel back to earth at -60dB. This, as my quick observation, has very little impact on the needle movement. But, it is there, so why not give it a try.
Consequently, I am quite confident that this update covers almost 99% of analog/needle (not LED) AIMP VU meter skins as listed here [
https://www.aimp.ru/forum/index.php?topic=52865.0].
As noted, please unzip the attached file to retain the folder structure, then copy them to the root or 'profile' folder of fb2k (or we can make some changes as suggested by @
sveakul https://hydrogenaud.io/index.php?msg=1053489)
Thank you to those who have given us positive and constructive feedback to keep the light going on. I hope this brings you all a little bit more joy.
Important: Please note that this is for look & feel only, not real VU meter. and, the formula is as following:
function dbToAngle(db,c){
var angle= 0;
var scaleAngle = MaxAngle[c] - MinAngle[c]; //symmetric on the VU Meter scale
var ratio = MinAngle[c]/scaleAngle;
ratio = Math.abs(ratio);
// @Black_AVP : May 06, 2016, 15:25:42
// https://www.aimp.ru/forum/index.php?topic=52865.msg325067#msg325067
// adpated for JSP3 DrawImage()
angle = scaleAngle * ( dBToPct(db - MaxLevel[c]) - ratio ) ;
/*/
console.log("aimp VU Meter needle angle:",'db=',db,',angle=',angle);
if (db <= MinLevel) angle = MinAngle;
if (db >= MaxLevel) angle = MaxAngle;
/*/
return angle;
}
function dBToPct(dB){
return Math.pow(10,(dB/20));
}
and those script to adapt AIMP Vu Meter into @marc2003's JSP3 [
now, i have no idea why some text is there]
function AIMP_VU_Meter_seting() {
ww = window.Width;
wh = window.Height;
if (!aimp_skin_check) return;
for (var c = 0; c < channels_count; c++) {
// 1 -- rescale size to retain the ratio as AIMP does. we do not scale VU meter as fb2k does.
// assuming : both left & right panel is equal in height
ww_[c] = (ww - LM)/2, wh_[c]= wh-TM;
var scaleAangle1 = ww_[c]/wh_[c];
if (scaleAangle1 > scaleAangle[c]) ww_[c] = wh_[c]*scaleAangle[c];
else wh_[c] = ww_[c]/scaleAangle[c];
// 2 -- x,y coords scale
x_[c] = LM ; y_[c] = TM ;
if (c >0) {
x_[c]=ww_[c-1]+x_[c-1];
y_[c]=y_[c-1];
// shift the right channel panel towards left if it is wider than left channel panel
if (channel_short.channel == 0) {
x_[c]=ww_[c-1]*channel_short.ratio + x_[c-1];
}
x_[c] --; // 1px to the left to hide the gab between Left and Right panel due to calculation
}
/*/ 3 -- width, height needle scaled : we have to create a needle image, then scale per actual panel size
[+] analog VU Meter:
|-- x_needle > 0:
|-- y_needle > 0:
|-- arrow_dir = other {vertical needle}
|-- arrow_dir = other {horizontal vertical} <== for left panel only
|-- arrow_dir = down
|-- y_needle <= 0:
|-- arrow_dir = down
X|-- arrow_dir = other {not practical!}
|-- x_needle <= 0:
|-- y_needle > 0:
|-- arrow_dir = other {horizon}
X|-- arrow_dir = down {not practical!}
|-- y_needle <= 0:
X|-- arrow_dir = other {not practical!}
X|-- arrow_dir = down {not practical!}
* x_needle : x_needle coords per INI file; y_needle : y_needle coords per INI file; X : Not existed/not practical VU Meter.
/*/
var xs_ = 0,ys_ = 0;
var nxs_= 0,nys_ = 0;
var wws_ =0, whs_= 0;
var nw_ = aimp_needle_img1[c].Width, nh_ = aimp_needle_img1[c].Height;
// 3.1-- analog, x_needle > 0, y_needle > 0, arrow_dir = other {vertical }[0 111]
if (aimp_type.type[c] == 0 && aimp_type.sub_type[c] == 0
&& aimp_type.x_needle_coords[c] == 1 && aimp_type.y_needle_coords[c] == 1
&& aimp_type.arrow_dir[c] ==1 ) {
ws[c] = (ww_[c]/scaleWidth[c])*2; hs[c] = (wh_[c]/scaleHeight[c])*2;
wws_ = ww_[c]; whs_ = wh_[c];
xs_ = 0; ys_ = 0 ;
nxs_ = 0; nys_ = 0;
xn_[c] = x_[c]; yn_[c] = y_[c];
}
// 3.1.1-- analog, x_needle > 0, y_needle > 0, arrow_dir = other {horizon} [0/1 111]
if (c==0 && aimp_type.type[c] == 0 && aimp_type.sub_type[c] == 1
&& aimp_type.x_needle_coords[c] == 1 && aimp_type.y_needle_coords[c] == 1
&& aimp_type.arrow_dir[c] ==1 ) {
ws[c] = (ww_[c] - ww_[c]/scaleWidth[c])*2; hs[c] = (wh_[c]/scaleHeight[c])*2;
wws_ = ww_[c]; whs_ = wh_[c];
xs_ = ws[c]/2-ww_[c]/scaleWidth[c]; ys_ = 0 ;
nxs_ = 0; nys_ = 0;
xn_[c] = x_[c] - ws[c]/2+ww_[c]/scaleWidth[c]; yn_[c] = y_[c];
}
// 3.2-- analog, x_needle <= 0, y_needle > 0, arrow_dir = other {horizon} [0 011]
if (aimp_type.type[c] == 0
&& aimp_type.x_needle_coords[c] == 0 && aimp_type.y_needle_coords[c] == 1
&& aimp_type.arrow_dir[c] ==1 ) {
ws[c] = (ww_[c]+ ww_[c]/scaleWidth[c])*2; hs[c] = (wh_[c]/scaleHeight[c])*2;
wws_ = ww_[c]; whs_ = wh_[c];
xs_ = ws[c]/2+ww_[c]/scaleWidth[c]; ys_ = 0;
nxs_ = 0; nys_ = 0;
xn_[c] = x_[c] - ws[c]/2-ww_[c]/scaleWidth[c]; yn_[c] = y_[c];
}
// 3.3-- analog, x_needle > 0, y_needle <= 0, arrow_dir = down [0 100]
if (aimp_type.type[c] == 0
&& aimp_type.x_needle_coords[c] == 1 && aimp_type.y_needle_coords[c] == 0
&& aimp_type.arrow_dir[c] == 0 ) {
ws[c] = (ww_[c]/scaleWidth[c])*2; hs[c]= (wh_[c]+ wh_[c]/scaleHeight[c] ) *2 ;
wws_ = ww_[c]; whs_ = wh_[c];
xs_ = 0; ys_ = wh_[c] + 2*wh_[c]/scaleHeight[c];
nxs_ = 0; nys_ = 0;
xn_[c] = x_[c]; yn_[c]= y_[c]- ys_;
}
// 3.4-- analog, x_needle > 0, y_needle > 0, arrow_dir = down [0 110]
if (aimp_type.type[c] == 0
&& aimp_type.x_needle_coords[c] == 1 && aimp_type.y_needle_coords[c] == 1
&& aimp_type.arrow_dir[c] == 0 ) {
ws[c] = (ww_[c]/scaleWidth[c])*2; hs[c] = (wh_[c] - wh_[c]/scaleHeight[c] ) *2 ;
wws_ = ww_[c]; whs_ = hs[c]/2;
xs_ = 0; ys_ = hs[c]/2;
nxs_ = 0; nys_ = aimp_needle_img1[c].Height/scaleHeight[c]
xn_[c] = x_[c]; yn_[c] = y_[c]-hs[c]/2 + wh_[c]/scaleHeight[c];
}
// 4-- needle scaled
// aimp_needle_img
if (aimp_needle_img[c]) aimp_needle_img[c].Dispose();
aimp_needle_img[c] = utils.CreateImage( ws[c], hs[c] );
var gb = aimp_needle_img[c].GetGraphics();
gb.DrawImage(aimp_needle_img1[c],
xs_,ys_,wws_,whs_,
nxs_,nys_,nw_,nh_);
aimp_needle_img[c].ReleaseGraphics(); gb = null;
// aimp_needle_peak_img
if (aimp_needle_peak_img[c]) aimp_needle_peak_img[c].Dispose();
aimp_needle_peak_img[c] = utils.CreateImage(ws[c], hs[c]);
var gb = aimp_needle_peak_img[c].GetGraphics();
gb.DrawImage(aimp_needle_peak_img1[c],
xs_,ys_,wws_,whs_,
nxs_,nys_,nw_,nh_);
aimp_needle_peak_img[c].ReleaseGraphics(); gb = null;
// aimp_needle_peak_peak_img
if (aimp_needle_peak_peak_img[c]) aimp_needle_peak_peak_img[c].Dispose();
aimp_needle_peak_peak_img[c] = utils.CreateImage(ws[c], hs[c]);
var gb = aimp_needle_peak_peak_img[c].GetGraphics();
gb.DrawImage(aimp_needle_peak_peak_img1[c],
xs_,ys_,wws_,whs_,
nxs_,nys_,nw_,nh_);
aimp_needle_peak_peak_img[c].ReleaseGraphics(); gb = null;
}
/*/ for testing only
window.MaxWidth = window.MinWidth = LM+aimp_needle_img1[c].Width*2;
window.MaxHeight = window.MinHeight = TM+aimp_needle_img1[c].Height;
/*/
}
due to my limited-resource, i am sorry in advance for later reply, if any.
And now, I have to rush for a 4P pizza as my lovely wife is right behind me.
Regards,
@ilovefb2k
Hi @Defender , @sveakul, @Air KEN and @all,
A week has gone by too fast, like the wind. Please find the updated JSP3 'AIMP Analog VU Meter' script attached, named version '1.0.13 DT-K 08-Nov-24' for convenient reference, details as following:
Just one feature was added: unlock aspect ratio, as per @Defender's suggestion.
A free night weekend allowed me to play around with this feature, which I also think is a must-try if we want the script to move on to 'animation' VU Meters, which contain pre-calculated data/images per needle angle.
Please note that once this option is on, CPU load may be boosted up to Mars and won't come back, so fasten your computer's belt for a safe trip.
What happens behind the scenes:
The script will create around 200 x 2 channels = 400 needle images (we may tune this number per the hard-coded variable stepCache, for now), which are number of screenshots of needles per angle along the meter range, then load them into 'heap' memory. We will instantly note an increase in RAM consumption in less than 1 second, then it will return to normal.
Later on, we just retrieve each needle image by its index-converted angle as real-time calculated.
To do this, we have to do a trick, just jotting it down here for those who want to make it better:
-Step 1: Allocate memory for hundreds of images.
-Step 2: Draw needles, 1 needle per 1 image, per 1 angle. This takes about 1 ms each.
-Step 3: Garbage collection. As we allocate stack memory, we have to clear it ourselves or soon end up crashing. This will also take more than 1 ms each, which is time-consuming.
So, we have to make an async task, which will transfer the clearance job (step 3) to another thread, and we can move on. In principle, we can reuse some async methods of JSP3 to do this job in a very 'strange' manner. For example:
fb.AddLocationsAsync(window_id, [""]);
on_locations_added(task_id, handle_list) { do clearing job, which is not related to this native function}
Or, simply, leave this mess for window.SetTimeout({do clearing job}, 1)
=> We move on, and this method, on another thread, will do the clearing job after 1 ms and not bother us.
As such, we will experience a frozen-screen instance (not core audio engine) for a very short time. To save CPU power, just do this one time per current panel size until we move to another skin. Consequently, the resolution will not be nice if we enlarge the panel size, or we will have to switch forward and back just 1 skin to update the needle images caching for the current panel size.
If something seems wrong (e.g. needles are not on show), then a 'hard reset' via context menu [shift +right click] will bring back default setting and may help.
And that is all. Wish you all the very best and a very nice weekend.
Regards,
@ilovefb2k
quick edit ,
please ignore the script in the previous post.
use the attached herein instead.
update: addressing a special case where the needles are horizontal.
regards
@ilovefb2k
quick edit ,
please ignore the script in the previous post.
use the attached herein instead.
update: addressing a special case where the needles are horizontal.
regards
This last script does not show a VU meter for me.
Just one feature was added: unlock aspect ratio, as per @Defender's suggestion.
@ilovefb2k
Just a quick reaction. It works fine and is the way I am going to use it.
To clarify ... I don't want to stretch the VU meter (BIN or yours) more than either a maximum horizontal scaling or a maximum vertical scaling so I recalculate the VU meter coordinates using these maximum scaling factors. If that means there's either some horizontal or vertical space left I display a bezel around the VU meter, which I don't do with my transparent skin that I made for your script since it doesn't look better. For reference I attached the relevant code for calculating VU coordinates.
I now applied this code also to your script. As you can see your VU meter looks slightly larger than the original BIN. Reason for that is that I slightly cut the original bezel from the BIN before making the remaining bezel transparent.
// plug.x - initial VU panel x-coordinate
// plug.y - initial VU panel y-coordinate
// plug.w - initial VU panel width
// plug.h - initial VU panel height
$ifgreater($get(dbg.vu),0, $puts(dbg1,STEP|1:|plug.xywh=$get(plug.x).$get(plug.y).$get(plug.w).$get(plug.h)) ,)
// VU panel standard settings
$puts(vu.x_fact, 400) // VU default proportion - X
$puts(vu.y_fact, 100) // VU default proportion - Y
$puts(vu.acc, $mul(%on.accent.vu%,%def.accent%)) // VU - Accent padding
$puts(vu.acc_limit, $muldiv(0,%scale%,100)) // Limit to trigger accent padding - 0= Always full on, otherwise either horizontal only or vertical only
// VU panel specific padding
$puts(vu.l_pad, 0) // VU - Left padding
$puts(vu.r_pad, $get(vu.l_pad)) // VU - Right padding
$puts(vu.t_pad, 0) // VU - Top padding
$puts(vu.b_pad, $get(vu.t_pad)) // VU - Bottom padding
// VU panel specific width and scaling settings
$puts(vu.w_min, $muldiv( 250,%scale%,100)) // VU minimum width - when less width available do not display VUmeter
$puts(vu.w_max, $muldiv(10000,%scale%,100)) // VU maximum width - set very high to use full available width
$puts(vu.w_scale, $max(175, 100)) // VU maximum width scale percentage related to original vu dimensions vu.x_fact en vu.y_fact. Minimum value 100
$puts(vu.h_scale, $max(150, 100)) // VU maximum height scale percentage related to original vu dimensions vu.x_fact en vu.y_fact. Minimum value 100
// Calculate initial VU height and width using available width/height and above settings
$puts(vu.w, $sub($min($get(vu.w_max),$get(plug.w)),$get(vu.l_pad),$get(vu.r_pad)))
$puts(vu.h, $sub($get(plug.h),$get(vu.t_pad),$get(vu.b_pad)))
$puts(vu.h, $min($get(vu.h), $muldiv($muldiv($get(vu.w),$get(vu.y_fact),$get(vu.x_fact)), $get(vu.h_scale), 100)))
$puts(vu.w, $min($get(vu.w), $muldiv($muldiv($get(vu.h),$get(vu.x_fact),$get(vu.y_fact)), $get(vu.w_scale), 100)))
// Calculate final VU coordinates adjusted for padding and painted accent
$ifgreater($get(vu.w_min),$get(vu.w),
$puts(vu.w, 0)
,
$puts(vu.y, $add($get(plug.y), $div($sub($get(plug.h),$get(vu.h)),2))) // Vcenter alignment
$puts(vu.x, $add($get(plug.x), $div($sub($get(plug.w),$get(vu.w)),2))) // Hcenter alignment
$ifgreater($get(dbg.vu),0, $puts(dbg2,STEP|2:|||vu.xywh=$get(vu.x).$get(vu.y).$get(vu.w).$get(vu.h)) ,)
// Paint accent and adjust VU coordinates accordingly
$ifgreater($get(vu.acc),0,
$ifgreater($get(vu.acc_limit),0,
$puts(vu.x_pad, $sub($get(vu.x),$get(plug.x)))
$puts(vu.y_pad, $sub($get(vu.y),$get(plug.y)))
$ifgreater($get(vu.acc_limit),$get(vu.x_pad),
$puts(vu.x_pad, 0)
,)
$ifgreater($get(vu.acc_limit),$get(vu.y_pad),
$puts(vu.y_pad, 0)
,)
,
$puts(vu.x_pad, 1)
$puts(vu.y_pad, 1)
)
$ifgreater($add($get(vu.x_pad),$get(vu.y_pad)),0,
// $drawrect($get(vu.x), $get(vu.y), $get(vu.w), $get(vu.h), %cola.at%, %cola.at%)
$puts(i,0)
$ifgreater($get(vu.acc),$get(i), $drawrect($add($get(vu.x),$get(i)), $add($get(vu.y),$get(i)), $sub($get(vu.w),$mul($get(i),2)), $sub($get(vu.h),$mul($get(i),2)), 0-0-0-0, %cola.at%) $puts(i, $add($get(i),1)) ,)
$ifgreater($get(vu.acc),$get(i), $drawrect($add($get(vu.x),$get(i)), $add($get(vu.y),$get(i)), $sub($get(vu.w),$mul($get(i),2)), $sub($get(vu.h),$mul($get(i),2)), 0-0-0-0, %cola.at%) $puts(i, $add($get(i),1)) ,)
$ifgreater($get(vu.x_pad),0,
$puts(vu.x, $add($get(vu.x), $get(vu.acc)))
$puts(vu.w, $sub($get(vu.w), $mul($get(vu.acc),2)))
,)
$ifgreater($get(vu.y_pad),0,
$puts(vu.y, $add($get(vu.y), $get(vu.acc)))
$puts(vu.h, $sub($get(vu.h), $mul($get(vu.acc),2)))
,)
,)
,)
)
$ifgreater($get(dbg.vu),0, $puts(dbg3,STEP|3:|||vu.xywh=$get(vu.x).$get(vu.y).$get(vu.w).$get(vu.h)) ,)
// vu.x - final VU x-coordinate
// vu.y - final VU y-coordinate
// vu.w - final VU width - do not show/display VU panel when value is 0
// vu.h - final VU height
One thing I noticed is that your skin does not look as sharp as the original BIN, which is very noticeable with larger sized VU meters.
Do you use an internal smaller rendered image before rescaling and displaying to the allotted panel?
EDIT: Sorry, just noticed you already mentioned this.
Hi @
Defender,very nice look& feel, you made a clever change to the script.
skin does not look as sharp as the original BIN:
yeah, i noted that also. the script created skin images based on the current panel size and will not look nice if we , even, enlarge the panel size after that. well-noted this.thank you very much.
regards
@ilovefb2k
quick edit ,
please ignore the script in the previous post.
use the attached herein instead.
update: addressing a special case where the needles are horizontal.
regards
This last script does not show a VU meter for me.
hi
@Defender,
if something goes wrong, then i have to revise the script throughout.
this may be last changes has made this script too messy.
thank you,
@ilovefb2k edit:
@Defender : i just have had a quick revise and found nothing illogic. can you hard reset the script to see what is next ?
i may wait for other replies to replicate that errors.
thank you.
hard reset the script
That did the trick. Thx.
very nice look& feel, you made a clever change to the script.
@ilovefb2k In my skin there are 5 different instances of VU BIN you can enable (and now one VU JSP). All are driven by the same scaling code although the bottom ones use slightly different parameters than the upper ones.
Please don't implement my maximum vu.h_scale / vu.w_scale method unless you make it optional.
I have no way of knowing what skin is selected and it's native aspect ratio. I also cannot read Properties. Hence the generic values of vu.x_fact and vu.y_fact instead of the actual x/y of the BIN png in my code. These values work fine for all selected horizontal VU skins, but look awful in vertical and square skins.
Hi there,
In JScript Panel3 samples, there is a VU Meter which is horizontal. Is there a vertical VU meter sample?
Add included vu meter and then paste this additional code in the same panel.
There are no labels. I'm too lazy for that.
function on_paint(gr) {
gr.Clear(colours.background);
if (wh < 1 || ww < 1)
return;
var smooth_mode = properties.meter_style.value == 0;
var bar_width = Math.floor(ww / channels.count);
var bar_height = wh;
if (bar_height != brush.Start[1]) {
brush.Start[1] = bar_height;
brush.End[1] = 0;
if (!solid_colour) {
colours.bar = JSON.stringify(brush);
}
}
if (!smooth_mode) {
var block_count = Math.max(Math.floor(dBrange / properties.rms_block_db.value), 1);
var block_height = bar_height / block_count;
var block_pad = Math.max(Math.ceil(block_height * 0.05), 1);
}
for (var c = 0; c < channels.count; ++c) {
if (RMS_levels[c]) {
var rms_db = _clamp(to_db(RMS_levels[c]) + rms_db_offset, minDB, maxDB);
if (smooth_mode) {
var height = Math.round(bar_height * (rms_db - minDB) / dBrange);
} else {
var blocks = Math.round(block_count * (rms_db - minDB) / dBrange);
var height = blocks * block_height;
}
gr.FillRectangle(bar_width * c, 0, bar_width - 1, wh, colours.bar);
gr.FillRectangle(bar_width * c, 0, bar_width - 1, wh - height, colours.background);
if (!smooth_mode) {
for (var i = 1; i <= blocks; ++i) {
gr.FillRectangle(bar_width * c, wh - height + Math.ceil(block_pad / 2) + (i * block_height), bar_width - 1, block_pad, colours.background);
}
}
}
if (peak_bar_width > 0 && Peak_levels[c] > 0) {
var peak_db = _clamp(to_db(Peak_levels[c]), minDB, maxDB);
if (peak_db > minDB) {
var peak_pos = wh - Math.round(bar_height * (peak_db - minDB) / dBrange);
gr.FillRectangle(bar_width * c, peak_pos, bar_width - 1, peak_bar_width, colours.peak);
}
}
}
}
Oh cool!! Thank you very much
@marc2k3 👍 👍
@boxerfan88
What is the Vertical (Left + Right) VU Meter for AIMP Analog VU Meter? I'd like to try it. Thanks.
@boxerfan88
What is the Vertical (Left + Right) VU Meter for AIMP Analog VU Meter? I'd like to try it. Thanks.
Air Ken he means the vertical version of the JSP3 Sample VU Meter, which can be enabled by adding the script just posted by marc2k3 to the JSP3 Sample VU Meter. The "vertical" version mentioned by ilovefb2k was to add vertical layout option as in foo_vis_vumeter, that is on his 'to do" list I believe.
@sveakul
I see, thank you. My mind is in total panic.
I tried Samples - VU Meter (v). Thanks @marc2k3.
-------
@sveakul
Is DejaVU Compact Calibrated Bright usable?
me again heh still trying with this error
JScript Panel 3.8.0 (AIMP Analog VU Meter v1.0.12 QM 06-11-24 by @case, @marc2003; mod by @ilovefb2k aka viking)
JavaScript compilation error
Unterminated string constant
File: <main>
Line: 92, Col: 63
var aimp_path = "C:\Users\telbo\AppData\Roaming\foobar2000-v2;
It seems that "beat_audio_vu_meter" and Skin folder are not placed correctly. What happened to yesterday's skin folder? You have never responded to our reply about what you did or did not do. It's difficult to cooperate.
\skins\viking\images\vnav_fb2k\beat_audio_vu_meter\
Or is it on purpose? It's done on purpose, it's harassment. You can definitely do this if you reread it.
There's no way that there wouldn't be someone who could upload a screenshot or edit the account in the Browse configuration folder (foobar2000-v2) path to make it invisible.
ok I will all files same place bbs thank you
well that did not work :'(
Please read it again.
Reply #1960: https://hydrogenaud.io/index.php/topic,110516.msg1053745.html#msg1053745
You have never responded to our reply about what you did or did not do. It's difficult to cooperate.
\skins\viking\images\vnav_fb2k\beat_audio_vu_meter\
i don't see this path
\skins\viking\images\vnav_fb2k\beat_audio_vu_mete
do i need to make it
Why don't you review your previous posts?
It's done on purpose, it's harassment. You can definitely do this if you reread it.
Reply #1926: https://hydrogenaud.io/index.php/topic,110516.msg1053632.html#msg1053632
Launch foobar2000. Shift key + menu "File" > Browse configuration folder will open.
The foobar2000-v2 folder will open.
C:\Users\UserName\AppData\Roaming\foobar2000-v2\skins\viking\images\vnav_fb2k\beat_audio_vu_mete
okay i will make the path and read previous post thank you for your time and patience you deserve a medal ;)
Reply #1933: https://hydrogenaud.io/index.php/topic,110516.msg1053647.html#msg1053647
You can now view the AIMP Analog VU Meter Panel. Pop Up shows
-------
@sveakul
Is DejaVU Compact Calibrated Bright usable?
The AIMP version of that BIN, DejaVU Compact LED Calibrated Elemental-mod2.zip, opens in the "1.0.13 DT-K 08-Nov-24" version of the ilovefb2k script, but does not show the top (L) needle or the LEDs. I reported that here and attached the zip as well:
https://hydrogenaud.io/index.php/topic,110516.msg1053665.html#msg1053665 (https://hydrogenaud.io/index.php/topic,110516.msg1053665.html#msg1053665)
I hope ilovefb2k can add support for the design in his next script! BTW, this AIMP version does work just like the BIN version in foo_vis_vumeter.
Is there any real advantage of the JSP3 script VU meter over the recent and terrific re-work of foo_vis_vumeter by oops? With all due respect to ilovefb2k, I did get a meter to show up, but that script is a nightmare.
Is there any real advantage of the JSP3 script VU meter over the recent and terrific re-work of foo_vis_vumeter by oops? With all due respect to ilovefb2k, I did get a meter to show up, but that script is a nightmare.
It runs (with modification) with transparant background and under CUI. So it is promising.
hi @sveakul,
thank you for your feedback. It is just an attempt for us to play around and tune it to suit our specific look & feel. e.g. we may construct ourself a fb2k theme/skin and let this help us in manipulating a VU Meter.
It is in no way can compared with well-coded, beautiful and rich-feature one of @oops' or the 32x version.
hi @Defender,
yeah, you are totally right.
wish you both a nice day.
@ilovefb2k
@ilovefb2kHi.
JSP AIMP analog VU Meter:
context menu > Setting > check setting > FL > FR OK → OK
Is this automatic?
[/spoiler]
Hi @Air KEN and @all,
As per some feedback and suggestions , please find the JSP3 "AIMP Analog VU Meter" update attached, version named "1.0.1 QM 05-11-24" for convenient reference.
This update addresses some points:
- High CPU load.
- Covering some very special cases, which were not easy to find a skin for, but they are there, finally. We also attached some for your quick loading:
+ The needle is upside down. Technically, the y_needle coordinates can be in (>=0) or outside (<0) the background area.
+ The needle is horizontal.
We find it very interesting as, to some extent, we could not think of such skins existing early on. Wow, what creativity from us as an audio lovers community.
On the way back home, I also thought of an option (as per
@Air KEN's feedback of 'check setting'), where we can adjust a little bit the Max/MinLevel to let the needle follow fb2k's audio engine (tweak): push the MaxLevel straight up to +3dB, and pull the MinLevel back to earth at -60dB. This, as my quick observation, has very little impact on the needle movement. But, it is there, so why not give it a try.
Consequently, I am quite confident that this update covers almost 99% of analog/needle (not LED) AIMP VU meter skins as listed here [
https://www.aimp.ru/forum/index.php?topic=52865.0].
As noted, please unzip the attached file to retain the folder structure, then copy them to the root or 'profile' folder of fb2k (or we can make some changes as suggested by @
sveakul https://hydrogenaud.io/index.php?msg=1053489)
Thank you to those who have given us positive and constructive feedback to keep the light going on. I hope this brings you all a little bit more joy.
Important: Please note that this is for look & feel only, not real VU meter. and, the formula is as following:
function dbToAngle(db,c){
var angle= 0;
var scaleAngle = MaxAngle[c] - MinAngle[c]; //symmetric on the VU Meter scale
var ratio = MinAngle[c]/scaleAngle;
ratio = Math.abs(ratio);
// @Black_AVP : May 06, 2016, 15:25:42
// https://www.aimp.ru/forum/index.php?topic=52865.msg325067#msg325067
// adpated for JSP3 DrawImage()
angle = scaleAngle * ( dBToPct(db - MaxLevel[c]) - ratio ) ;
/*/
console.log("aimp VU Meter needle angle:",'db=',db,',angle=',angle);
if (db <= MinLevel) angle = MinAngle;
if (db >= MaxLevel) angle = MaxAngle;
/*/
return angle;
}
function dBToPct(dB){
return Math.pow(10,(dB/20));
}
and those script to adapt AIMP Vu Meter into @marc2003's JSP3 [
now, i have no idea why some text is there]
function AIMP_VU_Meter_seting() {
ww = window.Width;
wh = window.Height;
if (!aimp_skin_check) return;
for (var c = 0; c < channels_count; c++) {
// 1 -- rescale size to retain the ratio as AIMP does. we do not scale VU meter as fb2k does.
// assuming : both left & right panel is equal in height
ww_[c] = (ww - LM)/2, wh_[c]= wh-TM;
var scaleAangle1 = ww_[c]/wh_[c];
if (scaleAangle1 > scaleAangle[c]) ww_[c] = wh_[c]*scaleAangle[c];
else wh_[c] = ww_[c]/scaleAangle[c];
// 2 -- x,y coords scale
x_[c] = LM ; y_[c] = TM ;
if (c >0) {
x_[c]=ww_[c-1]+x_[c-1];
y_[c]=y_[c-1];
// shift the right channel panel towards left if it is wider than left channel panel
if (channel_short.channel == 0) {
x_[c]=ww_[c-1]*channel_short.ratio + x_[c-1];
}
x_[c] --; // 1px to the left to hide the gab between Left and Right panel due to calculation
}
/*/ 3 -- width, height needle scaled : we have to create a needle image, then scale per actual panel size
[+] analog VU Meter:
|-- x_needle > 0:
|-- y_needle > 0:
|-- arrow_dir = other {vertical needle}
|-- arrow_dir = other {horizontal vertical} <== for left panel only
|-- arrow_dir = down
|-- y_needle <= 0:
|-- arrow_dir = down
X|-- arrow_dir = other {not practical!}
|-- x_needle <= 0:
|-- y_needle > 0:
|-- arrow_dir = other {horizon}
X|-- arrow_dir = down {not practical!}
|-- y_needle <= 0:
X|-- arrow_dir = other {not practical!}
X|-- arrow_dir = down {not practical!}
* x_needle : x_needle coords per INI file; y_needle : y_needle coords per INI file; X : Not existed/not practical VU Meter.
/*/
var xs_ = 0,ys_ = 0;
var nxs_= 0,nys_ = 0;
var wws_ =0, whs_= 0;
var nw_ = aimp_needle_img1[c].Width, nh_ = aimp_needle_img1[c].Height;
// 3.1-- analog, x_needle > 0, y_needle > 0, arrow_dir = other {vertical }[0 111]
if (aimp_type.type[c] == 0 && aimp_type.sub_type[c] == 0
&& aimp_type.x_needle_coords[c] == 1 && aimp_type.y_needle_coords[c] == 1
&& aimp_type.arrow_dir[c] ==1 ) {
ws[c] = (ww_[c]/scaleWidth[c])*2; hs[c] = (wh_[c]/scaleHeight[c])*2;
wws_ = ww_[c]; whs_ = wh_[c];
xs_ = 0; ys_ = 0 ;
nxs_ = 0; nys_ = 0;
xn_[c] = x_[c]; yn_[c] = y_[c];
}
// 3.1.1-- analog, x_needle > 0, y_needle > 0, arrow_dir = other {horizon} [0/1 111]
if (c==0 && aimp_type.type[c] == 0 && aimp_type.sub_type[c] == 1
&& aimp_type.x_needle_coords[c] == 1 && aimp_type.y_needle_coords[c] == 1
&& aimp_type.arrow_dir[c] ==1 ) {
ws[c] = (ww_[c] - ww_[c]/scaleWidth[c])*2; hs[c] = (wh_[c]/scaleHeight[c])*2;
wws_ = ww_[c]; whs_ = wh_[c];
xs_ = ws[c]/2-ww_[c]/scaleWidth[c]; ys_ = 0 ;
nxs_ = 0; nys_ = 0;
xn_[c] = x_[c] - ws[c]/2+ww_[c]/scaleWidth[c]; yn_[c] = y_[c];
}
// 3.2-- analog, x_needle <= 0, y_needle > 0, arrow_dir = other {horizon} [0 011]
if (aimp_type.type[c] == 0
&& aimp_type.x_needle_coords[c] == 0 && aimp_type.y_needle_coords[c] == 1
&& aimp_type.arrow_dir[c] ==1 ) {
ws[c] = (ww_[c]+ ww_[c]/scaleWidth[c])*2; hs[c] = (wh_[c]/scaleHeight[c])*2;
wws_ = ww_[c]; whs_ = wh_[c];
xs_ = ws[c]/2+ww_[c]/scaleWidth[c]; ys_ = 0;
nxs_ = 0; nys_ = 0;
xn_[c] = x_[c] - ws[c]/2-ww_[c]/scaleWidth[c]; yn_[c] = y_[c];
}
// 3.3-- analog, x_needle > 0, y_needle <= 0, arrow_dir = down [0 100]
if (aimp_type.type[c] == 0
&& aimp_type.x_needle_coords[c] == 1 && aimp_type.y_needle_coords[c] == 0
&& aimp_type.arrow_dir[c] == 0 ) {
ws[c] = (ww_[c]/scaleWidth[c])*2; hs[c]= (wh_[c]+ wh_[c]/scaleHeight[c] ) *2 ;
wws_ = ww_[c]; whs_ = wh_[c];
xs_ = 0; ys_ = wh_[c] + 2*wh_[c]/scaleHeight[c];
nxs_ = 0; nys_ = 0;
xn_[c] = x_[c]; yn_[c]= y_[c]- ys_;
}
// 3.4-- analog, x_needle > 0, y_needle > 0, arrow_dir = down [0 110]
if (aimp_type.type[c] == 0
&& aimp_type.x_needle_coords[c] == 1 && aimp_type.y_needle_coords[c] == 1
&& aimp_type.arrow_dir[c] == 0 ) {
ws[c] = (ww_[c]/scaleWidth[c])*2; hs[c] = (wh_[c] - wh_[c]/scaleHeight[c] ) *2 ;
wws_ = ww_[c]; whs_ = hs[c]/2;
xs_ = 0; ys_ = hs[c]/2;
nxs_ = 0; nys_ = aimp_needle_img1[c].Height/scaleHeight[c]
xn_[c] = x_[c]; yn_[c] = y_[c]-hs[c]/2 + wh_[c]/scaleHeight[c];
}
// 4-- needle scaled
// aimp_needle_img
if (aimp_needle_img[c]) aimp_needle_img[c].Dispose();
aimp_needle_img[c] = utils.CreateImage( ws[c], hs[c] );
var gb = aimp_needle_img[c].GetGraphics();
gb.DrawImage(aimp_needle_img1[c],
xs_,ys_,wws_,whs_,
nxs_,nys_,nw_,nh_);
aimp_needle_img[c].ReleaseGraphics(); gb = null;
// aimp_needle_peak_img
if (aimp_needle_peak_img[c]) aimp_needle_peak_img[c].Dispose();
aimp_needle_peak_img[c] = utils.CreateImage(ws[c], hs[c]);
var gb = aimp_needle_peak_img[c].GetGraphics();
gb.DrawImage(aimp_needle_peak_img1[c],
xs_,ys_,wws_,whs_,
nxs_,nys_,nw_,nh_);
aimp_needle_peak_img[c].ReleaseGraphics(); gb = null;
// aimp_needle_peak_peak_img
if (aimp_needle_peak_peak_img[c]) aimp_needle_peak_peak_img[c].Dispose();
aimp_needle_peak_peak_img[c] = utils.CreateImage(ws[c], hs[c]);
var gb = aimp_needle_peak_peak_img[c].GetGraphics();
gb.DrawImage(aimp_needle_peak_peak_img1[c],
xs_,ys_,wws_,whs_,
nxs_,nys_,nw_,nh_);
aimp_needle_peak_peak_img[c].ReleaseGraphics(); gb = null;
}
/*/ for testing only
window.MaxWidth = window.MinWidth = LM+aimp_needle_img1[c].Width*2;
window.MaxHeight = window.MinHeight = TM+aimp_needle_img1[c].Height;
/*/
}
due to my limited-resource, i am sorry in advance for later reply, if any.
And now, I have to rush for a 4P pizza as my lovely wife is right behind me.
Regards,
@ilovefb2k
Hi @Defender , @sveakul, @Air KEN and @all,
A week has gone by too fast, like the wind. Please find the updated JSP3 'AIMP Analog VU Meter' script attached, named version '1.0.13 DT-K 08-Nov-24' for convenient reference, details as following:
Just one feature was added: unlock aspect ratio, as per @Defender's suggestion.
A free night weekend allowed me to play around with this feature, which I also think is a must-try if we want the script to move on to 'animation' VU Meters, which contain pre-calculated data/images per needle angle.
Please note that once this option is on, CPU load may be boosted up to Mars and won't come back, so fasten your computer's belt for a safe trip.
What happens behind the scenes:
The script will create around 200 x 2 channels = 400 needle images (we may tune this number per the hard-coded variable stepCache, for now), which are number of screenshots of needles per angle along the meter range, then load them into 'heap' memory. We will instantly note an increase in RAM consumption in less than 1 second, then it will return to normal.
Later on, we just retrieve each needle image by its index-converted angle as real-time calculated.
To do this, we have to do a trick, just jotting it down here for those who want to make it better:
-Step 1: Allocate memory for hundreds of images.
-Step 2: Draw needles, 1 needle per 1 image, per 1 angle. This takes about 1 ms each.
-Step 3: Garbage collection. As we allocate stack memory, we have to clear it ourselves or soon end up crashing. This will also take more than 1 ms each, which is time-consuming.
So, we have to make an async task, which will transfer the clearance job (step 3) to another thread, and we can move on. In principle, we can reuse some async methods of JSP3 to do this job in a very 'strange' manner. For example:
fb.AddLocationsAsync(window_id, [""]);
on_locations_added(task_id, handle_list) { do clearing job, which is not related to this native function}
Or, simply, leave this mess for window.SetTimeout({do clearing job}, 1)
=> We move on, and this method, on another thread, will do the clearing job after 1 ms and not bother us.
As such, we will experience a frozen-screen instance (not core audio engine) for a very short time. To save CPU power, just do this one time per current panel size until we move to another skin. Consequently, the resolution will not be nice if we enlarge the panel size, or we will have to switch forward and back just 1 skin to update the needle images caching for the current panel size.
If something seems wrong (e.g. needles are not on show), then a 'hard reset' via context menu [shift +right click] will bring back default setting and may help.
And that is all. Wish you all the very best and a very nice weekend.
Regards,
@ilovefb2k
quick edit ,
please ignore the script in the previous post.
use the attached herein instead.
update: addressing a special case where the needles are horizontal.
regards
@ilovefb2k
I wonder if you could add the ability to display the left or right channel separately in the script? Thank you!
@sveakul
Thank you. I've already tried it. I really hope that happens because I like that skin too.
okay here's what I done uninstalling foobar and delete foobar v2 from appdata
reinstall foobar 32bit
i extracted the aimp vu skins folder in my foobar v2 on my appdata
installed jssript3 on ul
made a beat_audio_vu_meterbeat_audio_vu_meter on my c drive and used this script
hope you understand and can help
hope you understand and can help
Sorry, but help with WHAT? If it's only with adding the AIMP Analog VU Meter from ilovefb2k, all that requires is adding the JSP3 plugin (foo_uie__jsplitter not required), then a new panel with JSP-3 as the element using Layout Editing Mode (https://wiki.hydrogenaud.io/index.php?title=Foobar2000:Layout_Editing_Mode), and hitting click to get the "configuration" window. At that window, click the "Tools" button, and then "Import" the AIMP Analog VU Meter script you attached (only why not use the newest version instead posted here) (https://hydrogenaud.io/index.php?action=dlattach;topic=110516.0;attach=33487) .
In the meter script itself, before you Import it make a folder on your PC C:\meters\beat_audio_vu_meter, and change the text file in line 95 from:
var aimp_path = fb.ProfilePath + "skins\\viking\\images\\vnav_fb2k\\beat_audio_vu_meter\\";
to:
var aimp_path = c:\\meters\\beat_audio_vu_meter\\";
And put all your AIMP skins in that folder--actually you can make that path anything, but keep "beat_audio_vu_meter" as the name of the folder with the skins in it.
That's it. Choose a skin and settings from the configuration menu (right-click) in the panel you made. If you don't "get" this I give up, especially considering the help others have already tried to give.
With all due respect, and bearing in mind I know nothing about this, it seems confusing that you have given your instructions out of order ("before you import it..."), especially since the inquirer is clearly not best fluent in English. From what I can see, he has not been given clear, simple, step-by-step, self-contained instructions. I appreciate he is not clear in what he wants to do, but the experienced ones should be able to infer.
Eliminated the confusion by wiping the slate clean. Detail the steps needed to start with a fresh FB2K install add the VU meter panel to it, with only one action per step.
Many other "experienced ones" have attempted it, I've thrown mine in too. Why not you give it a shot? What step do you start at when there's no clear indication of if he even understands file and path terminology?
A no-shade suggestion to the OP is that if if he just wants to add a VU meter he might find it easier to just install the wonderful foo_vis_vumeter plugin by oops following the published steps.
Currently there are 3 methods afaik of displaying VU meters with needles in fooBar:
1) Original foo_vis_vumeter 2013-02-16, runs in DUI/CUI, but only 32bit. Supports lamps/lights. Does not support transparency. Has needle adjustment by mousewheel.
2) New foo_vis_vumeter by oops, runs in 32bit and 64bit, but only DUI, which is quite unfortunate.
3) JSP3 script by ilovefb2k, that runs AIMP meters in 32bit and 64bit, but only available for windows if I'm correct. Supports transparency. Does currently not support lamps/lights and needle adjustment by mousewheel. Current version supports unlock aspect ratio, but is buggy.
I know it is work in progress, but currently it's quite tedious to modify the parameters of an AIMP style VU meter for the JSP3 script. It's quite easy though to create with VU Editor a BIN from the unmodified AIMP sources that can be run with foo_vis_vumeter with (added) lights/lamps.
I experimented a bit by porting an AIMP style VU meter I made to original foo_vis_vumeter style BIN files using VU Editor. I created two different versions, one transparent and one opaque, both using a red needle and red lamps/lights.
The opaque one looks fine (just as the original with red needle/light), but the transparent one looks ugly probably because the original foo_vis_vumeter does not handle transparency. Screenshot attached with an upper large transparent JSP3 meter and a lower transparent BIN meter, with an ugly presentation of the transparent area.
I cannot test the new foo_vis_vumeter by oops since I'm running DUI.
Can someone verify what happens when the transparent BIN is loaded in the new component?
Thx.
@Defender
VU Meter Visualisation 0.5.2-rc (foo_vis_vumeter) 2024-11-07
foobar2000 core 2.24 preview 2024-11-06 x64
(https://i.imgur.com/P9ysBpo.png)
I tried displaying it on the VU Meter Visualisation (foo_vis_vumeter) Panel.
Is this all that's needed?
It's the same as the @Defender image, and has beautiful transparency.
I loaded 7inch_3 - defender.vu in VUEditorGUI and changed the needle to needle original.png (Because it might be useful later).
@Defender
I loaded 7inch_3 - defender.vu in VUEditorGUI and changed the needle to needle original.png (Because it might be useful later).
That's why I included the original needle and recreated white light/lamp :-)
VU Meter Visualisation 0.5.2-rc (foo_vis_vumeter) 2024-11-07
foobar2000 core 2.24 preview 2024-11-06
(https://i.imgur.com/P9ysBpo.png)
I tried displaying it on the VU Meter Visualisation (foo_vis_vumeter) Panel.
Is this all that's needed?
It's the same as the @Defender image, and has beautiful transparency.
I'm not sure about your picture. It displays the transparent parts as a grey checker board. That's also what the original foo_vis_vumeter does. It should show painted background/art it is displayed upon.
I attached a new screenshot where the background is first painted with a reddish gradient before the the JSP3 and foo_vis_vumeter VU meters are displayed.
The upper one is the JSP3 version which is correctly displayed. The lower one is the BIN version which overwrites the background with the checkerboard where it should be the same background as the upper one.
> I'm not sure about your picture. It displays the transparent parts as a grey checker board. That's also what the original foo_vis_vumeter does. It should show painted background/art it is displayed upon.
I simply made a panel out of foo_vis_vumeter.
> It displays the transparent parts as a grey checker board.
Yes. It remains transparent.
> It displays the transparent parts as a grey checker board.
Yes. It remains transparent.
In your picture I see the grey checkerboard, not the original background of the underlying panel.
Anyway, thx.
Yes, that's right. It's been panelized like this.
(https://i.imgur.com/R0aBc0e.png)
Yes, that's right. It's been panelized like this.
Thank you for confirming. Which means only the JSP3 script handles transperency correctly.
Yes, that's right. It's been panelized like this.
Thank you for confirming. Which means only the JSP3 script handles transperency correctly.
@Air KEN Follow-up. I don't like the grey checkerboard and also not the larger gap between the left & right VU meter, so I recompiled an imo nice looking variant with a smaller gap between L and R VU meter which uses separates BIN's for Left and for Right and a gradient that fits in my skin.
You might want to give it a try. Compiled versions and sourcefiles included in the attachment in case you want to change the red needle or red lamp/light.
Announcement of the Results:
7inch_3
(https://i.imgur.com/grnniCa.png)
7inch_3 - transparent red 7inch_3 - transparent red LR
(https://i.imgur.com/XwtuApS.png) (https://i.imgur.com/iv5SAWc.png)
7inch_3 - opaque red 7inch_3 - opaque LR
(https://i.imgur.com/nhlkO8l.png) (https://i.imgur.com/Q5rUeGw.png)
7inch_3 - gradient red 7inch_3 - gradient red LR
(https://i.imgur.com/A53cXZr.png) (https://i.imgur.com/05okQUk.png)
Announcement of the Results
LOL. I get the picture(s) :-)
I personally have not decided yet whether I prefer the original dark needle or the red one. I definitely like the red light/lamp more than the original white one.
Here are some more minimalistic versions of the gradient smaller bezel version.
I call it a day now until
@ilovefb2k comes with a new version of his script.
I wonder if you could add the ability to display the left or right channel separately in the script? Thank you!
hi
@sq68,
well-noted,
thank you for your suggestion.
@ilovefb2k
very nice look& feel, you made a clever change to the script.
@ilovefb2k
In my skin there are 5 different instances of VU BIN you can enable (and now one VU JSP). All are driven by the same scaling code although the bottom ones use slightly different parameters than the upper ones.
Please don't implement my maximum vu.h_scale / vu.w_scale method unless you make it optional.
I have no way of knowing what skin is selected and it's native aspect ratio. I also cannot read Properties. Hence the generic values of vu.x_fact and vu.y_fact instead of the actual x/y of the BIN png in my code. These values work fine for all selected horizontal VU skins, but look awful in vertical and square skins.
hi @
Defender,
wow, you have gone so fast.
masterpiece is not easy to take but worth trying.
i may stay back behind to finish the puzzle.
wish you nothing but a very happy life.
@ilovefb2k
@ilovefb2k : with your next AIMP Analog VU Meter script, is there any chance of adding:
1. Vertical layout for separate L/R meters?
2. Support for non-LVU AIMP analog skins that have "LEDs" and dual needles? (skin attached)
hi @
sveakul and @
all,
as per
@sveakul's suggestions, please find the attached script that was updated with this feature, named version after
1.0.14 DT-L 14-Nov-24 for easy reference.
i may take a nap and try to finish the puzzle by adding LVU as noted in the script.
hope this may bring a little joy to our life.
wish you all the best.
note: we attached the
@sveakul's VU Meter skin for convenience.
@ilovefb2k
That's amazing. Your script continues to evolve.
.my effort
@telboy1812
Are you talking about Analog VU Meter Visualisation (foo_vis_vumeter)?
AIMP Analog VU Meter is a JSP3 Script and is not the subject of this thread.
Then check the whole process before posting.
To use Analog VU Meter Visualisation (foo_vis_vumeter), simply place the vumeter folder and make it into a panel.
To use the AIMP Analog VU Meter, all you need to do is place the skin folder, prepare a JSP3 panel, and load the Script file (.txt).
The use and placement of JSP3 scripts, and the foo_vis_vumeter are much neater than in the previous screenshot. The previous interaction looks unnatural.
as per @sveakul's suggestions, please find the attached script that was updated with this feature, named version after 1.0.14 DT-L 14-Nov-24 for easy reference.
Thanks ilovefb2k for the script with the new "infinite" alignment options :o !
I noticed two issues with the DejaVu skin:
1. At lower levels, the bottom of the needles protrude slightly from the top and bottom of the main body; see Image #1
2. When "LED Level" is set to "Follow RMS" it works fine, needles and LED follow RMS together. But when set to "Follow Peak", the LEDs have a way too slow decay rate, resulting in being maxed out most of the time instead of accurately following the audio peak changes. GIF #2 is attached so you can get an idea of the LED Peak speed--it starts with pop music, which keeps the LEDs inaccurately pinned to Peak; then I change to classical so you can get an idea of the LED change rates--the Rise level is fine, but Decay is too slow.
Thanks for your work!
hi ken i am no good at writing scripts mine seem to be .bin in a folder in the foobar configuration when I right click the vu meter select growing these vu meters are available to me
? ? ?
This is about VU meter visualization (foo_vis_vumeter), please move it to another thread.
sorry
sorry
Yeah sure.
no text display + buttons :(
Create a new JSP3 panel. Click on configuraion - Choose samples
i don't want the albumart
as per @sveakul's suggestions, please find the attached script that was updated with this feature, named version after 1.0.14 DT-L 14-Nov-24 for easy reference.
Thanks ilovefb2k for the script with the new "infinite" alignment options :o !
I noticed two issues with the DejaVu skin:
1. At lower levels, the bottom of the needles protrude slightly from the top and bottom of the main body; see Image #1
2. When "LED Level" is set to "Follow RMS" it works fine, needles and LED follow RMS together. But when set to "Follow Peak", the LEDs have a way too slow decay rate, resulting in being maxed out most of the time instead of accurately following the audio peak changes. GIF #2 is attached so you can get an idea of the LED Peak speed--it starts with pop music, which keeps the LEDs inaccurately pinned to Peak; then I change to classical so you can get an idea of the LED change rates--the Rise level is fine, but Decay is too slow.
Thanks for your work!
hi @
sveakul,
just a quick reply as follows:
1. the bottom of the needles protrude slightly from the top and bottom :
This , in principal, can be hidden by maximize the meter. however, as i do not totally understand the algorithm / formula behind the scene then we just leave them there. this is absolutely annoying. well-noted.2. LEDs have a way too slow decay rate:
turn on the 'tweak' option to have fb2k's signal dominated may help. i will let the LED freely follow the signal.regards,
@ilovefb2k
That's amazing. Your script continues to evolve.
Hi @
Air KEN, @
sveakul, @
Defender and @
all,
Another weekend is coming, friYAY!!
Week by week, month by month, and just one left to reach Christmas and year-end eve. So fast.
Please find the attached script, with the last puzzle of the
AIMP Analog VU Meter deployed, version named
1.0.16 DT-M 16-Nov-24 for easy reference: AIMP LED VU Meter (
LVU) is supported.
As such, we should have a quick review:
-
Features:
+ Load AIMP VU meter
+ Free allocation in panel
+ Easy tuning
-
AIMP VU Meter types covered:
+Analog NEEDLE only (not analog LED) => vertical/horizontal needle, up/down needle arrow, >< V & /\ needle shape.
*Type 1: 1 image set for both channels
*Type 2: 2 image sets, each for each channel.
+ LED (LVU): vertical/horizontal bar
-
How to:
+Download AIMP VU Meter skin file, e.g.:
* analog NEEDLE :
https://www.aimp.ru/forum/index.php?topic=52865.0 * LED (Led VU) :
https://www.aimp.ru/forum/index.php?topic=54005 + Unzip the AIMP VU Meter skin into a folder and copy this [folder] to the specific directory as indicated by this script.
+ Load this script into a JSP3 /UI/ panel
Or follow @sveakul's instruction
https://hydrogenaud.io/index.php/topic,110516.msg1053636.html#msg1053636-
Limitations:
+ Options: MobilityNegative, MobilityPositive > could not take MobilityPositive into account.
+ Meter range (in the skin) is quite inaccurate.
+ Fb2k's VU Meter skins are currently not supported.
Note: Refer to fb2k, @oops's, Analog VU Meter Visualisation/foo_vis_vumeter component for a complete, rich-feature, well-tuning and bug-free
https://www.foobar2000.org/components/view/foo_vis_vumeter-
Credit and acknowledgment:
+ @
Case and @
marc2003 for their JSP3 VU Meter.
+ @
Artem and contributors /AIMP VU Meter - analog NEEDLE/ for their beautiful analog VU Meters.
+ @
xrEngine and contributors /AIMP VU Meter - LED/ for their elegant LED VU Meters.
Please note that this "AIMP Analog VU Meter" is just for
look & feel/eye-candy only, and to some extent, to humbly serve as a starting point for us all to tailor or play around with JSP3 VU meter. As such, we would like to expect this to be utilized and, of course, evolved to cover fb2k's VU Meter skins (BIN).
Again, thank you @all, especially @Air KEN, @sveakul, and
@Defender, for their valuable suggestions and positive feedback.
Wish you all a very nice weekend.
Regards,
@ilovefb2k
AIMP Analog VU Meter deployed, version named 1.0.16 DT-M 16-Nov-24
@ilovefb2k
Thanks for actively developing this script.
I like transparency and since the original foo_vis_vumeter does not support it and the new foo_vis_vumeter is DUI only/not transparent, your script is the only way to use this nice feature properly.
Nice you mention features, how to and limitations with new versions in your post, but could you also include a todo and version changes in the post. Especially the last one would be an improvement for me, since I then know what to test. Maybe also an idea to include the version name in the attached source rar itself?
I currently use:
fooBar 2.24 preview 2024-11-14 x86 - CUI/PSS 790MB typical memory usage
AIMP Analog VU Meter 1.0.16 DT-M 16-Nov-24
I did some testing on your current version:
ALIGNMENT:
I noticed in this version that the quality of the upscaled displayed image in all modes is now the same as foo_vis_vumeter.
All good except for the needle stuff mentioned below.
BTW. The original foo_vis_vumeter also has a mono choice besides only left and only right. It combines/adds L+R signals before using the left vu meter to display the results.
MEMORY USAGE:
When using any of the H and C scalings except H:Maximize and switching between them your script hardly uses any extra memory. All of these scalings however display part of the needle below L_0 & R_0 (and L_2 & R_2). Only H:Bottom looks fine because it probably paints the lower part of the needle outside of the panel.
The moment you switch to H:Maximize or any of the V and R scalings the needle is displayed correctly within image boundaries.
However memory uses goes up by a lot. Lowest value I have seen is +400MB, but sometimes it goes up by +1000MB. CPU usage stays low.
Any switch in scaling you do after you selected a high memory scaling, keeps the memory at those elevated levels even when playing stops or plugin is not displayed.
I also encountered some very infrequent freak spikes up to +2000MB while testing before fooBar became unstable and had to be killed.
NEEDLE CALIBRATION/MINIMAL ANGLE:
You mention easy tuning in your post. I still struggle a whole lot by trial and error to calibrate the position of the needle and the length of the needle. In the end I find the minimal angle (and maximum angle=-minimum angle). But the needle is a whole lot shorter when reaching the maximum value. Looks ok'ish at best. I hoped that the VU editor I use for making BIN's could provide me with values to use within the skin.ini file, but those values don't work.
How do you easy tune the needle? What tools do you have available?
While not playing I calibrate (by a lot of trial and error) the needle angle and position with one of the H:scalings (not H:Maximize), so the aspect ratio is the same of te L_0 & R_0 dimensions. Works fine when not playing and switching to any of the other H/C scalings except H:Maximize.
The moment I switch to H:Maximize or V/R scalings when not playing the needle moves from the position I calibrated to a slightly different position. Apparently in these modes the value is corrected by the value of PROPERTY HA.RMS.gain (dB). Can you disable this behavior so that the needle stays at 0 also in these scaling modes when not playing?
NEEDLE MOVEMENT:
In PROPERTIES you can set HA.RMS.gain (dB) which alters the movement of the needle. In foo_vis_vumeter this value is dynamic and can be changed by using the mouse scrollwheel.
I noticed that your script does not have a on_mouse_wheel(s) callback.
Can this be added so that you can also dynamically adjust the value of HA.RMS.gain (dB) PROPERTY in your script?
LAMP/LIGHT:
With VU Editor you can add a light/lamp overlay (with has the same dimensions as L_0 & R_0), that starts to be displayed as an overlay from a certain peak level to a maximum with increasing opaqueness. I use two knots in VU Editor values +0,0% and +4,100% with linear scale in between.
Can this be implemented in your script by adding the lights as L_3 & R_3 with PROPERTIES such as lowlight_dB, lowlight_perc and highlight_dB, highlight_perc?
I attached current version of my transparent AIMP style skin (red needles) with proposed lamp/light overlays included. Also a gradient BIN style (black needles) with red light/lamp. Also a small video with both VU meters running and show the light/lamp on the BIN.
@Defender : thanks you for such a detailed report/commentary on the newest ilovefb2k script, much appreciated! Was disappointed to hear about the spread of the needle bottom protrusions and the memory spikes on certain scalings (yikes!). I'm sure lovefb2k will be working on those. I was happy to hear about the increased quality of the upscaled meter image though. I didn't know about the use of the HA.RMS setting in Properties, thanks to you I will be experimenting with that.
@ilovefb2k : thanks for the new revision, haven't even loaded it yet but need to get some sleep first, haha.. Can't wait to try out the new addition of the LVU format, lots of cool designs available there!!
@sveakul
Awaiting an answer by @ilovefb2k about finding optimal PivotPoint and needle length, I had a "bright" idea. VU Editor does the job perfectly with the provided needle of it's project. So basically I am now using the information from the saved VU Editor project to find the values to use in skin.ini.
Method:
0.) Use VU Editor to create a project based on back L_0, needle and glass L_2, finding correct angles and offsets for current needle. Save project.
1.) Take original needle. Change canvas width to width of L_0, keeping the needle dead center and the height to the original height of the needle. Save as L_1.
2.) Set MinAngle and MaxAngle in skin.ini to the ones that are found in the saved VU Editor project (which is a textfile).
3.) Set MinLevel to -60 (not -22) and MaxLevel to +4.
4.) Set PivotPointX to the width of L_0 divided by 2.
5.) Load the skin while not playing and scaling set to H:Center (important), because of the HA.RMS.gain (dB) display bug.
6.) Use trial and error to find the correct PivotPointY where the needle goes straight through MinLevel. Do not change the angle which is already correct.
7.) When found, make the needle shorter to your liking by shifting it down keeping the containing canvas at the same dimensions.
8.) As a result the needle when playing will have the same length at MaxLevel as it has at MinLevel.
9.) Finding ZeroAngle at ZeroLevel=0 is a bit hard since fooBar cannot be playing when you want to find the correct angle. So I abuse MinAngle temporarily for that. You also cannot enter a positive angle. First I use magnifier to have the full left VU Meter as large as possible on the screen. Then I measure the distance between +0 and +4 (MaxLevel) with a ruler. Now change MinAngle so that the distance between the original MinLevel point is the same as distance between +0 and +4. When the angle is found use the absolute value of this found (negative) angle as ZeroAngle and reset MinAngle to the original value from VU Editor.
The check settings within rightclick on the JSP3 panel don't give me any values I can actually use.
For reference I added the skin build by using the above. In skin.ini I also included the text of the VU Editor project.
NB. I like the eye candy of a nice moving needle. I have ReplayGain on, peak needle is disabled and PROPERTY HA.RMS.gain (dB) is set to 19. Resulting red needles are similar to the black ones I have in the BIN, but a bit more nervous. Tempering with PROPERTIES HA.RMS.decay.Overridden or the MobilityNegative in skin.ini have no effect.
@ilovefb2k : Some things noticed first try with the "1.0.16 DT-M 16-Nov-24" script", DUI, Foobar 2.24 x64 :
1. If an LVU meter is loaded first, or is switched to from an AIMP meter, it works fine. If you then try to switch back to LVU from the AIMP meter, you end up with a white empty space, and cannot then change to any meter. Only a restart of Foobar temporarily fixes it, but behavior immediately reverts.
2. Whenever playback begins with a meter active, a file "~JSP_AIMP_VU_Meter_temp.ini" file is created in the beat_audio_vu_meter skins folder with the contents of:
[error]
number=0
3. Is there a setting that functions the same way as "var peak_hold = 10; // in frames" does in the JSP3 Sample VU Meter?
AIMP Analog VU Meter deployed, version named 1.0.16 DT-M 16-Nov-24
@ilovefb2k
Thanks for actively developing this script.
I like transparency and since the original foo_vis_vumeter does not support it and the new foo_vis_vumeter is DUI only/not transparent, your script is the only way to use this nice feature properly.
Nice you mention features, how to and limitations with new versions in your post, but could you also include a todo and version changes in the post. Especially the last one would be an improvement for me, since I then know what to test. Maybe also an idea to include the version name in the attached source rar itself?
I currently use:
fooBar 2.24 preview 2024-11-14 x86 - CUI/PSS 790MB typical memory usage
AIMP Analog VU Meter 1.0.16 DT-M 16-Nov-24
I did some testing on your current version:
ALIGNMENT:
I noticed in this version that the quality of the upscaled displayed image in all modes is now the same as foo_vis_vumeter.
All good except for the needle stuff mentioned below.
BTW. The original foo_vis_vumeter also has a mono choice besides only left and only right. It combines/adds L+R signals before using the left vu meter to display the results.
MEMORY USAGE:
When using any of the H and C scalings except H:Maximize and switching between them your script hardly uses any extra memory. All of these scalings however display part of the needle below L_0 & R_0 (and L_2 & R_2). Only H:Bottom looks fine because it probably paints the lower part of the needle outside of the panel.
The moment you switch to H:Maximize or any of the V and R scalings the needle is displayed correctly within image boundaries.
However memory uses goes up by a lot. Lowest value I have seen is +400MB, but sometimes it goes up by +1000MB. CPU usage stays low.
Any switch in scaling you do after you selected a high memory scaling, keeps the memory at those elevated levels even when playing stops or plugin is not displayed.
I also encountered some very infrequent freak spikes up to +2000MB while testing before fooBar became unstable and had to be killed.
NEEDLE CALIBRATION/MINIMAL ANGLE:
You mention easy tuning in your post. I still struggle a whole lot by trial and error to calibrate the position of the needle and the length of the needle. In the end I find the minimal angle (and maximum angle=-minimum angle). But the needle is a whole lot shorter when reaching the maximum value. Looks ok'ish at best. I hoped that the VU editor I use for making BIN's could provide me with values to use within the skin.ini file, but those values don't work.
How do you easy tune the needle? What tools do you have available?
While not playing I calibrate (by a lot of trial and error) the needle angle and position with one of the H:scalings (not H:Maximize), so the aspect ratio is the same of te L_0 & R_0 dimensions. Works fine when not playing and switching to any of the other H/C scalings except H:Maximize.
The moment I switch to H:Maximize or V/R scalings when not playing the needle moves from the position I calibrated to a slightly different position. Apparently in these modes the value is corrected by the value of PROPERTY HA.RMS.gain (dB). Can you disable this behavior so that the needle stays at 0 also in these scaling modes when not playing?
NEEDLE MOVEMENT:
In PROPERTIES you can set HA.RMS.gain (dB) which alters the movement of the needle. In foo_vis_vumeter this value is dynamic and can be changed by using the mouse scrollwheel.
I noticed that your script does not have a on_mouse_wheel(s) callback.
Can this be added so that you can also dynamically adjust the value of HA.RMS.gain (dB) PROPERTY in your script?
LAMP/LIGHT:
With VU Editor you can add a light/lamp overlay (with has the same dimensions as L_0 & R_0), that starts to be displayed as an overlay from a certain peak level to a maximum with increasing opaqueness. I use two knots in VU Editor values +0,0% and +4,100% with linear scale in between.
Can this be implemented in your script by adding the lights as L_3 & R_3 with PROPERTIES such as lowlight_dB, lowlight_perc and highlight_dB, highlight_perc?
I attached current version of my transparent AIMP style skin (red needles) with proposed lamp/light overlays included. Also a gradient BIN style (black needles) with red light/lamp. Also a small video with both VU meters running and show the light/lamp on the BIN.
hi @
Defender,
thank you very much for your very detail feedback, in terms of the script's functionality and performance.
I reckoned, playing around with this VU meter is as playing a game of tradeoffs. not to mention my limited knowledge of VU meter.
1. ALIGNMENT: well-noted.
2. MEMORY USAGE : as @marc2003 has just introduced IJSBitmap interface
https://jscript-panel.github.io/docs/interfaces/IJSBitmap/ along with JSP3 3.8.4
https://jscript-panel.github.io/docs/changes/#384, we will apply this and make some refactoring to see any improvement.
3. NEEDLE CALIBRATION/MINIMAL ANGLE:
How do you easy tune the needle? What tools do you have available?I completely have no idea about this. 'easy tuning' means playing around with aligning only.
as such, please accept my apology for giving a text that is not clear meaning. i will remove that text and consider have it back when we can enable such truly useful tuning as this vague feature: there may be a VU Meter, where the wallpaper is none, the background is transparent but meter range. then, the script can change the background/needle color, draw the meter range .
3. NEEDLE MOVEMENT: well - noted.
4. LAMP/LIGHT: well-noted.
best regards,
@ilovefb2k
@ilovefb2k : Some things noticed first try with the "1.0.16 DT-M 16-Nov-24" script", DUI, Foobar 2.24 x64 :
1. If an LVU meter is loaded first, or is switched to from an AIMP meter, it works fine. If you then try to switch back to LVU from the AIMP meter, you end up with a white empty space, and cannot then change to any meter. Only a restart of Foobar temporarily fixes it, but behavior immediately reverts.
2. Whenever playback begins with a meter active, a file "~JSP_AIMP_VU_Meter_temp.ini" file is created in the beat_audio_vu_meter skins folder with the contents of:
[error]
number=0
3. Is there a setting that functions the same way as "var peak_hold = 10; // in frames" does in the JSP3 Sample VU Meter?
hi @
sveakul ,
thank you for your feedback,
well-noted.
1- we will have that bug (1) cleared next round.
2 - that file is for error manipulation on purpose.
3- var peak_hold = 10 : can you shed me a light on what you are after ? we can have this back or make it as an option.
regards
@ilovefb2k
3. NEEDLE CALIBRATION/MINIMAL ANGLE:
How do you easy tune the needle? What tools do you have available?
I completely have no idea about this. 'easy tuning' means playing around with aligning only.
as such, please accept my apology for giving a text that is not clear meaning. i will remove that text and consider have it back when we can enable such truly useful tuning as this vague feature: there may be a VU Meter, where the wallpaper is none, the background is transparent but meter range. then, the script can change the background/needle color, draw the meter range .
@ilovefb2k Such a tool already exists in the existent VU Editor.
Because of current incompatibility between skin.ini and BIN project files you have to do a lot of tedious transformations by hand/eye in the needle png, adjusting length and finding of PivotPointY. See my previous post about this process and particularly the attached skin.ini.
https://hydrogenaud.io/index.php/topic,110516.msg1054186.html#msg1054186
Instead of putting effort in writing your own VU Editor for this JSP3 script, it might be a better approach to make this script compatible with and accept the values from the existing VU Editor project files as is.
EDIT: I'm pretty sure the compiled BIN files hold no magic. It just contains the L_0, L_2 and L_3 files as is and a number of prerendered (anglecount) needle png's rendered to the same dimensions as L_0. Therefore there's hardly a performance impact on CPU and memory displaying/scaling a running BIN VUmeter. The only thing needed is a decent scaling/rendering engine supporting alpha and brightness, such as JSP3 already has.
3. Is there a setting that functions the same way as "var peak_hold = 10; // in frames" does in the JSP3 Sample VU Meter?
hi @sveakul ,
thank you for your feedback,
3- var peak_hold = 10 : can you shed me a light on what you are after ? we can have this back or make it as an option.
@ilovefb2k
I thought it might help visually with the extremely slow decay rate of LEDs when "LED follows Peak" is selected. On the JSP3 bar meters it controls how long the peak line holds before beginning the decay of the line. May or may not be relevant here but maybe worth an optional inclusion. Just to clarify, the NEEDLE meter decay rate has always looked fine, but I assume that RMS is what is being used by default with AIMP meters?
Does anyone have a working last.fm love button script? Thanks in advance.
@Jacob91 As requested a working "Text Display + Album Art + Seekbar + Buttons, added Art mousewheel, ReplayGain button and rightclicks" script for JSP3 3.8.5.
EDIT: Needs the cui-configs.rar with stub images to be extracted in the foobar roaming folder, if not already present.
@Jacob91
As requested a working "Text Display + Album Art + Seekbar + Buttons, added Art mousewheel, ReplayGain button and rightclicks" script for JSP3 3.8.5.
EDIT: Needs the cui-configs.rar with stub images to be extracted in the foobar roaming folder, if not already present.
It works, thanks a lot ! :)) :D
3. NEEDLE CALIBRATION/MINIMAL ANGLE:
How do you easy tune the needle? What tools do you have available?
I completely have no idea about this. 'easy tuning' means playing around with aligning only.
as such, please accept my apology for giving a text that is not clear meaning. i will remove that text and consider have it back when we can enable such truly useful tuning as this vague feature: there may be a VU Meter, where the wallpaper is none, the background is transparent but meter range. then, the script can change the background/needle color, draw the meter range .
@ilovefb2k
Such a tool already exists in the existent VU Editor.
Because of current incompatibility between skin.ini and BIN project files you have to do a lot of tedious transformations by hand/eye in the needle png, adjusting length and finding of PivotPointY. See my previous post about this process and particularly the attached skin.ini.
https://hydrogenaud.io/index.php/topic,110516.msg1054186.html#msg1054186
Instead of putting effort in writing your own VU Editor for this JSP3 script, it might be a better approach to make this script compatible with and accept the values from the existing VU Editor project files as is.
EDIT: I'm pretty sure the compiled BIN files hold no magic. It just contains the L_0, L_2 and L_3 files as is and a number of prerendered (anglecount) needle png's rendered to the same dimensions as L_0. Therefore there's hardly a performance impact on CPU and memory displaying/scaling a running BIN VUmeter. The only thing needed is a decent scaling/rendering engine supporting alpha and brightness, such as JSP3 already has.
hi @
Defender ,
we have just bothered
@BoringName at MB 4rum to compile a command-line tool to extract fb2k Vu meter's BIN.
https://getmusicbee.com/forum/index.php?topic=41692.msg229960#msg229960 If things go fine, then Santa Claus already brings us present for this coming Xmas .
note: @marc2003 released JSP3 3.8.5
https://jscript-panel.github.io/docs/changes/, the last 2 updates with
IJSGraphics.PushLayer() and
IJSBitmap interface surely add a lot of values:
- IJSGraphics PushLayer : remove the '
weird tails' of VU Meter.
- IJSBitmap interface : we believe this will
reduce memory consumed after triggering IJSImage.ReleaseGraphics()
hope that we can have the last piece of the puzzle on place this weekend and then just script refactored.
regards
@ilovefb2k
EDIT: I'm pretty sure the compiled BIN files hold no magic. It just contains the L_0, L_2 and L_3 files as is and a number of prerendered (anglecount) needle png's rendered to the same dimensions as L_0. Therefore there's hardly a performance impact on CPU and memory displaying/scaling a running BIN VUmeter. The only thing needed is a decent scaling/rendering engine supporting alpha and brightness, such as JSP3 already has.
I don't really know how much time I'll have to monitor this thread so no guarantees on how much engagement I'll have here down the track.
The BIN files contain the background image as is. The needle and LED information is stored as pixel data and there are offsets stored for each frame that points to this data which contains what position in the background image it needs to replace. So the process is to start with the background image, look up the offset for the specific frame being drawn, use that data to replace pixels in the background image with the needle/led pixels, then draw the final image. It's a bit more complicated than that but it's not too far off.
There is a zeroFrame value stored which designates which frame should be used when the peak level is 1.0 (zero decibels).
Some frames use the same data and that's how the bin file creates a scale for the meter. If a meter starts at -40 decibels and another starts at -20, you will find the -20 meter will have a lot more frames with the needle pointing to -20 than the other meter will have pointing to -40. I hope that makes sense.
The calculation to determine which frame to use is Peak Value * zeroFrame. Assuming Foobar returns peak values between 0-1.0
we have just bothered @BoringName at MB 4rum to compile a command-line tool to extract fb2k Vu meter's BIN. https://getmusicbee.com/forum/index.php?topic=41692.msg229960#msg229960
Now I'm up to speed on what you want it for, I'm even more sure it's not going to do what you want. Aside from the issue I already mentioned about VUEditor appearing to anti-alias the needle image when it stores the data in the BIN file, the other problem is you are planning on caching thousands of images. Most bin files are 1024 frames. So you're talking over 2000 images if it has a needle and LED components.
It's been a decade since I've dabbled in javascript and I don't know what limitations you have with the jscript panel but for AIMP skins in my plugin, I just cache the background image and the needle image. Then each frame I draw the background, rotate the needle image based on the peak value and draw it over the top.
I might have it wrong but it looks like you are caching all the possible angles of the needle up front, wouldn't that be using large amounts of VRAM?
I initially tried that method with BIN files and it didn't end well.
If you are intent on supporting BIN files I'd suggest you have a read of the info oops provided and work on drawing them with the approach I mentioned at the start of this post. While you might be able to extract a fully intact needle image with the binExtractor program for some BIN files, I think you will find they will be in the minority.
Am I blind or is there no way to edit posts?
Anyway, one other issue is the VUEditor stores the glass and needle pixels together so that will also give undesirable results with your approach.
Am I blind or is there no way to edit posts?
For reasons known only to someone else, once posts here reach a certain limited age (an hour??) they cannot be edited. Until then if you press the "More" button it offers the ability to edit.
EDIT: I'm pretty sure the compiled BIN files hold no magic. It just contains the L_0, L_2 and L_3 files as is and a number of prerendered (anglecount) needle png's rendered to the same dimensions as L_0. Therefore there's hardly a performance impact on CPU and memory displaying/scaling a running BIN VUmeter. The only thing needed is a decent scaling/rendering engine supporting alpha and brightness, such as JSP3 already has.
I don't really know how much time I'll have to monitor this thread so no guarantees on how much engagement I'll have here down the track.
The BIN files contain the background image as is. The needle and LED information is stored as pixel data and there are offsets stored for each frame that points to this data which contains what position in the background image it needs to replace. So the process is to start with the background image, look up the offset for the specific frame being drawn, use that data to replace pixels in the background image with the needle/led pixels, then draw the final image. It's a bit more complicated than that but it's not too far off.
There is a zeroFrame value stored which designates which frame should be used when the peak level is 1.0 (zero decibels).
Some frames use the same data and that's how the bin file creates a scale for the meter. If a meter starts at -40 decibels and another starts at -20, you will find the -20 meter will have a lot more frames with the needle pointing to -20 than the other meter will have pointing to -40. I hope that makes sense.
The calculation to determine which frame to use is Peak Value * zeroFrame. Assuming Foobar returns peak values between 0-1.0
we have just bothered @BoringName at MB 4rum to compile a command-line tool to extract fb2k Vu meter's BIN. https://getmusicbee.com/forum/index.php?topic=41692.msg229960#msg229960
Now I'm up to speed on what you want it for, I'm even more sure it's not going to do what you want. Aside from the issue I already mentioned about VUEditor appearing to anti-alias the needle image when it stores the data in the BIN file, the other problem is you are planning on caching thousands of images. Most bin files are 1024 frames. So you're talking over 2000 images if it has a needle and LED components.
It's been a decade since I've dabbled in javascript and I don't know what limitations you have with the jscript panel but for AIMP skins in my plugin, I just cache the background image and the needle image. Then each frame I draw the background, rotate the needle image based on the peak value and draw it over the top.
I might have it wrong but it looks like you are caching all the possible angles of the needle up front, wouldn't that be using large amounts of VRAM?
I initially tried that method with BIN files and it didn't end well.
If you are intent on supporting BIN files I'd suggest you have a read of the info oops provided and work on drawing them with the approach I mentioned at the start of this post. While you might be able to extract a fully intact needle image with the binExtractor program for some BIN files, I think you will find they will be in the minority.
hi @
BoringName,
It is very kind of you to give us very valuable information about fb2k-VU-meter-BIN file format.
I have tried to unzip BIN file by 7zip
https://7-zip.org, then following
@oops 's instruction to manipulate that file content by utilizing an ActiveX Object
ADODB.Stream (which can read binary content), but no luck except for very strange characters.
you are totally right about VRAM consumed during rendering the AIMP VU Meter skins. we, as much as we can, avoid caching all the possible angles of the needle up front until struggling with some special layouts (e.g. maximize to have VU Meter skin filled the whole panel). however, we will have to figure out a formula ultimately or play around with that to reduce very high VRAM consumed.
dealing with fb2k VU Meter BIN is almost the last piece of the puzzle. step by step, we have tried our best.
as such, someone may think we are stubborn , try to mimic something that has been already done by professional people as
@BoringName and
@oops done, . . . and this VU script could not be compared with
foo_vis_vumeter in every aspects. But, think twice, as we have already undergone a very long time that the fb2k vu_meter component staying no updated until
@oops gave it a try. as such, we just want to have Vu meter done in JSP3 script as plain text here, then people as us can make any changes to this as long as @marc2003 keeps this component updated and been there no matter other real Vu meter. by then, VRAM and CPU power should not something for us to consider.
wish you all the best and very happy Xmas season to come.
regards
@ilovefb2k.
3. Is there a setting that functions the same way as "var peak_hold = 10; // in frames" does in the JSP3 Sample VU Meter?
hi @sveakul ,
thank you for your feedback,
3- var peak_hold = 10 : can you shed me a light on what you are after ? we can have this back or make it as an option.
@ilovefb2k
I thought it might help visually with the extremely slow decay rate of LEDs when "LED follows Peak" is selected. On the JSP3 bar meters it controls how long the peak line holds before beginning the decay of the line. May or may not be relevant here but maybe worth an optional inclusion. Just to clarify, the NEEDLE meter decay rate has always looked fine, but I assume that RMS is what is being used by default with AIMP meters?
hi @
sveakul,
we will have this
peak_hold setting back this weekend updated.
thank you for your feedback.
@ilovefb2k
I have tried to unzip BIN file by 7zip https://7-zip.org, then following @oops 's instruction to manipulate that file content by utilizing an ActiveX Object ADODB.Stream (which can read binary content), but no luck except for very strange characters.
Removing compression is definitely the first step. Finding a C# library that could unzip BZIP2 files properly was one of my biggest hurdles.
Let's see if you can decode the header using javascript and go from there. The first 8 bytes (64 bits) of the file contain the background image width, height, number of frames and zero frame. Each value is 2 bytes.
In C# I use BitConverter.ToUInt16(value,0);
Where value is a byte array containing the 2 bytes I want to convert.
If you can find a javascript equivalent of that command and extract the 4 values from the header that will be a good start.
@Defender
"Text Display + Album Art + Seekbar + Buttons, added Art mousewheel, ReplayGain button and rightclicks"
Thanks for this script.
Request:
Could you please add "Custom Text" to the Contestmenu?
Thank you.
(https://i.imgur.com/OfCcSAi.png) (https://i.imgur.com/VHM2rP4.png)
@Defender
"Text Display + Album Art + Seekbar + Buttons, added Art mousewheel, ReplayGain button and rightclicks"
Thanks for this script.
Request:
Could you please add "Custom Text" to the Contestmenu?
Thank you.
It already has, when you rightclick on the text (rightclicking the image will give a different menu).
Oops, when I right-clicked on the bottom of the image, the original "Text Display + Album Art" context menu appeared.
"Text Display + Album Art" displays a context menu even on images.
I am deeply remorseful.
Oops, when I right-clicked on the bottom of the image, the original "Text Display + Album Art" context menu appeared.
I am deeply remorseful.
It's a small glitch in my (old) script (which I do not use myself), where I manually added support for mousewheel on art including stub image support (and extra buttons, optional font/size with rightclick support).
The current version of the sample script now has built-in a lot of the stuff I originally added including mousewheel support on art and image support for buttons.
I took current version of the sample script and applied the things I still miss like optional transparency, stub art, extra buttons with optional font/size support and rightclick functions.
Hereby attached the upgraded version (v11). It needs the (same old) stub art of course to be extracted as well.
Let me know if it works as intended.
Perfect, thank you
(https://i.imgur.com/IYFKC8Y.png)
I have tried to unzip BIN file by 7zip https://7-zip.org, then following @oops 's instruction to manipulate that file content by utilizing an ActiveX Object ADODB.Stream (which can read binary content), but no luck except for very strange characters.
Removing compression is definitely the first step. Finding a C# library that could unzip BZIP2 files properly was one of my biggest hurdles.
Let's see if you can decode the header using javascript and go from there. The first 8 bytes (64 bits) of the file contain the background image width, height, number of frames and zero frame. Each value is 2 bytes.
In C# I use BitConverter.ToUInt16(value,0);
Where value is a byte array containing the 2 bytes I want to convert.
If you can find a javascript equivalent of that command and extract the 4 values from the header that will be a good start.
hi @
BoringName,
We think Santa Claus is true and He just bought us a Xmas present.
tonight, employing your tool
https://getmusicbee.com/forum/index.php?topic=41692.msg229228#msg229228 , i could extract
McIntosh.bin fb2k VU Meter bin into a folder, then applying a db-angle calculation, we can get the VU meter:
- every needle image is scattered along meter range and each has its own position on the scale.
- we then apply a formula to convert decibel into angle, then figure out the index number of the needle image.
quick observation show that it is very promising.
we will have it in detail tomorrow evening and hope that this is true, then we can release the 1st candidate.
again, thank you for your help and valuable inside information to finish the last piece of the puzzle ultimately.
regards,
@ilovefb2k P/s. attached is the screenshot of the VU Meter: top is
@oops 's Analog VU Meter Visualisation , bottom is JSP3_VU_Analog_Meter. i am on CPU: AMD Ryzen 7 4700U, 8 threads, OS: Windows 10, x64.
xmas present
Great news. This is also one of my preferred BIN's.
But I am puzzled by this post. Were you able to retrieve the back (L_0), needle (L_1) and glass (L_2) from the BIN?
You state, "we then apply a formula to convert decibel into angle" ... how and what?
Nice screenshot. Can you send a working extracted set of L_0, R_0, L_1, R_1, L_2. R_2 with skin.ini from this BIN?
But I am puzzled by this post. Were you able to retrieve the back (L_0), needle (L_1) and glass (L_2) from the BIN?
You state, "we then apply a formula to convert decibel into angle" ... how and what?
ilovefb2k's method will only work for certain skins. When the BIN file is created with the VUEditor, it merges the needle and glass pixels so you can't separate them.
You can extract the background image without any problems.
You can extract a full needle image only if there is at least one angle where it will not be covered by a glass element.
You can extract full LED images.
The problem with just extracting images is you have to manually configure the pivot point and scale of the meter. While it's a lot more complicated up front, decoding the BIN file properly will produce a much better result.
But I am puzzled by this post. Were you able to retrieve the back (L_0), needle (L_1) and glass (L_2) from the BIN?
You state, "we then apply a formula to convert decibel into angle" ... how and what?
ilovefb2k's method will only work for certain skins. When the BIN file is created with the VUEditor, it merges the needle and glass pixels so you can't separate them.
You can extract the background image without any problems.
You can extract a full needle image only if there is at least one angle where it will not be covered by a glass element.
You can extract full LED images.
The problem with just extracting images is you have to manually configure the pivot point and scale of the meter. While it's a lot more complicated up front, decoding the BIN file properly will produce a much better result.
Ok. I'll wait and won't respond to posts that rise more questions than answers.
FYI. Earlier in this thread I described a working but very elaborate way of creating a AIMP skin from the 7inch_3 BIN and using VU Editor to help at least with finding the correct angles to use in skin.ini.
https://hydrogenaud.io/index.php/topic,110516.msg1054186.html#msg1054186
The current version of the sample script now has built-in a lot of the stuff I originally added including mousewheel support on art and image support for buttons.
I took current version of the sample script and applied the things I still miss like optional transparency, stub art, extra buttons with optional font/size support and rightclick functions.
Hereby attached the upgraded version (v11). It needs the (same old) stub art of course to be extracted as well.
Let me know if it works as intended.
Text Display + Album Art + Seekbar + Buttons - v11 with middle mouse button
@Air KEN@Jacob91 Two modifications:
1) For the time being I've activated the stub Radio.png for playing streams until I have a solution for displaying the current streaming artist image instead of another stub image.
2) Doubleclicking the text part on normal tracks opens the containing folder in an explorer window.
No changes in the stub images, but added to be complete.
Text Display + Album Art + Seekbar + Buttons - v11 with middle mouse button
Can you send me your script? You implemented some extra buttons and my modified script also has no middle mouse action.
We think Santa Claus is true and He just bought us a Xmas present.
Here's another - BinExtractor1.1.zip (https://www.mediafire.com/file/h0vuneho1gy9eaa/BinExtractor1.1.zip/file)
BinExtractor will now take 2 command line arguments. The first is the path to the bin file and the second is a frame number.
eg)
BinExtractor.exe "C:\FoobarSkins\McIntosh.bin" 400
This will extract the background image, needle and LED frame for frame number 400 into the following folders
C:\FoobarSkins\McIntosh\left
C:\FoobarSkins\McIntosh\right
If there is no right meter the folder will be empty.
The frame number argument starts at zero so if a skin has 1024 frames and you want the last one you need to use 1023.
If the frame number argument is omitted it will extract all the frames. As previously mentioned this has the potential to create A LOT of files, over 4000.
If you specify a frame number argument that is larger than the number of frames in the specified bin file, it will extract all frames.
If you extract a bin file that only has LEDs and no Needles, it will still create a needle file for each frame, they will just be blank.
This is provided as is, use at your own risk. It doesn't really check for errors and if the arguments are wrong it will just exit without letting you know why. Make sure you enclose the bin path in quotes if it has any spaces in it.
Edit: Also I hinted about this earlier but you may find some needle images contain parts of the background image as well. This isn't a bug with the extractor, it's just how the needle pixel data has been stored by the original VUEditor program. I don't know if this is a bug with the original program or intentional to provide some form of antialiasing or other reason.
@Defender
Thanks! :)
Text Display + Album Art + Seekbar + Buttons - v11 with middle mouse button
Can you send me your script? You implemented some extra buttons and my modified script also has no middle mouse action.
Text Display + Album Art + Seekbar + Buttons - v11 with
middle mouse button mouse wheel + extra buttons
@Jacob91
Thanks.
It would be nice if all the buttons were centered. Thanks.
------
Sorry. It's done.
Line: 110
var x = (panel.w - (bs * (btot + 1))) / 3.8; // Last button also needs bs width
Use "foo_flowin"
(https://i.imgur.com/Kix1bnh.png)
extra buttons
@Jacob91 @Air KEN Hi Jacob,
Couple of things. Your script is based on an older version version of my script. Therefore you miss out on left doubleclicking on the textpart to open an explorer in the folder of the currently displayed track. You also won't get a Radio stub image displayed on a stream.
Random was already implemented by rightclick on Play/Pause.
Show Console I now added as a rightclick on Preferences.
I added support for an optional Albumlist button. Go to line 57 and set var al_enable to 1 to have it displayed.
I also made sure alignment is centered again. Hereby attached the modified version. (With required stub images which did not change).
Enjoy!
NB. With mouseover on buttons the second line of help shows the assigned rightclick function when implemented.
@Jacob91 @Air KEN
I don't use the Text Display + Album Art + Seekbar + Buttons - v12 script myself. I use image based AudioControl buttons.
Buttons are different to:
Menu, Stop, Play/Pause, Previous, Next, PBO, Randomize selection, Queue selection, ReplayGain, DSP preset, OutputDevice - All with rightbutton extras, which are described in the script itself.
Have a look. Maybe gives an idea for other text based buttons. Attached is cui-configs_AudioControls.rar with required base script and images.
hi Defender as I can't get to grasp with these scripts and I have tried could you try text display and buttons please no hurry as I am off to bed soon early shift tom
I can't get to grasp
You can't grasp anything. Just give it up and go away.
I've seen the huge amount of time and effort numerous people have spent trying to help you and you throw it back in their face every single time by never understanding anything you've been told.
We think Santa Claus is true and He just bought us a Xmas present.
Here's another - BinExtractor1.1.zip (https://www.mediafire.com/file/h0vuneho1gy9eaa/BinExtractor1.1.zip/file)
BinExtractor will now take 2 command line arguments. The first is the path to the bin file and the second is a frame number.
eg)
BinExtractor.exe "C:\FoobarSkins\McIntosh.bin" 400
This will extract the background image, needle and LED frame for frame number 400 into the following folders
C:\FoobarSkins\McIntosh\left
C:\FoobarSkins\McIntosh\right
If there is no right meter the folder will be empty.
The frame number argument starts at zero so if a skin has 1024 frames and you want the last one you need to use 1023.
If the frame number argument is omitted it will extract all the frames. As previously mentioned this has the potential to create A LOT of files, over 4000.
If you specify a frame number argument that is larger than the number of frames in the specified bin file, it will extract all frames.
If you extract a bin file that only has LEDs and no Needles, it will still create a needle file for each frame, they will just be blank.
This is provided as is, use at your own risk. It doesn't really check for errors and if the arguments are wrong it will just exit without letting you know why. Make sure you enclose the bin path in quotes if it has any spaces in it.
Edit: Also I hinted about this earlier but you may find some needle images contain parts of the background image as well. This isn't a bug with the extractor, it's just how the needle pixel data has been stored by the original VUEditor program. I don't know if this is a bug with the original program or intentional to provide some form of antialiasing or other reason.
hi @
BoringName,
Thank you very very much for your help. without your tool, we can not do anything with fb2k Vu Meter.
But your have just made it more fantastic, we can now extract the BIN file on-the-fly, it works flawlessly.
we still try to have FB2k_VU_Meter bin decoded natively to save CPU-load and reduce RAM consumed, but this tool surely inspires us in a very positive way.
again, thank you a lot for your time.
wish your all the best and a very happy, enjoyable weekend.
regards
@ilovefb2k
AIMP Analog VU Meter deployed, version named 1.0.16 DT-M 16-Nov-24
@ilovefb2k
Thanks for actively developing this script.
I like transparency and since the original foo_vis_vumeter does not support it and the new foo_vis_vumeter is DUI only/not transparent, your script is the only way to use this nice feature properly.
Nice you mention features, how to and limitations with new versions in your post, but could you also include a todo and version changes in the post. Especially the last one would be an improvement for me, since I then know what to test. Maybe also an idea to include the version name in the attached source rar itself?
I currently use:
fooBar 2.24 preview 2024-11-14 x86 - CUI/PSS 790MB typical memory usage
AIMP Analog VU Meter 1.0.16 DT-M 16-Nov-24
I did some testing on your current version:
ALIGNMENT:
I noticed in this version that the quality of the upscaled displayed image in all modes is now the same as foo_vis_vumeter.
All good except for the needle stuff mentioned below.
BTW. The original foo_vis_vumeter also has a mono choice besides only left and only right. It combines/adds L+R signals before using the left vu meter to display the results.
MEMORY USAGE:
When using any of the H and C scalings except H:Maximize and switching between them your script hardly uses any extra memory. All of these scalings however display part of the needle below L_0 & R_0 (and L_2 & R_2). Only H:Bottom looks fine because it probably paints the lower part of the needle outside of the panel.
The moment you switch to H:Maximize or any of the V and R scalings the needle is displayed correctly within image boundaries.
However memory uses goes up by a lot. Lowest value I have seen is +400MB, but sometimes it goes up by +1000MB. CPU usage stays low.
Any switch in scaling you do after you selected a high memory scaling, keeps the memory at those elevated levels even when playing stops or plugin is not displayed.
I also encountered some very infrequent freak spikes up to +2000MB while testing before fooBar became unstable and had to be killed.
NEEDLE CALIBRATION/MINIMAL ANGLE:
You mention easy tuning in your post. I still struggle a whole lot by trial and error to calibrate the position of the needle and the length of the needle. In the end I find the minimal angle (and maximum angle=-minimum angle). But the needle is a whole lot shorter when reaching the maximum value. Looks ok'ish at best. I hoped that the VU editor I use for making BIN's could provide me with values to use within the skin.ini file, but those values don't work.
How do you easy tune the needle? What tools do you have available?
While not playing I calibrate (by a lot of trial and error) the needle angle and position with one of the H:scalings (not H:Maximize), so the aspect ratio is the same of te L_0 & R_0 dimensions. Works fine when not playing and switching to any of the other H/C scalings except H:Maximize.
The moment I switch to H:Maximize or V/R scalings when not playing the needle moves from the position I calibrated to a slightly different position. Apparently in these modes the value is corrected by the value of PROPERTY HA.RMS.gain (dB). Can you disable this behavior so that the needle stays at 0 also in these scaling modes when not playing?
NEEDLE MOVEMENT:
In PROPERTIES you can set HA.RMS.gain (dB) which alters the movement of the needle. In foo_vis_vumeter this value is dynamic and can be changed by using the mouse scrollwheel.
I noticed that your script does not have a on_mouse_wheel(s) callback.
Can this be added so that you can also dynamically adjust the value of HA.RMS.gain (dB) PROPERTY in your script?
LAMP/LIGHT:
With VU Editor you can add a light/lamp overlay (with has the same dimensions as L_0 & R_0), that starts to be displayed as an overlay from a certain peak level to a maximum with increasing opaqueness. I use two knots in VU Editor values +0,0% and +4,100% with linear scale in between.
Can this be implemented in your script by adding the lights as L_3 & R_3 with PROPERTIES such as lowlight_dB, lowlight_perc and highlight_dB, highlight_perc?
I attached current version of my transparent AIMP style skin (red needles) with proposed lamp/light overlays included. Also a gradient BIN style (black needles) with red light/lamp. Also a small video with both VU meters running and show the light/lamp on the BIN.
hi @Defender,
thank you very much for your very detail feedback, in terms of the script's functionality and performance.
I reckoned, playing around with this VU meter is as playing a game of tradeoffs. not to mention my limited knowledge of VU meter.
1. ALIGNMENT: well-noted.
2. MEMORY USAGE : as @marc2003 has just introduced IJSBitmap interface https://jscript-panel.github.io/docs/interfaces/IJSBitmap/ along with JSP3 3.8.4 https://jscript-panel.github.io/docs/changes/#384, we will apply this and make some refactoring to see any improvement.
3. NEEDLE CALIBRATION/MINIMAL ANGLE:
How do you easy tune the needle? What tools do you have available?
I completely have no idea about this. 'easy tuning' means playing around with aligning only.
as such, please accept my apology for giving a text that is not clear meaning. i will remove that text and consider have it back when we can enable such truly useful tuning as this vague feature: there may be a VU Meter, where the wallpaper is none, the background is transparent but meter range. then, the script can change the background/needle color, draw the meter range .
3. NEEDLE MOVEMENT: well - noted.
4. LAMP/LIGHT: well-noted.
best regards,
@ilovefb2k
hi @
Defender;
thanks to recent JSP3 updated by @marc2003 (3.8.4, 3.8.5), we now can address the 'weird tail' of the skin and reduce RAM consumed (but not much).
LAMP/LIGHT: i already enclosed this in the script, but may not as your suggestion, please make changes if any and refer to later post for a full script. navigate to line 3398, the main script is there.
we have to change the filename of that lamp from
L_3.png, R_3.png into
L_4.png, R_4.png as
@sveakul already uses these filenames for another skin (
DejaVU Compact LED Calibrated Elemental-mod2)
// layer 2.2 > turn peak LED on, if any
//-----------------------------------
for (c = 0; c < channels_count; c++) {
opacity[c] = 0;
if ( Peak_LED_levels[c] > 0 && aimp_peak_LED_img[c] ){
db_ = _clamp(db_peak_LED[c], lowlight_dB[c], highlight_dB[c]);
minOpacity = highlight_perc[c]/100; maxOpacity = 1-lowlight_perc[c]/100;
opacity[c] = ( db_ - lowlight_dB[c])/(highlight_dB[c] - lowlight_dB[c]) ;
if (db_ >= highlight_dB[c] || db_ >= MaxLevel[c]) opacity[c] = maxOpacity;
else if (db_ <= lowlight_dB[c] ) opacity[c] = minOpacity;
else
opacity[c] = minOpacity + opacity[c] * (maxOpacity - minOpacity);//linear scale
opacity[c] = _clamp(opacity[c],0,1);
}
try {
if (opacity[c] != null )
gr.DrawBitmap (aimp_peak_LED_img[c],
x_[c],y_[c],ww_[c],wh_[c],
0,0,wwc[c],whc[c],opacity[c]);
} catch (e) {
console.log('\n\n-------------',window.Name, ' : Error line 3300, /AIMP_VU_Meter_needle_render/ = ',e);
}
}
hope this helps.
regards
@ilovefb2k
hope this helps.
I'd love to test it. My current script is version "1.0.16 DT-M 16-Nov-24" and it only has 3144 lines ... Did I miss a more recent version with more lines?
xmas present
Great news. This is also one of my preferred BIN's.
But I am puzzled by this post. Were you able to retrieve the back (L_0), needle (L_1) and glass (L_2) from the BIN?
You state, "we then apply a formula to convert decibel into angle" ... how and what?
Nice screenshot. Can you send a working extracted set of L_0, R_0, L_1, R_1, L_2. R_2 with skin.ini from this BIN?
hi @
Defender,hope that i do not miss any your post and sorry for jumping in between you and
@BoringName 's discussion.
about your feedback:
-
Were you able to retrieve the back (L_0), needle (L_1) and glass (L_2) from the BIN? : No, all the magic things done by @
BoringName , we just employ
@BoringName's fantastic tool
BinExtractor https://getmusicbee.com/forum/index.php?topic=41692.msg229228#msg229228 and BinExtractor1.1
https://getmusicbee.com/forum/index.php?topic=41692.msg230008#msg230008 and get all needle images, LED images and background.
@BoringName has just done us a favor by compiling this tool as a command-line utility (1.1).
-
You state, "we then apply a formula to convert decibel into angle" ... how and what? : as i said, i have no idea about Vu Meter, just copy this formula from here https://www.aimp.ru/forum/index.php?topic=52865.msg325066#msg325066 . frankly, how hard we have tried, we could not figure out how these parameter related to each others (INI file of AIMP analog Vu Meter):
MinAngle, MinLevel
ZeroAngle,ZeroLevel
MaxAngle, MaxLevel
-
Can you send a working extracted set of L_0, R_0, L_1, R_1, L_2. R_2 with skin.ini from this BIN? : we get around 1000 images for needle/channel and 1000 images for LED/channel.
regards,
@ilovefb2k
we get around 1000 images for needle/channel and 1000 images for LED/channel.
I got the message already by Boringname :-)
Please send me a working script to enable me to test lights/lamps.
Oh for fucks sake, please make it stop. This thread is now a complete dumpster fire. I was expecting half a dozen images required at most for these cancerous fucking analog meters. Now you're talking about hundreds/thousands. Fucking idiots the lot of you. :/
Oh for fucks sake, please make it stop. This thread is now a complete dumpster fire. I was expecting half a dozen images required at most for these cancerous fucking analog meters. Now you're talking about hundreds/thousands. Fucking idiots the lot of you. :/
LOL. I just asked for a working script :-)
But you are right, this has nothing to do with JSP3 as such,
@Iovefb2k
Can you open a separate thread regarding your script?
hi @
all,
another weekend is coming, friYaY and also another holiday season to come.
please find a script attached, named
JSP3 Analog VU Meter, version
1.0.0 DT-N 23-Nov-24 for easy reference.
-
features :
+ load analog/needle AIMP Vu meter (after unziping)
+ load FB2K VU Meter (after extracting by
@BoringName 's tool).
+ free allocation in panel
-
AIMP VU Meter types covered:
1 >
AIMP VU Meter: + analog NEEDLE only (not analog LED) => vertical/horizontal needle, up/down needle arrow ,>< V & /\ needle shape.
* type 1 : 1 image set for both channels
* type 2 : 2 image sets, each for each channel.
+ LED (LVU) : vertical/horizontal bar
- how to :
+ download AIMP Vu Meter skin file e.g.
* analog NEEDLE :
https://www.aimp.ru/forum/index.php?topic=52865.0 * LED (Led VU) :
https://www.aimp.ru/forum/index.php?topic=54005 + unzip AIMP Vu Meter skin into a folder and copy this [folder] to specific directory as indicated by this script.
+ load this script into a JSP3 /UI/ panel
2>
FB2K VU Meter:
- step 0: get a FB2k Vu meter skin (e.g.
https://audio-file.org/foobar2000-vu-meter-skins-gallery)
- step 1: extract bin file by employing
@BoringName's tool:
https://getmusicbee.com/forum/index.php?topic=41692.msg230008#msg230008 (re-post by
@BoringName 's permission
https://getmusicbee.com/forum/index.php?topic=41692.msg229964#msg229964)
we may get 1024 needle image files (needle0000.png, . . . needle1023.png), 1024 LED image files (LED0000.png, . . LED1023.png),
background.png per channel.
=> 1024 + 1024 + 1 = 2049 files /channel x 2 channels =
4098 files. - step 2: create a folder named after 'name
.bin' (name is fb2k skin name, e.g. 'fisher', 'accuphase', 'sony'...).
- step 3: if skin has 1 set needle, 1 set LED images : create a sub folder '
VU' for needle images, a subfolder '
VU_LED' for LED images
if skin has 2 needle sets, 2 LED image set: create a sub folder '
VU_L' for
left needle images, a subfolder '
VU_LED_L' for left
LED images
then, '
VU_R' folder for all
right needle images, '
VU_LED_R' for all
right LED images.
all these subfolder are
right under 'name.bin' folder.
- step 4: copy/move 'name.bin' folder into specfic folder as indicated in the script,line 140
[fb.ProfilePath + "skins\\viking\\images\\vnav_fb2k\\beat_audio_vu_meter\\"]; we can change this path to any other for convinience.
note: we recognised this folder as FB2k VU Meter skin by its '
.bin' characters, so make sure to have this text in the folder name.
-
limitation: + options: MobilityNegative, MobilityPositive > could not take MobilityPositive into account.
+ meter range (in the skin) is quite inaccurate based on fb2k's audio engine.
+ Fb2k's VU Meter skins are currently consumed high RAM memory.
note: refer to fb2k , @
oops's,
Analog VU Meter Visualisation/foo_vis_vumeter component [
https://www.foobar2000.org/components/view/foo_vis_vumeter]
for more options
-
credit and acknowledgment:
+ @
marc2003 for rich-feature and powerful, rapid-updated JSP3 component.
+ @
Case and @
marc2003 for their JSP3 VU Meter.
+ @
Artem and contributors /AIMP VU Meter - analog NEEDLE/ for their beautiful analog VU Meters.
+ @
xrEngine and contributors /AIMP VU Meter - LED / for their elegant LED VU Meters.
+ @
BoringName at https://getmusicbee.com/forum/index.php?topic=41692.msg230008#msg230008 for BinExtractor.exe tool to extract fb2k VU Meter bin skins.
+ @
Defender, @
sveakul and @
Air KEN for nice suggestions and positive feedbacks.
- special JSP3 features:
+ IJSImage.CreateBitmap() : (3.8.4++) to reduce memory consumed before caching.
+ gr.PopLayer() : (3.8.5++) set a boundary to be visualied.
+ gr.DrawBitmap() : (3.8.4++) improve rendering image due to image-converted Bitmap in advance, more efficient CPU-load.
wish you all a very nice weekend and happy holiday season to come.hope that you all can find this humble script a little bit joyful.
regards,
@ilovefb2k
sorry for double posts.
@marc2003: please delete.
@ilovefb2k
Oh for fucks sake, please make it stop. This thread is now a complete dumpster fire. I was expecting half a dozen images required at most for these cancerous fucking analog meters. Now you're talking about hundreds/thousands. Fucking idiots the lot of you. :/
hi @
marc2k3,
sorry for spamming your thread, but luckily we have already reached the end.
thank you for your powerful JSP3 component and wish you a very nice weekend.
@ilovefb2k
frankly, how hard we have tried, we could not figure out how these parameter related to each others (INI file of AIMP analog Vu Meter):
MinAngle, MinLevel
ZeroAngle,ZeroLevel
MaxAngle, MaxLevel
MinLevel - The minimum level displayed by the meter in decibels. eg) -40, -20 etc..
MinAngle - The angle of the needle when the peak level is at or below the Minlevel
ZeroLevel - What level should be classed as zero. It's nearly always set to zero. It's a method to offset the meter for AIMP users as AIMP doesn't allow you to adjust the decibel level like Foobar and my plugin in Musicbee do with the mousewheel.
ZeroAngle - The angle of the needle when the peak level is 1.0 (zero decibels).
MaxLevel - The max level displayed on the meter in decibels eg) 5, 10 etc...
MaxAngle - The angle of the needle when the peak level is at or above the MaxLevel.
This is the code I use in C#. The reason it's not just maxAngle - minAngle * peak is some meters use a different scale for each side of zero.
if (peak > 1.0)
{
rotOffset = (zeroAngle - minAngle) + (peak - 1.0f) * (maxAngle - zeroAngle);
} else {
rotOffset = peak * (zeroAngle - minAngle);
}
rotation = minAngle * Constants.radian + rotOffset * Constants.radian;
Sorry if I added to the dumpster fire. I did warn about the insane amount of image files that method would create......but who am I to judge.
If you want any more info ilovefb2k just send me a PM and I'll see if I can help.
frankly, how hard we have tried, we could not figure out how these parameter related to each others (INI file of AIMP analog Vu Meter):
MinAngle, MinLevel
ZeroAngle,ZeroLevel
MaxAngle, MaxLevel
MinLevel - The minimum level displayed by the meter in decibels. eg) -40, -20 etc..
MinAngle - The angle of the needle when the peak level is at or below the Minlevel
ZeroLevel - What level should be classed as zero. It's nearly always set to zero. It's a method to offset the meter for AIMP users as AIMP doesn't allow you to adjust the decibel level like Foobar and my plugin in Musicbee do with the mousewheel.
ZeroAngle - The angle of the needle when the peak level is 1.0 (zero decibels).
MaxLevel - The max level displayed on the meter in decibels eg) 5, 10 etc...
MaxAngle - The angle of the needle when the peak level is at or above the MaxLevel.
This is the code I use in C#. The reason it's not just maxAngle - minAngle * peak is some meters use a different scale for each side of zero.
if (peak > 1.0)
{
rotOffset = (zeroAngle - minAngle) + (peak - 1.0f) * (maxAngle - zeroAngle);
} else {
rotOffset = peak * (zeroAngle - minAngle);
}
rotation = minAngle * Constants.radian + rotOffset * Constants.radian;
Sorry if I added to the dumpster fire. I did warn about the insane amount of image files that method would create......but who am I to judge.
If you want any more info ilovefb2k just send me a PM and I'll see if I can help.
hi @
BoringName ,
wow, we will have something to chill this weekend.
thank you very very very much for your valuable information and see if we can digest this to not bothering you again.
P/S. @marc2003 just said so, but @marc2003 is kind and nice inside. without recent JSP3 updated, we still struggle with an annoying bug of the JSP3 Analog Vu Meter.
best regards and nice weekend,
@ilovefb2k
new script
First look ... first findings (and very pleased btw).
I'm running my original AIMP skin based on VU Editor project and did not extract a thing.
Proper transparency support (like it already was).
Music stopped, needle goes to the defined MinLevel in all scalings now. Fixed.
No more needle ghosting outside of glass L_2/R_2, cutoff btw should be one pixel higher.
There's lights/lamps in scaling mode with standard aspect ratio. Lights are not shown in H:Maximize though.
What's the reason that I only see one needle in V/H:Maximize (old issue)?
So it seems all the visuals are in place, just needs some tweaking.
Still missing a much needed mouse scrollwheel though to adjust the needle(s).
I won't be able to test for the upcoming month. Only access to a laptop with probably limited/no internet access and I'll be submerged a lot of the time.
A new topic has been added to the forum, JSP3 Script Analog VU Meter (https://hydrogenaud.io/index.php/topic,126962.0.html), for any posts concerning this project--its continuing development, use, examples, etc. Please use it as of today.
A special thanks to marc2k3 for his past forbearance in the use of his "JScript Panel script discussion/help" topic's thread for posts concerning this project.
Using "foo_uie_jsplitter" and "foo_flowin", I am enjoying Artist images (Last.fm) being displayed one after another on "foo_flowin" with "Thumbs (Thumbs off)" overlaid on top of a "Text Display (Text only)" Panel (Automatic, Manual).
Of course, you can also double-click the image to enlarge it as a standard feature.
Is it possible to make this into one Panel using JScript Panel 3 Script?
Thank you.
https://i.imgur.com/slUspT8.mp4
https://i.imgur.com/y8aNQhP.mp4
(https://i.imgur.com/MmQ2mC6.png)
foo_uie_jsplitter 3.6.1.10
https://foobar2000.ru/forum/viewtopic.php?t=6378
foo_flowin 0.2.2
https://github.com/ttsping/foo_flowin/releases
----------
foobar2000 v2.24 preview 2024-11-14 : 32-bit | 64-bit
Windows 11 24H2
Processor: AMD Ryzen 7 5700X 8-Core Processor 3.40 GHz
RAM: 64.0 GB
GPU: NVIDIA GeForce RTX 4060
Hi :)
I ask here, even though we talked about it here
https://hydrogenaud.io/index.php/topic,126966.new.html
I have the discography of many singers and I would like to click on the entries of the songs that I seem to remember that I like and I would like to hear them directly (then if they are bad I manually delete them from the playlist) but if I disable Enqueue I lose the playlist, if I leave it enabled I don't hear the songs and I have to click on them to start them.
basically I want to click on a song in Win Explorer and I would like this song to be added to the default playlist and played directly. Is possible?
I use the playlist of JScript Panel with Playlist Organizer
i am not vary good at this but have you tried smooth browser from the panel list
If I might chip in: basically LauraQ wants to set up shell integration so that if Windows sends a media file to FB2K, it gets added to a playlist (not sent to playlist) and starts playing it.
For whatever reason, she does not want to browse her library within FB2K (and I sort of get that, the library in FB2K has to be pre-configured and you can't just pick any file on the computer ad hoc).
@LauraQ
How about changing your perspective? I don't say it's necessary, but if you use foobar2000 and want to play music from Windows Explorer, it's because you're not familiar with the "Media Library" function.
Basically, foobar2000 is great for building a "Media Library" and allowing you to search and create flexible playlists using features such as Album List, Playlist Panels such as ReFacets, and "Library Search".
"Playlist Organizer" is not the best choice for you.
"Playlist Organizer" is good, but you should also become proficient with the basic Album List and ReFacets Library Search.
In other words, master the basic usage.
Then there's the difference in threads.
If I might chip in: basically LauraQ wants to set up shell integration so that if Windows sends a media file to FB2K, it gets added to a playlist (not sent to playlist) and starts playing it.
For whatever reason, she does not want to browse her library within FB2K (and I sort of get that, the library in FB2K has to be pre-configured and you can't just pick any file on the computer ad hoc).
thank you, you are very kind to help me make others understand what I am looking for :)
@LauraQ
How about changing your perspective? I don't say it's necessary, but if you use foobar2000 and want to play music from Windows Explorer, it's because you're not familiar with the "Media Library" function.
Basically, foobar2000 is great for building a "Media Library" and allowing you to search and create flexible playlists using features such as Album List, Playlist Panels such as ReFacets, and "Library Search".
"Playlist Organizer" is not the best choice for you.
"Playlist Organizer" is good, but you should also become proficient with the basic Album List and ReFacets Library Search.
In other words, master the basic usage.
Then there's the difference in threads.
thank you but I'm not an expert and then I'm "habitual", I usually listen to music by clicking on the files from Win explorer and, sorry if I'm arrogant, I don't think I'm asking for such absurd things if I'm looking for a player that plays them
Anyway, it's a different thread
Anyway, it's a different thread
becouse JScript Panel script can't have this option?
extra buttons
@Jacob91 @Air KEN
Hi Jacob,
Couple of things. Your script is based on an older version version of my script. Therefore you miss out on left doubleclicking on the textpart to open an explorer in the folder of the currently displayed track. You also won't get a Radio stub image displayed on a stream.
Random was already implemented by rightclick on Play/Pause.
Show Console I now added as a rightclick on Preferences.
I added support for an optional Albumlist button. Go to line 57 and set var al_enable to 1 to have it displayed.
I also made sure alignment is centered again. Hereby attached the modified version. (With required stub images which did not change).
Enjoy!
NB. With mouseover on buttons the second line of help shows the assigned rightclick function when implemented.
Thanks,
I added one button for TotalCommander.
good afternoon is it possible to make a jsp script to show number of times a track has been played and the date last played
like
no. of plays / last played on
3 03/12/2024
i hope you understand what I mean and maybe you fancy a challenge if possible
many thanks in advance happy scripting :)
You don't need at all jscript for that, it can be done with standard columns and tags. But yes, it can also be done with jscript.
https://wiki.hydrogenaud.io/index.php?title=Foobar2000:Components/Playback_Statistics_v3.x_(foo_playcount)
thank you roger i tried this but it didn't display as I wanted
Just install the component and display it using Text Display (JSP3) or similar.
Playback Statistics (foo_playcount)
https://www.foobar2000.org/components/view/foo_playcount
Titleformat Playback Statistics
https://wiki.hydrogenaud.io/index.php?title=Foobar2000:Titleformat_Playback_Statistics
[Play Count: %play_count% x]$crlf()
[First Played: $date(%first_played%)]$crlf()
[Last Played: $date(%last_played%)]
------
Playcount 2003 (foo_playcount_2003)
https://marc2k3.github.io/component/playcount-2003/
%2003_playcount%
%2003_first_played%
%2003_last_played%
%2003_first_played_ts%
%2003_last_played_ts%
%2003_first_played_ago%
%2003_last_played_ago%
%2003_first_played_ago2%
%2003_last_played_ago2%
-----
Text Display (JSP3)
https://jscript-panel.github.io/gallery/text-display/
Custom text...
Flowin
(https://i.imgur.com/JyDB8FR.png)
thank you will give it a try
i got foo playcount what else what I see do i just open text display in a new panel
Do as you like.
There are helpful instructions so anyone can do it.
thank you ;D
Please don't send me PMs to ask for support when that can be asked on the forum. Specially when you are asking me the same than here.
sorry I do apologize
woo hoo i did it :) :) the only thing I don't like is the way the way the date is displayed but this maybe adjusted in my pc settings but a big thank you to all that helped
my text format
$font(Segoe UI,13,700)
Title: %title% $crlf()
Album: %album% $crlf()
Year: %date% $crlf()
Played: %play_count% times$crlf()
First Played: %first_played% $crlf()
Since Last Play: %last_played% $crlf()
I always tell you to read carefully.
[First Played: $date(%first_played%)]
[Last Played: $date(%last_played%)]
Reply #2064 https://hydrogenaud.io/index.php/topic,110516.msg1055352.html#msg1055352
Title Formatting Reference - Time and date functions
https://wiki.hydrogenaud.io/index.php?title=Foobar2000:Title_Formatting_Reference#Time_and_date_functions
thank you
trying to format the date
this last Play: %$day_of_month(time)%%$month(timw)%%$year%(time)%$crlf()[/b]
returns this
Last Played: ???
all i would like is Friday 07 December 2024 11.22
the format i used here
https://wiki.hydrogenaud.io/index.php?title=Foobar2000:Title_Formatting_Reference
using text format in jsp script
any help would be appropriate
last played 3?
trying to format the date
this last Play: %$day_of_month(time)%%$month(timw)%%$year%(time)%$crlf()[/b]
returns this
Last Played: ???
Putting "last Play:" in as a text string cannot possible return "Last Played:". You are not helping yourself by being so inaccurate with your quoting/transcribing. You also seem to have ignored advice above exactly what titleformat strings to call.
It seems to be resolved
https://hydrogenaud.io/index.php/topic,127050.0.html
yes :D
yes :D
For the sake of (my) sanity / love of God, start working on your communication skills.
Yes. :))
glad you like it
This confirms that you have been completely mocking people.
Text Display sample (or one of the derivatives):
My tags are %artistcountry% (and %releasecountry%).
How do I add the display of a country flag in the Custom text ... ?
Text Display sample (or one of the derivatives):
My tags are %artistcountry% (and %releasecountry%).
How do I add the display of a country flag in the Custom text ... ?
Hi!
if it can help you
%artist% $font(Twemoji Mozilla,15) $country_flag(%country%)$crlf()
Hi!
if it can help you
%artist% $font(Twemoji Mozilla,15) $country_flag(%country%)$crlf()
It certainly did. Thx!
I have a question about JS3 samples.
In a number of them you can select the "Selection mode" either Prefer now playing or Follow selected track.
It changes the value of panel.prefer_playing().
I like to change buttons based on this value the moment this value is changed.
What callback is associated with the change of this value so I can fire buttons.update() from within this callback?
I have a question about JS3 samples.
In a number of them you can select the "Selection mode" either Prefer now playing or Follow selected track.
It changes the value of panel.prefer_playing().
I like to change buttons based on this value the moment this value is changed.
What callback is associated with the change of this value so I can fire buttons.update() from within this callback?
It works when I add one line in panel.js:
line 164 case idx == 110:
case idx == 111:
this.selection.value = idx - 110;
this.item_focus_change();
buttons.update(); // ADDED
break;
But I prefer not to make changes to panel.js.
Editing .js files was a terrible thing to do when the component was actively maintained. Any component update always wiped component folder contents as part of the process. But the component is no longer getting updated so do what you want.
Editing .js files was a terrible thing to do when the component was actively maintained. Any component update always wiped component folder contents as part of the process. But the component is no longer getting updated so do what you want.
I never did update the js itself. I always took the code and included it in the sample file itself, before modding it. Only when you made major changes I had to redo this operation.
I guess there is no callback I can trigger upon changing the selection mode from the context menu, so I included the modified panel.js in the script.
BTW. You are sorrily missed and I hope at one time you actively start maintaining/updating the component again.
For those interested ... I attached a package with updated Text Display script to facilitate current changes in foo_input_udsd. Also includes a list of changes.
Also did a RFC to the SACD/UDSD forum:
I attached two images of my current JS3 script that I adapted to represent current state of foo_input_udsd 0.015 and foo_outinfo 1.2.3.
Green part represents the current audio chain for the playing (selected or not selected) track (SACD in this case), I applied a silly DSP downmix to 1.0 to show things more clearly in the audiochain.
Blue depicts a debugger that show the currently in TF available fields. Tags are from the selected track and from the playing track (can be the same track of course).
First image: White are tags of the current selected playing/paused track (in this case an SACD track).
Second Image: Yellow are tags of the current selected not-playing track (normal flac in this case).
When an SACD track is selected and that track is playing, everything is ok.
What I'm missing in foo_input_udsd 0.015 when a SACD track is playing, but some other track (flac) selected are the following fields of the playing/not-selected SACD track that are required to see what happens in the audiochain:
1) $info(dsd_samplerate), $info(dsd_bitspersample), $info(dsd_channels)
2) $info(decoded_samplerate), $info(decoded_bitspersample), $info(decoded_channels)
I guess $info(decoded_channels) is not needed since foo_input_udsd probably does not change that while decoding, but I do need to see the number of channels before some DSP can mess around with it. So please also provide $info(dsd_channels).
Getting there slowly.
I'm trying to make some button code that does not create a button when there is not enough width to show this button.
If a button has been created and the window is being resized to a smaller width than what this button needs, buttons.update() is fired and my buttoncode says not to (re)create this button. However the button still exists and is displayed in weird places.
If the window width is enlarged and enough width becomes available again the button is restored to it's former glory.
What is the code to dispose of an existing not needed button?
NB. I have a workaround by recreating a dummy with the same name. But I'd rather have a more elegant solution.
I attached a slightly modified version of the Playback Buttons script. It contains 4 buttons and the last one is protected by the creation of a dummy button.
buttons.update = function () {
// this wipes all previous buttons
this.buttons = {};
// now create new ones conditionally
}
I have a similar question about width with Text Display sample. I'm using it in "text only" mode, and basically I want to change the panel width to match the text width, i.e. something like -
var text_width = utils.CalcTextWidth2(text_layout, text_font);
window.MinWidth = window.MaxWidth = text_width;
The trouble being I have no clue how to access the text and font being used in the layout - is that easily possible?
I likewise made a workaround by duplicating the same title format and font size used and put that into new variables - and sure it works fine, but of course it would be nicer to get the existing width. If it would be more complicated than that, no need to bother, just my curiosity at play. ;)
I guess it could be complicated because the text can be on multiple lines and font sizes and how to determine which is the widest? - though I'm only using it to display a single tag value, such as $meta(artist,0)
You can get the text/font like this.
var text_width = utils.CalcTextWidth2(text.text, panel.fonts.normal);
^ Fantastic. That makes things so much easier. Thanks. 8)
buttons.update = function () {
// this wipes all previous buttons
this.buttons = {};
// now create new ones conditionally
}
Thx! That cleaned up the code a lot.
New version
Attached screenshot shows all defined optional buttons.
Made some changes to get the audiocontrols of this script more in line with my AudioControls imagebuttons script.
Added OutputDev button
Leftclick: Dropdown to the available output devices
Rightclick: Reset to second device (Primary Sound Driver) or Preferences when Output Device is already second device
Button char: Different for Speakers, Headphones, Bluetooth and Otherwise
Button colors: Red for Null Device, Green [exclusive] devices, White for second device, Yellow for other Devices that are not Speakers, Headphones or Bluetooth
Added DSP Preset button
Leftclick: Dropdown to the available DSP Presets
Rightclick: Disable DSP or Preferences when DSP already disabled
Button colors: White if DSP is disabled, Red when downmix, Yellow when upmix, Green otherwise
Bugfix for NowPlaying button which led to not showing the correct artwork.
Preferences button is default OFF. Enable when desired.
PlayOrPause button now uses different chars for Not Playing, Playing and Paused.
Position of ReplayGain button is moved from last button on the left side to first on the right side.
Fixed on_size issues and improved aligning.
Prioritize which selected buttons are shown when width is too limited. Change order when desired.
Easy to adjust display positions for buttons. Change positions when desired.
@Defender
Happy new year.
Thank you as always.
foobar2000 v2.24.1 64bit Default UI
2025-01-01 v14
Display: 3840 x 2160 27inch
Line 198: var bs = _scale(30);
Use:
Flowin 0.2.2 (foo_flowin) It doesn't seem to affect the display.
JScript Panel 3 3.8.5 (foo_jscript_panel3)
Output Info 1.2.3 (foo_outinfo)
Playcount 2003 0.3.0 (foo_playcount_2003)
----
Button:
ReplayGain
DSP Preset
Output Device
Select Now Playing
-----
The buttons I see are different from your screenshots and description. Is this normal for my Text Display (2025-01-01 v14)?
(https://i.imgur.com/uQbbRSw.png)
Display: 3840 x 2160 27inch
Line 198: var bs = _scale(30);
Use:
Flowin 0.2.2 (foo_flowin) It doesn't seem to affect the display.
JScript Panel 3 3.8.5 (foo_jscript_panel3)
Output Info 1.2.3 (foo_outinfo)
Playcount 2003 0.3.0 (foo_playcount_2003)
The buttons I see are different from your screenshots and description. Is this normal for my Text Display (2025-01-01 v14)?
Happy new year to you too.
This script is just a small adaptation I made on the original that is included with JS3 which missed a couple of things that I liked.
Until a week ago I did not even use the script myself, but now with changes being made and availability of components like foo_outinfo, foo_hdcd, foo_input_sacd/foo_input_udsd it offers me an extra value (especially the NowPlaying button and the Output text part) so I gave the script a panel in my skin.
I am a bit wary to offer support on this script and answer your question here in this thread though, since I don't want to fall in the same trap that happened with the VU meter script.
I'll answer your questions for now though and hope I don't piss off anyone.
About the buttons themselves:
What you are seeing is the way it is intended and the way I use the script myself. Out of the box these are the buttons that are enabled and the way they look and the colors also represent the way it is intended. The screenshot I sent accompanying the last version just has all buttons enabled.
In the config section of the script you can select what buttons are displayed. Line 63/70.
You have a different char for the ReplayGain, because your RG is set to Album mode, my setting and default is Track/Album by PBO, which gives the same result as Album when tracks are grouped by Album in the playlist (correct me if I'm wrong).
Your DSP button is a green star. I have chosen a star character to represent DSP after searching for something appropriate for a long time. If you have a better suggestion please do. I try to use only characters that in default mode only have an outline instead of a solid fill. It is green because you have a DSP enabled, of which the name not starts with Upmix or Downmix.
Your OutputDevice button is yellow, because it is not the default device (which is Primary Sound Driver). It would be green if you select your device in exclusive mode).
If I'm not mistaken in current versions of foobar you don't need to use WASAPI anymore since that is default behavior.
When you select an OutputDevice that start with Speakers the character the button uses will change.
About the plugins you are using:
The custom text part of script also supports foo_cover_utils (1.1), foo_hdcd (1.20+ preview 2024-12-22), and foo_input_udsd (0.0.15). Both foo_hdcd and foo_input_udsd need some work to be perfect, and I made detailed requests for that.
About the custom text you are using:
It is different from mine, but actually the only difference is the first played and last played fields. I will change the section of Custom Text to make the display for these two fields optional.
The change you have to make for ButtonSize is interesting. What scaling are you using? I use 100% on my main system and 250% on my 4K monitors and those do not need the value of the ButtonSize changed.
My knowledge of JS3 is very limited and I have no clue how to detect current windows scaling.
In TF I use this to detect correct scaling:
$font(Consolas,10,) // Set fixed monospaced font
$puts(ts_consolas10, $muldiv($gettextwidth($repeat(W,100)),100,700)) // Consolas 10 with scaling 100percent is 700 pixels
$ifgreater($get(ts_consolas10), 370, $puts(scale,350) ,
$ifgreater($get(ts_consolas10), 313, $puts(scale,300) ,
$ifgreater($get(ts_consolas10), 256, $puts(scale,250) ,
$ifgreater($get(ts_consolas10), 227, $puts(scale,225) ,
$ifgreater($get(ts_consolas10), 213, $puts(scale,200) ,
$ifgreater($get(ts_consolas10), 184, $puts(scale,175) ,
$ifgreater($get(ts_consolas10), 156, $puts(scale,150) ,
$ifgreater($get(ts_consolas10), 127, $puts(scale,125) ,
$puts(scale,100)
))))))))
Based on the scale value I set things like buttonsizes, bezels and accents which makes my skin look the same on all windows scalings, which is also the reason why I started making my own DarkOne skin in the first place.
For me the most valuable button in this script is the NowPlaying button, which offers me to switch with a rightlick between info for the current playing track and a different track in the playlist and also can change the focus (leftclick) in the playlist.
I use colors to distinguish between the playing and the selected track so you always know what you are looking at.
At the moment I don't have any things I would like to add to this script, but I am open for suggestions.
Can you send me a screenshot after you adapted your buttons, I'd like to see how you use this script?
Thanks for your detailed explanation.
I would like to work on it little by little.
Display: 3840 x 2160 150% 27inch
I don't know where to put it. Line n - Can you tell me Line n?
I guess it's a bug in the original scripts where the seekbar placement/text layout doesn't adjust itself automatically when the button size is changed manually.
Button sizes already scale to DPI but I guess people may want them bigger/smaller independent of that.
In the panel. scroll to the bottom inside
on_size and change
seekbar.y = panel.h - _scale(44);
to
seekbar.y = panel.h - _scale(16) - bs;
Then edit
samples\js\text_display.js line 247
if (this.buttons_or_rating) {
albumart.h -= _scale(40);
this.y -= _scale(40);
}
to
if (this.buttons_or_rating) {
var offset = 0;
if (typeof bs === 'number') {
offset = bs + _scale(16);
} else if (typeof rating === 'object') {
offset = rating.h + _scale(16);
}
albumart.h -= offset;
this.y -= offset;
}
@marc2k3
Happy new year.
Thank you for the advice.
But Panel crashes (JavaScript error)
'break' cannot be specified outside a loop
Oops, it's done.
But it's not balanced. It's still small. Is this normal?
Line 198: var bs = _scale(30); or Line 198: var bs = _scale(32); is best.
Line 198: var bs = _scale(30);
(https://i.imgur.com/AFBQKg7.png) (https://i.imgur.com/OpWIR35.png)
Thanks.
------
I'm nervous that I'll be scolded again.
I guess it's a bug in the original scripts where the seekbar placement/text layout doesn't adjust itself automatically when the button size is changed manually.
Button sizes already scale to DPI but I guess people may want them bigger/smaller independent of that.
In the panel. scroll to the bottom inside on_size and change
Effectively shifts down the buttons and seekbar by _scale(4). Looks fine to me.
Then edit samples\js\text_display.js line 247
I do not want to edit the standard js scripts since I still hope you will resume support.
For now I copied text_display.js inside my script and made adjustments there.
Thx
@Airken Did you change var wscale to 150 in the configuration section of my script before you changed the value of var bs?
Like I said I don't have a clue in JS3 how to get the windows scaling. Therefore you need to hardcode it.
I also moved the declaration of var bs inside the configuration settings of my script (just under wscale).
If you still want bigger buttons after setting wscale to the correct value just change the value of var bs.
This will now work correctly because of the above changes.
The attached script also contains a small fix for color settings of the DSP button and includes a modified section of Custom text which now (optionally) displays foo_playcount_2003 info.
Thanks.
> Did you change var wscale to 150 in the configuration section of my script before you changed the value of var bs?
No, 150% is standard (recommended).
Line 62: var bs = _scale(24); // Button size
This time, since it is larger, I made it (20).
Don't worry, you will adjust it yourself.
It's a common occurrence
(https://i.imgur.com/V8d4D5B.png)
The _scale function does windows DPI for you. No one should be entering anything manually. How stupid does one have to be to think the name of the function must be for something else entirely. :/
No script editing was ever needed for these functioning 100% / 200% layouts.
> Did you change var wscale to 150 in the configuration section of my script before you changed the value of var bs?
No, 150% is standard (recommended).
I don't understand what you mean. Things get lost in translation I guess :-)
If you use this script you have to copy the scriptcode inside the JS3 panel and then you MANUALLY have to change the wscale value to the correct windows display percentage.
So in your case you have to change it from 100 to 150.
That's it.
My best guess is that you used this script before with the setting still on wscale 100, where it should have been 150.
The _scale function does windows DPI for you. No one should be entering anything manually. How stupid does one have to be to think the name of the function must be for something else entirely. :/
No script editing was ever needed for these functioning 100% / 200% layouts.
I only needed it to slightly change the x coordinate of the dropdowns, since I like the text inside the dropdown better aligned under the left side of the actually displayed pixels of the button instead of the whole dropdown window aligned with the beginning of the bs x coordinate.
Therefore I needed to adjust this x offset per windows scaling:
DPI = 96 * wscale / 100;
dx = x + (bs*bpos) - 32*(96/DPI)
This kind of works for 100, 125, 150, 175, 200, 225, 250, 300 and 350 windows scaling.
If you have a better way of aligning the text part of the dropdown with the left pixels of the button, I would be much obliged.
@marc2k3
My brain is a mess now.
> How stupid does one have to be to think the name of the function must be for something else entirely.
I'm so low level I don't even know what this means.
The buttons look small to me in that image (marc2k3).
Reply #2103
JS3_Text Display + Album Art + Seekbar + Buttons - v14a.txt
100% / 150% layouts
(https://i.imgur.com/uO8vyhq.png) (https://i.imgur.com/0Xa5PNn.png)
Display: 3840 x 2160 150% 27inch
It's a little big in terms of balance.
In the end, I adjust it myself.
This is common in User's JSP3 Script.
This does not happen in marc2k3's Sample Script.
Display: 1920 x 1080 100% 23inch
Modified 2025-01-02 v14a
(https://i.imgur.com/hFWSkF6.png)
I didn't do anything with this one.
It's just the right balance.
I think this is just a personal feeling.
・I think the problem is the display resolution and the display size.
--------
For example, when using "VU Meter 4 color bars" created by Case at 1920 x 1080 100% 23 inches, it was necessary to adjust the height of each bar.
After adjustment
(https://i.imgur.com/URy4IaF.png) (https://i.imgur.com/bdih0Kt.png)
The _scale function does windows DPI for you. No one should be entering anything manually. How stupid does one have to be to think the name of the function must be for something else entirely. :/
No script editing was ever needed for these functioning 100% / 200% layouts.
I only needed it to slightly change the x coordinate of the dropdowns, since I like the text inside the dropdown better aligned under the left side of the actually displayed pixels of the button instead of the whole dropdown window aligned with the beginning of the bs x coordinate.
Therefore I needed to adjust this x offset per windows scaling:
DPI = 96 * wscale / 100;
dx = x + (bs*bpos) - 32*(96/DPI)
This kind of works for 100, 125, 150, 175, 200, 225, 250, 300 and 350 windows scaling.
If you have a better way of aligning the text part of the dropdown with the left pixels of the button, I would be much obliged.
@marc2k3 I started some work to find a better solution not using custom vars and only use your _scale function, but encounter some issue I cannot solve.
The first part to solve the problem is to do an approximation of the first left pixel of the button, which of course depends on the used character.
For the kind of chars I use, I found a shift of bs * 0.14 does a pretty decent job and works with windows scalings of 100&175 and buttonsizes 24&48.
So far, so good. (pictures 1a,1b,2a,2b).
Now the only thing to do is to correct this value with the x coordinate you use for the textfields in a dropdown. I don't think this depends on bs.
With windows scaling 100 I find _scale(28) does the job. (pictures 3a,3b).
However I find that in windows scaling 175 an adjustment with _scale(28) is not correct. (picture 4a).
With windows scaling 175 I find _scale(44) does the job. (pictures 5a,5b).
What is my thinking error?
Can you please point me to the correct value of x of the textfields in a dropdown for different windows scaling based on your _scale function (thus not using custom vars)?
Sorry for all the attachments, but I wanted to show that I actually test my stuff.
@Defender
Reply #2109
> I think the problem is the display resolution and the display size.
Do you have a Display: 3840 x 2160 150% 27inch (4K)?
Try it then, you'll see right away.
--------
Reply #2109
"VU Meter 4 color bars"
Could you please try it at 1920 x 1080 100% 23 inches?
https://mega.nz/file/VPdnFBhY#KOqq0jictU97VjFQfmcra262LchYqNckenEwj_NDSIY
Line 140: var h = 21;
21 → 13
@Defender
Reply #2109
> I think the problem is the display resolution and the display size.
Do you have a Display: 3840 x 2160 150% 27inch (4K)?
Try it then, you'll see right away.
--------
Reply #2109
"VU Meter 4 color bars"
Could you please try it at 1920 x 1080 100% 23 inches?
https://mega.nz/file/VPdnFBhY#KOqq0jictU97VjFQfmcra262LchYqNckenEwj_NDSIY
Line 140: var h = 21;
21 → 13
I really don't know what you are talking about.
I do not use the VU Meter 4 color bars script.
Depending on the display resolution and the display size, some parts of the JSP 3 Script will need to be resized.
It's the same thing.
See Reply #2109: https://hydrogenaud.io/index.php/topic,110516.msg1057008.html#msg1057008
Depending on the display resolution and the display size, some parts of the JSP 3 Script will need to be resized.
It's the same thing.
Maybe in the VU script, but as Marc said not in the textsample script.
Only thing that does not align out of the box now are my modified positions for dropdown boxes for which I asked his help.
The issue I have is with the size of the "Size" button.
Where did my problem go?
The issue I have is with the size of the "Size" button.
Where did my problem go?
Again I have no clue what you are referring to.
If you mean changing the size of a button ... that has been solved with the two changes Marc indicated which I both implemented in my script 14a.
Not resolved. I have to adjust it myself.
I think it's best to adjust it yourself.
Are you referring to the difference that display resolution and the display size make?
The display size for comparison is Display: 1920 x 1080 100% 23 inches.
Display: 3840 x 2160 150% different from 27inch (4K).
Not resolved. I have to adjust it myself.
I think it's best to adjust it yourself.
Are you referring to the difference that display resolution and the display size make?
The display size for comparison is Display: 1920 x 1080 100% 23 inches.
Display: 3840 x 2160 150% different from 27inch (4K).
I don't have any issues. You do know that after changing the windows scaling you have to restart foobar to correctly redraw everything?
Reply #2104: https://hydrogenaud.io/index.php/topic,110516.msg1056998.html#msg1056998
I would be happy if you could make it a little smaller. It will be the same size as the previous button icon.
The extreme size difference that existed before is gone.
The _scale function does windows DPI for you. No one should be entering anything manually. How stupid does one have to be to think the name of the function must be for something else entirely. :/
No script editing was ever needed for these functioning 100% / 200% layouts.
Can you please point me to the correct value of x of the textfields in a dropdown for different windows scaling based on your _scale function (thus not using custom vars)?
Adjusted my button sized factor to find the first pixel of the displayed button to bs * 0.10 and did more testing.
The x coordinate of the textfields that has to be adjusted on the above value changes roughly _scale 4/5 per 25% change in windows scaling percentage.
var drop_offset = bs * 0.10; // Dropdown window x now under left pixels of button with normal sized char regardless of buttonsize
// var drop_offset = drop_offset - _scale(60); // 250 OK
// var drop_offset = drop_offset - _scale(54); // 225 OK
// var drop_offset = drop_offset - _scale(50); // 200 OK
// var drop_offset = drop_offset - _scale(44); // 175 OK
// var drop_offset = drop_offset - _scale(40); // 150 OK
// var drop_offset = drop_offset - _scale(32); // 125 OK
// var drop_offset = drop_offset - _scale(28); // 100 OK
Is there a component (borders or left margin?) inside your dropdown box code that does not use _scale?
I cannot adjust my code without using a hardcoded variable since in JS3 I have no way of knowing the current windows scaling.
Reply #2104: https://hydrogenaud.io/index.php/topic,110516.msg1056998.html#msg1056998
I would be happy if you could make it a little smaller. It will be the same size as the previous button icon.
Again I have no clue what you are talking about.
What or what button should be made a little smaller.
We are polluting the thread (exactly what I was afraid about), please send me PM's instead.
Hi,
the Jscript Panel3 github page is showing for me as "not found", did something happen?
marc took it down i think i use 3.81
https://hydrogenaud.io/index.php?msg=1054834
Moderator: removed attachment (there's another thread (https://hydrogenaud.io/index.php/topic,110499.0.html) for the component, this is the discussion thread)
@telboy1812 Thanks, i didn't realize he was also taking down the whole github with older versions and documentation, i was developing for it and couldn't access the documentation in the middle of the night :))
For reference for people looking for it in the future, the latest version is still available in archive.org, the latest backup being at:
https://web.archive.org/web/20241208093147/https://jscript-panel.github.io/
I'm trying to add some functionality to the original seekbar from the samples.
I added PlayOrPause to rightclick so you can start playing, pause or resume playing. Works.
I added some changes in the display of the TIME/seekbar stuff when width is limited. Also works.
I added hover on TIME/seekbar so the alpha goes up when being over the seekbar with the mouse. Works well too when playing. But not when paused or stopped.
While playing it uses the callback on_mouse_move to set the alpha, but this callback does not seem to be triggered when paused/stopped.
Checked all the docs, tried a lot but cannot activate the hover when paused/stopped.
Is there another callback I should use? Or does it require changes in seekbar.js?
Hi
I can't seem to find this script. Theres only an outdated version on github.
Hi
I can't seem to find this script. Theres only an outdated version on github.
Seems to be completely scrubbed now, even the 3.8.5 version that was left up for a while. "Why?" Nothing on the Wayback Machine link either besides documentation--clicking the 3.8.5 download link once it is finally found results in "url not archived."
The developer mentioned about putting some scripts on the Uploads forum, nothing there yet. I've attached it here, hopefully not breaking any rules.
Thank you very much. I will take a look at this because it seems most panels dont do what I want them to. Though I know this will be a pain.
I'm using JScript Panel 3 to get some Artists Info statistics and Similar Artists from lastfm.
The default path that this component is writing the json files is profile\js_data\artists\<artist Name>
I would like to change that to <artist folder>\lastfm
This way in case I delete the artist I would like this data to be removed otherwise it just keep growing.
Any ideas?
I'm trying to add some functionality to the original seekbar from the samples.
I added PlayOrPause to rightclick so you can start playing, pause or resume playing. Works.
I added some changes in the display of the TIME/seekbar stuff when width is limited. Also works.
I added hover on TIME/seekbar so the alpha goes up when being over the seekbar with the mouse. Works well too when playing. But not when paused or stopped.
While playing it uses the callback on_mouse_move to set the alpha, but this callback does not seem to be triggered when paused/stopped.
Checked all the docs, tried a lot but cannot activate the hover when paused/stopped.
Is there another callback I should use? Or does it require changes in seekbar.js?
Nevermind. I figured it out. It was the latter and a bit of the first.
Hello there, I know this might be abandoned but I'll try.
Is it possible to replace the spectogram view into waveform instead?
I tried to replace the ffmpeg command showspectrumpic in seekbar.js file into showwavespic but doesn't seems to work.
You'll need to remove the existing
this.properties.params.value from the command line as well because they won't apply here.
And looking at the docs, you'll need to add various other params as well.
But honestly, I'd just stick to this:
https://www.foobar2000.org/components/view/foo_wave_minibar_mod
edit: if you want to persist with the scripting, after the line that begins with
var cmd = console.log(ffmpeg_exe, cmd);
and then copy/paste the output from the fb2k console to a command prompt and run it. That will give clues as to it succeeding/failing.
Thank you Marc, it works.
Yeah, I also use the wave_minibar_mod components and it has been solid for years.
I'm just looking for ways to emulate this design, it's the Amberol music player for Gnome.
I think the waveform would fit well in the Text Display sample.
The black background is the issue now.
(https://i.imgur.com/fM84g3j.png)
Edit on_paint in the main panel to remove the black background
function on_paint(gr) {
gr.Clear(RGB(0, 0, 0));
seekbar.paint(gr);
}
In my scripts, it's there for when images can't be generated. You can remove it/change the colour.
I was trying the waveform on track + specto sample, I missed the gr.FillRectangle line haha.
Thanks again Marc!
Hello there, I know this might be abandoned but I'll try.
Is it possible to replace the spectogram view into waveform instead?
I tried to replace the ffmpeg command showspectrumpic in seekbar.js file into showwavespic but doesn't seems to work.
Note that command creates an actual waveform image (bg included), which will differ a lot from what you showed at that pic. There will also be no way to change colors unless you also edit the CMD or paint using masks, which will greatly increase complexity. And forget about increasing/decreasing resolution, proper resizing, etc. Also everytime you change a setting, files would need to be reanalyzed.
You have an actual usage of ffmpeg at my waveform script (https://hydrogenaud.io/index.php/topic,124385.msg1057785/topicseen.html#new) which avoids those drawbacks by painting the waveform using the audio data, not an image, which looks exactly like that pic (if you disable animation). It's obviously not for JSP3, but you can either use other JS host or reuse the design.
Thanks for the reply Regor.
The waveform images generated are actually has transparent layer, so the background can be adjusted from the script.
It's also generated really quickly without any performance impact, plus the cache files are smaller ~5kb per file, much smaller compared to spectogram.
It can also be resized and recoloured quite easily via the context menu command, I think it's simple enough for my use case.
Thanks for sharing your waveform script. I tried it, but honestly found it quite slow and not as fluid as I had hoped, even at the highest refresh rate. I appreciate your work on it, but I think I will explore other options for visualisation, thank you!
(https://i.imgur.com/FySeYTK.gif)
The waveform images generated are actually has transparent layer, so the background can be adjusted from the script.
Great, then color could also be changed easily with masks without needing to touch the command line.
It's also generated really quickly without any performance impact, plus the cache files are smaller ~5kb per file, much smaller compared to spectogram.
It can also be resized and recoloured quite easily via the context menu command, I think it's simple enough for my use case.
Well one thing is adjusting the command line to your specific system and theme, and another making it work in general. Your gif is just resizing the 1024x128 image to your panel size, which may work for you, but for sure will not work if the program is meant to be adjusted to different DPIs or sizes (that's what happens in Georgia Reborn) or when you have more than 2 channels. The image is just distorted in such case. There is also no interpolation for data when you resize to lower/higher sizes, thus as I said, being totally different to the pic you showed. And then you also have the problem of track length, where tracks with higher length will show more "precission" than those with lower length. (which is fine if you like it that way)
That's also why it's faster.
Thanks for sharing your waveform script. I tried it, but honestly found it quite slow and not as fluid as I had hoped, even at the highest refresh rate. I appreciate your work on it, but I think I will explore other options for visualisation, thank you!
The script is only slower at the analyzing step, since contrary to the image approach, it will actually scan and store the waveform data which can then be interpolated to any size. But that's done once, and data can be reused, applying UI settings on top.
Unless you talk about the "animation" but that's up to you to find your right settings, if you disable it, it's on par with your approach. My system is pretty slow and It doesn't take more than 1 second to analyze (in the example it says 500ms), and then data is reused. it's also within Georgia Reborn and considering the entire theme is JS based, there were zero complains about not being fluid, so not sure where your experiences comes from.
Btw data size is less than 1 / 2 kbs per file in my case, since I use LZ16 compression. Which is much lower than the spectogram, ffmpeg images or anything out there.

Full:

Normalization to a fixed width = your example pic: (any track, no matter their length, will display the exact same amount of data)

Then there are also a myriad of settings to tweak how things look (cover background, dynamic colors, waveform styles, etc.), like the C++ component marc recommended you (which also allows to set different colors to the already played and remaining parts). Just giving the info and some insights about the problems of using ffmpeg to draw images because you specifically asked to
emulate the design of your pic (which can't be done with ffmpeg alone), but use whatever suits you for sure :)
Edit: an image example, setting it to emulate your pic: (no current position, no alternate background, no animation, gray colors, width normalized to 2) with/out cover background
Hello, I would like to find the easiest way how to call a system command on track changes. I want to catch sample rate changes. I tried the very old foo_uie_biography which contains the possibility to run external command. It is outdated, it does not work for its original purpose (it supports only http, no https) and it attempts to contact allmusic server despite of I unconfigured everything what I could, but running an external command on track changes still works.
I would like to perform this task with some plugin or maybe API which is maintained and more current, preferably working in 64bit foobar2000 version. Could you suggest me one? Maybe the one of this thread, or any other which would be easy to setup for the given purpose?
Well I will not bother looking for the missing deleted docs for this component, but on SMP (x32) / JSplitter (x64) you have a callback which is called when playing a new track, which sounds to me a solution.
https://theqwertiest.github.io/foo_spider_monkey_panel/assets/generated_files/docs/html/module-callbacks.html#~on_playback_new_track
"on_playback_new_track"
I suppose the JSP equivalent is even named the same. In any case, both work for x64. You can run CMD commands there, adding this line to the callback:
new ActiveXObject('WScript.Shell').Run(command, 0, bWait);
For ex: (copy old.txt to new.txt, hide the CMD window and wait to finish)
new ActiveXObject('WScript.Shell').Run('CMD /C COPY "old.txt" "new.txt"', 0, true);
All together: (I don't think I added anything incompatible with JSP)
const WshShell = new ActiveXObject('WScript.Shell');
const command = 'CMD /C COPY "old.txt" "new.txt"';
function on_playback_new_track(handle) {
if (handle) {WshShell.Run(command, 0, false);}
}
@regor Thank you very much! Your code worked so I could adapt it. Much better for my needs than my yesterday attempt with foo_uie_biography.
Glad you got it working.
I think I may create a script for this case, since "foo_uie_biography" is dead, for my toolbar buttons. Something which would easily allow to set a callback (on track played) and a CMD action, just using simple menus. No need to know anything about JS for that, so anyone could easily set their own actions.
@regor If it would allow to choose a callback, it would be really easily usable by anybody. Best if one could use title format strings about content played for example %album% or %samplerate%, so they could be set as command line parameters of the called external command.
My use case: I am using virtual audio cable to send foobar2000 output to other application. To avoid unnecessary resampling, I need to set sample rate in the other program to be the same as of the content played in foobar2000. From this reason I need to catch sample rate changes. It takes some time for the receiving program to process the sample rate switch, therefore I need to delay playback for few seconds. Since I need to perform more foobar2000 related operations at once, it is advantage for me to use SMP with javascript.
Other thing is that I generally understand programming, but I'm used to do simple procedural programming (bash, perl and python) with no things like async actions and event handlers. I didn't do any javascript programming before, but with some help from web I ended with this working code:
let last_sample_rate = null;
const WshShell = new ActiveXObject('WScript.Shell');
function on_playback_new_track(handle) {
if (handle) {
let current_sample_rate = fb.TitleFormat("%samplerate%").Eval();
let command = `CMD /C D:\\tools\\sr-switcher\\sr-switcher.bat ${current_sample_rate}`;
if (last_sample_rate != null && current_sample_rate != last_sample_rate) {
fb.Stop();
WshShell.Run(command, 0, false)
setTimeout(() => fb.Play(), 2000);
}
last_sample_rate = current_sample_rate;
}
}
Maybe some things are not optimal, but it works. Thanks for your previous help!
Question about applying an effect (luminance) on a given image before saving.
I have a blurred image, I can save it and use it elsewhere outside of JS3.
Problem is that when the original image is too bright also the blurred image will be too bright.
I played a bit around with GetColourSchemeCount(count) and Luminance(colour), but I cannot find any documentation about the first function.
When count = 1 does it return the average colour for the whole image?
Or do I need for instance count 5 to get more predominant colours and if so is there also a weight available per returned array element (colour)?
In the end I want to calculate the overall luminance for a given image, then alter the luminance of the original image based on this calculated value, and then save.
I noticed there are some effects you can apply to an image (grayscale, invert, sepia), but those effects do not include increase/decrease luminance.
When the calculated luminance is too high, I could invert the image before saving, but that means I lose the original colours.
The JS3 draw functions themselves do accept an alpha setting upon displaying, but those are only available within JS3.
Does anyone have an idea, how to change the luminance of an image before saving?
Obviously there is no builtin way for that. Neither you need it (although going that route, I would say JSP is simply not the right tool and you should execute a third party binary via CMD).
Just paint a black layer over the image with low alpha until you get your desired effect. You may also do a similar thing with a grayscale layer, and also have in mind you can use inverted and B&W images as alpha masks too (so you can selectively brighten/darken some parts).
For luminance, contrast and complex color manipulations I use chroma.js (https://regorxxx.github.io/chroma.js/) , I think the original repo is also being updated too. Don't expect further guidance by me about that part thought.
Just paint a black layer over the image with low alpha until you get your desired effect. You may also do a similar thing with a grayscale layer, and also have in mind you can use inverted and B&W images as alpha masks too (so you can selectively brighten/darken some parts).
Does not work, because dark blurs will be darkened even more (and I actually want those dark blurs appear brighter).
I also want to keep the original album cover colors as the theme colors and not a inverted, sepia, b&w variant.
For luminance, contrast and complex color manipulations I use chroma.js (https://regorxxx.github.io/chroma.js/) , I think the original repo is also being updated too. Don't expect further guidance by me about that part thought.
I had a look in chroma.js and did not find anything to manipulate an image, and since I won't get any guidance for using this I consider it a dead end.
But I solved my issue, I now calculate the luminance of the dominant color and put that in the name of the blur image I save.
In PSS and ELP I modify the user requested base alpha based on this luminance value of the blur, either increasing (blurs with low luminance) or decreasing (blurs with high luminance).
Works remarkably well.
Does not work, because dark blurs will be darkened even more (and I actually want those dark blurs appear brighter).
I also want to keep the original album cover colors as the theme colors and not a inverted, sepia, b&w variant.
Either I didn't explain it enough or you are not doing it right. If you have an image with shadows and lights, and you use the same image as a mask, then light areas will be filled while dark areas will be omitted. Thus, if you invert the image, to use it as a mask, and you apply a white tint, it necessarily brightens the dark areas.
That has nothing to do with changing colors. But obviously you can use inverted, sepia or b&w variants as masks to selectively darken or brighten certain areas.
Additionally you can paint the image over a dark or white background with alpha applied, which is just the inverse operation.
In particular, you may apply such trick to paint the image over a background filled with an specific color (the most dominant for ex), with alpha. So everything will be nuked, except colors which have greatest contrast against it. You can use such image as a mask again, converting it to B&W.
In PSS and ELP I modify the user requested base alpha based on this luminance value of the blur, either increasing (blurs with low luminance) or decreasing (blurs with high luminance).
Works remarkably well.
To be honest I don't get how that's a solution to the problem. Or better said, why it was a problem in the first place.
If you already know the image is too bright (in JSP) and you just decrease the alpha on that case (in ELP), you are not changing the luminance of the source image at all, just doing a workaround xd which was my point, JSP or SMP are not image editors. You can apply tricks, that's all. (since changing transparency will just nuke darken areas, to try to save brighter areas)
But then, if you just apply a lower alpha (in ELP), you could also just save the image as png with a base transparency already applied (in JSP). There is no need to apply it in a third party panel (?) Unless I'm missing something, I don't see the difference between saving an image at 30% transpareceny as png or loading it in ELP and applying a 30% transparency there + the user value, since you are already clipping the max transparency in any case to that 30%. (leaving performance or other things out of the equation)
Anyway glad you found a way!
Hi
@regor I was able to follow your suggestion in 32bit foobar2000 but I didn't find a way how to do it in JSplitter (since 64bit SMP probably doesn't exist - I didn't find it). Please see https://hydrogenaud.io/index.php/topic,126743.msg1060790.html#msg1060790
Hey folks, question: is there a way to check whether a main menu command is enabled or not when a script first initializes?
I made a button to show status of Skip Tracks (foo_skip) command ("Playback/Skip tracks & use bookmarks") and to toggle it on/off, using panel properties to remember the setting. That all works fine. The problem now is I made different layouts with another instance of the button that does not remember the current setting.
I guess it'll be something to do with fb.EnumerateMainMenuCommands() (https://web.archive.org/web/20241201230443/https://jscript-panel.github.io/docs/namespaces/fb/#fbenumeratemainmenucommands) and I see the example there prints all checked commands to console, but I'll need an example how to return a true/false on just the above command since I'm not savvy with the JS.
Thanks for any help. :)
You can write something like...
var str = fb.EnumerateMainMenuCommands();
var arr = JSON.parse(str);
var checked = arr.filter(function (item) {
return item.FullPath == "Playback/Skip tracks & use bookmarks" && item.Checked;
});
if (checked.length == 1) {
console.log("This item is checked");
}
But of course changes cannot be detected while fb2k is running.
Thanks Marc :) - That works perfectly, and I got it working in the button script eventually (I had some trouble getting buttons.update() to update after changing the panel property, but then realized probably no longer need to set a property. In any case it works the way I wanted now)
Cheers
help to align the text in the text reader according to the center - I understand what's in the file "panel.js" but only the header is aligned, the text itself remains on the left edge
DWRITE_TEXT_ALIGNMENT_LEADING, DWRITE_PARAGRAPH_ALIGNMENT_CENTER, DWRITE_WORD_WRAPPING_NO_WRAP, DWRITE_TRIMMING_GRANULARITY_CHARACTER
help to align the text in the text reader according to the center - I understand what's in the file "panel.js" but only the header is aligned, the text itself remains on the left edge
DWRITE_TEXT_ALIGNMENT_LEADING, DWRITE_PARAGRAPH_ALIGNMENT_CENTER, DWRITE_WORD_WRAPPING_NO_WRAP, DWRITE_TRIMMING_GRANULARITY_CHARACTER
Don't know what function you mean, but for instance:
LEFT: gr.WriteText(txt, font, colour, x, y, w, h, 0, 2);
RIGHT: gr.WriteText(txt, font, colour, x, y, w, h, 1, 2);
CENTER: gr.WriteText(txt, font, colour, x, y, w, h, 2, 2);
^Tbat's not it.
Scripts that have scrollable text use a different API. You have to open
samples\js\text_reader.js and change line 74 from
this.text_layout = utils.CreateTextLayout(this.text, this.properties.fixed.enabled ? 'Consolas' : panel.fonts.name, _scale(panel.fonts.size.value));
to become...
this.text_layout = utils.CreateTextLayout(
this.text,
this.properties.fixed.enabled ? 'Consolas' : panel.fonts.name,
_scale(panel.fonts.size.value),
DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
DWRITE_TEXT_ALIGNMENT_CENTER
);
Thanks, it worked! I really miss the hand/cursor scroll, I'm learning the language, I'm inserting a translation into the panel under the lyrics, the fact is that you can drag the cursor in the upper panel, but when you switch to the text, you want to use the reader out of habit.
+ Last.fm Artist Info + User Info - I think that an invaluable contribution to the development of the player would be the ability to add tags to the body of the GENRE file, and I ask you to remake the script as follows: when selecting information about the artist of the top tags - tags should start with capital letters and be divided according to the general rules - a semicolon, in one line - when clicking on the panel, they should be copied to the clipboard for subsequent editing, and ideally added to the file, as I said above
Progressive Deathcore; Progressive Death Metal; Progressive Metal etc
When updating foobar2000 to version 2.24.3 on top of the DarkOne v4 mod based on v1.5.8.0, an error appears at startup:
JScript Panel JScript Execution error
The object cannot be created by the object programming server
File: <main>
Line: 60, Col: 1
How can I fix it?
Unfortunately, the mod is no longer supported by the author.
https://imagizer.imageshack.com/img922/342/z0oOeW.jpg
When updating foobar2000 to version 2.24.3 on top of the DarkOne v4 mod based on v1.5.8.0, an error appears at startup:
JScript Panel JScript Execution error
The object cannot be created by the object programming server
File: <main>
Line: 60, Col: 1
How can I fix it?
Unfortunately, the mod is no longer supported by the author.
https://imagizer.imageshack.com/img922/342/z0oOeW.jpg
Since no one responds.
What happens when you upgrade JS2 from 2.3.6.1 to JS2 2.8.8 (on fooBar 2.24.3 32bit of course)?
NB. It would have helped if you had attached the script itself to your post, since there are several variants of the original DarkOne button script.