RealRaven2000 / FiltaQuilla

Adds many new mail filter actions to Thunderbird
http://quickfilters.quickfolders.org/filtaquilla.html
GNU General Public License v3.0
87 stars 15 forks source link

Feature Request tts espeak or execute script with parameters (Linux) #233

Closed Luxi84 closed 1 year ago

Luxi84 commented 1 year ago

Hello a tts feature would be nice, like: espeak -v[Voice/Language] -[parameters] "text to say"

I was not able to execute a bash script with parameters (script.sh [p1] [p2]) not with execute Program or execute File, am I doing anything wrong? (File is marked es executable (chmod a+x filename)) I am using Linux.

Regards Martin

RealRaven2000 commented 1 year ago

Sorry I am a complete idiot on Linux. If that's (bash) even Linux.

If you want me to test something in a virtual machine (Ubuntu), just pretend you're dealing with a 5 year old.

Luxi84 commented 1 year ago

bash scripts start but not with Parameters e.g.

executable.sh (starts) executable parameter1 parameter2 or executable "parameter1 as String" "parameter2 as String" (bashscript.sh "String to use as Parameter1" "String to use as Parameter2" don't work) I filtered from an exchange somthing like that: (Subject of Mail) Someexchange Buy Order Coin1/Coin2 filled and wanted Filtaquilla to use (for my bash script which ist using a text to speach (espeak) to say "Coinname buyed" Filtaquilla should start the bash script with two parameters: bashscript.sh "buy order filled" "Coin1/Coin2" (with Parameters (as String)) but I was just able to start any bashscript without any Parameter.

Your 5 and you programed Filtaquilla or did you fork it? Otherwise Thumbs up :-)

I am not sure which command you use and which language it is based on, I can take a look an do some research maybe I can post some Code snipped so that Parameters for execution (for "execute Program") could be used.

fe-hicking commented 1 year ago

Out of curiousity - does your bash script not start at all, or is it "just" missing the parameters?

Maybe quoting/escaping modifies the quoted parameters? Did you try it with static parameters, single string, no quotes? Or single quotes?

That text to speech idea is awesome, I've got to use that. 😅

RealRaven2000 commented 1 year ago

Your 5 and you programed Filtaquilla or did you fork it? Otherwise Thumbs up :-)

😅

I didn't fork it, but I took it over from its original author, Kent James, who retired for health reasons. There were a number of Add-on developers in our little bubble who took over development of his many useful Add-ons. I know a bit about Add-on development (I started in 2009 with writing patches for QuickFolders, which was also gifted to me later) but it's mainly in Windows where I do all my development and 99.8% of testing.

Since I did a "bit" of work in the Filter space with my little Add-on quickFilters, (and also wrote a patch for Tb and some code for Postbox) and there are many users in that group who are also interested in filtaQuilla.

I am not sure which command you use and which language it is based on, I can take a look an do some research maybe I can post some Code snipped so that Parameters for execution (for "execute Program") could be used.

I would love that, it's in JavaSCript, look at this part in filtaquilla.js:

https://github.com/RealRaven2000/FiltaQuilla/blob/ESR115/content/filtaquilla.js#L506

Running the file is dependent on the XUL interface nsIProcess (probably something from the bad old Netscape days):

let theProcess = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess)

I bet this is not a Mail specific interface (so it is not part of the comm-central codebase) but one from Mozilla (m-c / mozilla central) which is the core of Firefox. These interfaces are not accessible for true (API based) "mail extensions" and we can onlyu access them via "experimental" code, which gives us an exception to use the code that the Thunderbird frontend also uses. This JavaScript layer runs most of the UI and quite a bit of the logic, but many of the XUL interfaces are just scriptable commands that go straight into C++ / compiled code that can easily crash Thunderbird. Hence they are not supported officially for Add-on devs.

The interface is defined here: https://searchfox.org/mozilla-esr115/source/xpcom/threads/nsIProcess.idl#11

I don't really dive as deep as the C++ but I believe the source code for external processes might be here(?) https://searchfox.org/mozilla-esr115/source/xpcom/threads/nsProcessCommon.cpp#60

I don't debug THunderbird compiled code anymore because it is just a PITA and above my paygrade. But I am happy to step through front end code using the built in JavaScript debugger (Ctrl+Shift+J) if you can share an easy bash script I can test. Maybe a script that outputs a text to the screen?

RealRaven2000 commented 1 year ago

PS: I am actually 57, but the intellectual abilities seem to go in a parabolic curve. Also since I got infected with the music production virus I am putting 98% of my spare capacity for technical knowledge into Cubase Pro and Mixing / Arrangements / Music Theory. Learning Curves are steep.

fe-hicking commented 1 year ago

Wow what a great intro to getting started. I read the code as if parameters are enrered like:

/path/to/script.sh,param1,param2,...

instead of

/path/to/script.sh param1 param2

Could you try that? I'm only on my mobile right now but I'm so excited about the idea, I'll circle back to it during the week and will try it out on my own. 🥹

RealRaven2000 commented 1 year ago

Cool, I am open to any patches you may throw my way. BUilding the Add-on is extremely simple, just zip the root folder into an archive. you can then drop the archive into Add-ons Manager to install it permanently. Or:

image

Luxi84 commented 1 year ago

I tried /pathtoscript/script.sh "parameter1" "parameter2" that dit not work what works was: /pathtoscript/other-script.sh

Not sure if FQ accepts script.sh, "stingparameter1", "strinparameter2" but I will test it (seperatet with ",")

I think it has sure somthing to do how the handofer to execute Program is coded. I took a short look (searched in the code in the js Files) but I just found the fq.runfile I ditn't found runProgram so I have to take more Time to look, I just developed some Pascal and C++ not JS and I am no Pro but I am interested in to solve it, but it would take some time to dig into.

I've had to understand the Code I know a little bit of how to use espeak (with mbrola Voice) in Linux but this is surley wanted Windows/Linux and multiple languages and this is a little bit more but we will see, it is long ago I see "ifdef" for OS=Linux and OS=Windows and than use Courtana API on Windows and maybe espeak on Linux and then get it togheter with the given Code for Language X/Y this is sure some work.

Luxi84 commented 1 year ago

@fe-hicking you're right but I had to change my Script a bit...

I have found a simple solution for myself by modifying my script so that it doesn't accept parameters within double quotes like:

Instead, I use ["buy"] and ["sell"] as [-b] or [-s] and "STORJ/BTC" as [STORJ_BTC] like:

In Filtaquilla, it actually separates them with a comma, so:

/Path-to-Script/bittrex.sh,-b,STORJ_BTC

works!

Here is my Code if anyone is interested in:

#!/bin/bash

# Check if first Parameter is -b (for buy) if [ "$1" == "-b" ]; then # Check if the second parameter is "STORJ/BTC" if [ "$2" == "STORJ_BTC" ]; then espeak -vmb-de5 -b1 -s110 "Storj tokens were purchased" fi fi

# Check if First Parameter is -s (for sell) if [ "$1" == "-s" ]; then # Check if the second parameter is "STORJ/BTC" if [ "$2" == "STORJ_BTC" ]; then espeak -vmb-de5 -b1 -s110 "Storj tokens were sold" fi fi

this is OK for a Test Yes it could say were purchased sold for BTC but I didn't need this at the Moment and for the First Time I did not check multible Tokens.

This workaround works well, as otherwise, a lot of code in FiltaQuilla would need to be modified. My script uses espeak for speech output under Linux (it's a Bash script) with the German mbrola voice 5. The 's' parameter controls the speech speed, and 'b1' was, I believe, for UTF encoding. My code was originally in German, but I had it translated.

Luxi84 commented 1 year ago

Thanks for your efford @RealRaven2000, Thunderbird already uses the built in Notification System on my System.

The Prameters work in the Edit of FQ seperatet with [,] as @fe-hicking correctly said but I did not know how to parse Double Quotes correctly to FQ so I changed my Code and it now works for me.

I am not that good in developing for Crosscompiling (Windows and Linux) maybe just use the Windows built in Speech API and for Linux I use espeak as I said, tts is not on every Distro preinstalled so maybe there had to be a hint, install tts package x/y.

Luxi84 commented 1 year ago

@fe-hicking maybe there are better sounding tts than espeak I dit not test every program so I think with as you are right, the Parameters as you said, it wouldn't be a Problem even under Windows to let a Script (Powershell or so) to interact with Qortana. Just filtering the Mail, and give the Parameters a Script which uses Qortana. OK built in tts in FQ would be nice.

fe-hicking commented 1 year ago

Nice!

On OSX I use the built-in "say" now. I create a simple /Users/garvin/saymail.sh file:

#!/bin/bash
sleep 1
mail="$2"
re='(.*)<[^>]+>+(.*)'
while [[ $mail =~ $re ]]; do
  mail=${BASH_REMATCH[1]}${BASH_REMATCH[2]}
done
say -r 200 -v "Anna" "$mail, Subject $1"

and in FiltaQuilla similar to youI configured:

/Users/garvin/saymail.sh,@SUBJECT@,@AUTHOR@

There's some extra "magic" in the Bash-Script that removes the mailaddress in angular brackets from being read out. The sleep is in there to wait a second, because another incoming mail jingle arrives just before.

Seems to work at first glance, not sure yet what happens when multiple mails are received at the same time - if they overlap, or are executed in sequence.

RealRaven2000 commented 1 year ago

So there is some documentation here:

https://quickfilters.quickfolders.org/filtaquilla.html#run_file

And it's called runFile in source code (even though it is technically run program) - that was just Kent's choice.

Run Program: This action takes the file name of an executable, and runs a new process with that file. It differs from Launch File in that “Launch” will use a file’s type to decide what program to run, while in Run File the program to run is explicitly given.

In addition, Run Program can accept parameters. The text that is generated when you select a file to run in the filter editor may be modified by you to include a set of parameters to run, separated by commas. The whole line is a little difficult to see and edit because of the limited space available, but if you select the text and move your cursor to the right, you can edit the parameters that are sent to the process when it is run.

The parameters that are used to run the file can include information from the message header. Special character values beginning and ending with “@” are used to denote replaceable parameters that are sent to the process to run. For example, a file line like this:

C:\PROGRAMS\runme.exe,@SUBJECT@,@MESSAGEID@

will run the program “runme” with two parameters, the first being the subject and the second the message id. This is, in fact, the default parameters that are used when a file is selected. The full list of available substitutable parameters is:

  // @SUBJECT@ subject
  // @MESSAGEID@ message Id
  // @AUTHOR@ author
  // @RECIPIENTS@ recipients
  // @DATE@ date (local string)
  // @CCLIST@ cc list
  // @DATEINSECONDS@ date in seconds
  // @MESSAGEURI@ URI for the message
  // @PROPERTY@somedbproperty@ uses .getStringProperty(“somedbproperty”)

The last item actually has a second internal substitutable parameters. It is intended to be used with a custom DB header, such as “X-SPAM”. You must first define the custom db header by adding that header to the preference mailnews.customDBHeaders, then you can use that header in this parameter list.

I did link you to the source of the action: https://github.com/RealRaven2000/FiltaQuilla/blob/ESR115/content/filtaquilla.js#L506

the comma separated parameters are converted here:

          // convert parameters
          let parameters = new Array(parmCount);
          if (isUnicode) {
            for (let i = 0; i < parmCount; i++) {
              let pRaw = _replaceParameters(aMsgHdrs[messageIndex], args[i + 1]);
              parameters[i] = utf8To16(pRaw);
            }
            theProcess.runw(false, parameters, parmCount); // [issue 102] decoding problems -  UTF-16
          }
          else {
            for (let i = 0; i < parmCount; i++) {
              parameters[i] = _replaceParameters(aMsgHdrs[messageIndex], args[i + 1]);
            }
            theProcess.run(false, parameters, parmCount);
          }

so the function _replaceParameters converts any keywords and probably just passes throuhd plain string arguments. Not sure that using "double quotes" is necessary. I would just avoid using "," within the string.

RealRaven2000 commented 1 year ago

Seems to work at first glance, not sure yet what happens when multiple mails are received at the same time - if they overlap, or are executed in sequence.

As all filters run synchronously, they are indeed executed in sequence. But I am not sure right now whether theProcess.run() run synchronously and waits for the process to end. That might potentially be a performance problem...

fe-hicking commented 1 year ago

I had the issue occur now, and indeed it fired the events asynchronously, so two mails got read aloud at the same time. That wasn't a problem, in my simple bash script I added some dumb locking mechanism, that just lets every followup instance wait until the previous one released its lockfile:

#!/bin/bash
sleep 1

while [ -f /tmp/saymail.log ]
do
  sleep 2
done

touch /tmp/saymail.log

mail="$2"

re='(.*)<[^>]+>+(.*)'
while [[ $mail =~ $re ]]; do
  mail=${BASH_REMATCH[1]}${BASH_REMATCH[2]}
done

say -r 200 -v "Anna" "$mail, Subject $1"

rm /tmp/saymail.log

Seems to work, but I'm not sure if race conditions may apply. I really like that new mechanism, thanks for mentioning this here.

(Personally I believe the issue can be closed since everything works well :-) )

Luxi84 commented 1 year ago

Maybe

start the reading of the Mail if say Process is not running, Maybe a Delay and "Next Mail ..." under Linux pgrep -p could be used.

Luxi84 commented 1 year ago

Maybe somthing like so

# Name of the process to check and start process_name="say"

# Parameter for the process Parameter1="Your_Parameter1"

while true; do # Check if the process is running if pgrep -x "$process_name" > /dev/null; then echo "The process $process_name is already running." else # If the process is not running, start it with Parameter1 echo "Starting the $process_name process with Parameter1: $Parameter1" "$process_name" "$Parameter1" & fi # A short pause before the next check (e.g., 5 seconds) sleep 5 done

Luxi84 commented 1 year ago

OK than I will close the Issue/Feature Request hope everyone is fine with it.

RealRaven2000 commented 1 year ago

OK than I will close the Issue/Feature Request hope everyone is fine with it.

That's fine with me. I was wondering whether the nsIProcess.run() could be synchronized by using await nsIProcess.run() and turning

self.runFile = async () => {
  // ... code for calling external processes
  await theProcess.run(false, parameters, parmCount);
}

... but that would probably be useless because it is still called from Thunderbird core like a "Normal" synchronous function, (Without await) - I guess they would need to patch all their code to make all filter actions async to fix this.