Variable not updated in time

I have a floating menu (related to the YouTube video which is playing) with few "Standard items" showing different info and doing some actions. One of these items is executing "Run Real JavaScript" and it is doing its magic fine (adding a YouTube video in a specific playlist), but I guess there's an issue with a persistent variable which it should set "custom_var_result_from_add_video_to_playlist". This variable is NOT being set correctly the first time I click the "Standard item", but only the 2nd time.

Here's the script itself:

async function itemScript(itemUUID) {

    let pythonScriptPath = "/Users/myuser/Documents/btt/scripts/youtube_all_in_one.py";
    let venvPath = "/Users/myuser/tmp/venv_youtube/"

    let searchQuery = await get_string_variable({variableName: "BTTNowPlayingInfoTitle"});
	let channelName = await get_string_variable({variableName: "BTTNowPlayingInfoArtist"});
    let video_id = await get_string_variable({variableName: "custom_var_video_id_from_safari"});
	let searchQuery_escaped = searchQuery.replace(/'/g, "'\\''")

    let command = `source '${venvPath}/bin/activate' && python3 '${pythonScriptPath}' "${video_id}" "${channelName}" "${searchQuery}"`;

    let result_from_add_video_to_playlist = await runShellScript({"script": command});

    await set_persistent_string_variable({variableName: "custom_var_result_from_add_video_to_playlist", to: result_from_add_video_to_playlist})
	console.log('result_from_add_video_to_playlist', result_from_add_video_to_playlist);
	return result_from_add_video_to_playlist;
}

As you can see from the below screenshot, the variable "custom_var_result_from_add_video_to_playlist" has not been updated and it is showing previous message. Its value now should be "The Weather Girls - It's Raining Men (Video) added to favorites" since indeed it has been added.

So now after the video is added to the playlist if I click again the same "Standard item" correct value is populated - "The Weather Girls - It's Raining Men (Video) already in Favourites"

If I execute the python script, which is actually adding the video to the playlist, from my terminal I get the correct output/stdout which should then be assigned to "result_from_add_video_to_playlist" and then respectively to "custom_var_result_from_add_video_to_playlist", but it is not working for some reason.

This was working quite well a long time ago.

might be a problem related to a recent fix that prevents js deadlocks in some situations. Most likely even a very small delay will resolve this. I'll have a look!

1 Like

I have tried to reproduce the issue, but was unable to.

Does it work for you with a simple script like this?

async function itemScript(itemUUID) {
    let date = await runShellScript({script:"date"});
    await set_persistent_string_variable({variableName: "savedDate", to: date});
	let result = await get_string_variable("savedDate");
	return result;
}

Is the problem maybe that BTTNowPlayingInfo variables do not updated immediately?

This works well every time compared to the behavior I'm seeing - upon 1st click video is added to the playlist, but vars are not updated on BTT. If I trigger adding to playlist again, while on the same video, every time I got the correct result/var - $someRandomSong already in Favourites

BTTNowPlayingInfo are updated immediately

Does the console.log you added output the correct result?

How to see that?

Ah sorry, you can access the logs by using Safari's develop menu (developer mode needs to be activated)

Alternatively you can use BTTLog("somelog") instead, then it will be written to the log files in ~/Library/Application Support/BetterTouchTool/Logs

I've checked few random "Java Script runner" and "JS Runner" ones, but was not able to find anything meaningful. I see there's itemScript for some items, but is this the action ID:

or something else, because I cannot see that action's UUID in Safari

Ah I somehow thought this was a content script for a floating menu item. In case of the "run real javascript" action it's harder to use the safari menu because as you figured it's often hard to find the correct item. (You could rename the script to something unique, then it might be easier)

BTTLog() might be easier here:

BTTLog(`result_from_add_video_to_playlist  ${result_from_add_video_to_playlist}`);

There's nothing in the logs 1st time the script is executed only the 2nd time.

Andreas, do you have any ideas?

If there is nothing in the logs it would mean the console.log code is never reached.
I could only think of something throwing an exception, but the runShellScript should only do that in very weird cases.

You can try wrapping the code in a try catch to see whether any exception is logged

async function itemScript(itemUUID) {
    try {
        let pythonScriptPath = "/Users/myuser/Documents/btt/scripts/youtube_all_in_one.py";
        let venvPath = "/Users/myuser/tmp/venv_youtube/";

        let searchQuery = await get_string_variable({ variableName: "BTTNowPlayingInfoTitle" });
        let channelName = await get_string_variable({ variableName: "BTTNowPlayingInfoArtist" });
        let video_id = await get_string_variable({ variableName: "custom_var_video_id_from_safari" });

        let searchQuery_escaped = searchQuery.replace(/'/g, "'\\''");

        let command = `source '${venvPath}/bin/activate' && python3 '${pythonScriptPath}' "${video_id}" "${channelName}" "${searchQuery}"`;

        let result_from_add_video_to_playlist = await runShellScript({ script: command });

        await set_persistent_string_variable({
            variableName: "custom_var_result_from_add_video_to_playlist",
            to: result_from_add_video_to_playlist
        });

        console.log('result_from_add_video_to_playlist', result_from_add_video_to_playlist);
        return result_from_add_video_to_playlist;
    } catch (error) {
        console.error("Error in itemScript:", error);
        await set_persistent_string_variable({
            variableName: "custom_var_result_from_add_video_to_playlist",
            to: `Error: ${error.message || error}`
        });
        return "error";
    }
}

Maybe some part of the shell script causes it to not exit / return :thinking:

Btw. I added a basic log viewer to the scripting/variables view in BTT.

I've troubleshooted using the BTT configuration window and running the script directly using "Run Script" button:

and I've got the output from the script in the "Script result" field:

TypeError: undefined is not an object (evaluating 'BTT.set_persistent_string_variable_internal')

Does this help you?

that would mean the script is trying to set a undefined value - most likely the result of the python script.

Maybe add another log to log the exact command that is executed and see whether anything is weird in that

console.log(command)

I can confirm that the exact command is correct and it is working as expected (video added to playlist + output to stdout) - I've copy/pasted it from the output of console.log(log); and tested it manually.

I've noticed an interesting thing - if my python script initially produce the 2nd possible output - "Already in Favourites" (meaning that I'm trying to a video already in my playlist) then if I play next video and try to add, this new new video, it in the playlist - it works and it works each time.

Maybe the difference is the used shell. By default the runShellScript function uses /bin/bash, but macOS default is nowadays /bin/zsh

Could you try this?

 let result_from_add_video_to_playlist = await runShellScript({ script: command,  launchPath: '/bin/zsh', });

By default BTT uses the first thing written to stdout. Maybe the script writes something else at first, but then continues writing the expected output?

Appreciate your ideas on this!

By default BTT uses the first thing written to stdout. Maybe the script writes something else at first, but then continues writing the expected output?

If that was the case the var would never have the correct value, right? Either way - I'm only printing the actual message.

My default $SHELL is /bin/bash, so there's no difference.

I've included the following check in the script:

    if (result_from_add_video_to_playlist && result_from_add_video_to_playlist.trim() !== "") {
        await set_persistent_string_variable({variableName: "custom_var_result_from_add_video_to_playlist", to: result_from_add_video_to_playlist});
    }
    else {
		console.log('No result from python script console')
        BTTLog('No result returned from Python script');
    }

and the if condition is being executed because it is trying to set_persistent_string_variable(), but again I'm once again getting:

TypeError: undefined is not an object (evaluating 'BTT.set_persistent_string_variable_internal')

I have also tried
await set_persistent_string_variable({variableName:"custom_var_result_from_add_video_to_playlist", to: 'test'});

to remove all dependencies from the python script and still this var was not set and the same error was shown.

If I do not set the variable custom_var_result_from_add_video_to_playlist using set_persistent_string_variable() or set_string_variable() and leave only return result_from_add_video_to_playlist;, the proper output from the python script is shown always in the BTT's "Script Result" field.

That is interesting, thanks for the details. I'll add some logs to the next version that should clarify what is happening.

Maybe I found something already. Could you check whether 5.738 solves this? (I'll be back later today, need to leave now but the upload of that version should finish within the next ~10min)