Skip to main content

Notice

Please note that most of the software linked on this forum is likely to be safe to use. If you are unsure, feel free to ask in the relevant topics, or send a private message to an administrator or moderator. To help curb the problems of false positives, or in the event that you do find actual malware, you can contribute through the article linked here.
Topic: JScript Panel script discussion/help (Read 366715 times) previous topic - next topic
0 Members and 2 Guests are viewing this topic.

Re: JScript Panel script discussion/help

Reply #1451
@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.

Code: [Select]
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


Re: JScript Panel script discussion/help

Reply #1453
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.

Re: JScript Panel script discussion/help

Reply #1454
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.


Re: JScript Panel script discussion/help

Reply #1455
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.

Re: JScript Panel script discussion/help

Reply #1456
@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?

Re: JScript Panel script discussion/help

Reply #1457
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

Re: JScript Panel script discussion/help

Reply #1458
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.

Re: JScript Panel script discussion/help

Reply #1459
Try

function on_script_unload() {
   window.NotifyOthers("Test",1);
}


Re: JScript Panel script discussion/help

Reply #1460
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.

Re: JScript Panel script discussion/help

Reply #1461
Quote
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.

Re: JScript Panel script discussion/help

Reply #1462
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.

Re: JScript Panel script discussion/help

Reply #1463
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.

Code: [Select]
// ==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();
}

Re: JScript Panel script discussion/help

Reply #1464
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.


Re: JScript Panel script discussion/help

Reply #1465
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?

 

Re: JScript Panel script discussion/help

Reply #1466
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


Re: JScript Panel script discussion/help

Reply #1467
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.

Re: JScript Panel script discussion/help

Reply #1468
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

Re: JScript Panel script discussion/help

Reply #1469
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.

Re: JScript Panel script discussion/help

Reply #1470
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

Re: JScript Panel script discussion/help

Reply #1471
Code: [Select]
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.

Re: JScript Panel script discussion/help

Reply #1472
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:
Code: [Select]
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?

Re: JScript Panel script discussion/help

Reply #1473
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.

Re: JScript Panel script discussion/help

Reply #1474
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.