3

I'm using a function in a userscript that I'm writing which does not work in Greasemonkey due to the limitations of Greasemonkey. This function is not necessary for proper operation of the userscript, but it improves user experience, so I don't want to just remove it entirely.

I tried using a try { ... } catch() { ... } block, but unfortunately Greasemonkey ceases execution of the script as soon as it attempts execution of the function instead of throwing an exception. So I instead decided to prevent execution of the function when the script is loaded via Greasemonkey, but I have been unable to find a method of doing that.

How can I go about detecting whether the active userscript manager is Greasemonkey or not?

Random Logic
  • 132
  • 12
  • Is any of that useful to you? https://userscripts-mirror.org/topics/96693 – Pinkie Pie Sep 08 '17 at 18:22
  • @Pinkie Unfortunately no, as that checks for the existence of GM* functions, which are also available in most other userscript managers (specifically Tampermonkey and Violentmonkey which support the function that Greasemonkey does not). – Random Logic Sep 08 '17 at 18:26
  • 1
    You can check via exclusion e.g. `@grant GM_addValueChangeListener` and then `if (typeof GM_addValueChangeListener === 'undefined') ...` would mean it's not Tampermonkey. Next check for something that's supported in Violentmonkey but not in GM. – wOxxOm Sep 08 '17 at 19:02
  • 1
    And what is the specific function you're talking about? Maybe it would be smarter to simply check if it works, instead of checking which userscript manager you're in. – Tomáš Zato Sep 08 '17 at 19:46
  • 1
    @TomášZato I did try that, unfortunately no exceptions are thrown but Greasemonkey ceases execution of the script when it executes the function. Realistically changing this from a "how-to" style question to an overly specific debugging style question (i.e "this MCVE does not work in Greasemonkey") is not going to be useful for future readers, and the specific function is not relevant to this question. As this question represents a valid programming task that is clear and reasonably scoped, I feel that it should be allowed to stand as it is. – Random Logic Sep 08 '17 at 20:47
  • 1
    I just asked for clarification, I didn' want you to change the scope of the question – Tomáš Zato Sep 08 '17 at 20:54
  • @TomášZato Sorry, usually when someone asks for an MCVE/specific function/etc the question is then quickly closed as lacking an MCVE, so I assumed that was what was going to happen here upon reading your comment. – Random Logic Sep 08 '17 at 20:57
  • 1
    I understand, this happens to me also and is very frustrating here on SO. – Tomáš Zato Sep 08 '17 at 21:09

2 Answers2

2

In the same vein as the third item in your list, you could choose a function that is not supported by Greasemonkey, but is supported by the userscript managers that support your function.

From this comparison table we can see that the @author meta property is not supported by Greasemonkey, but it is supported by Tampermonkey and Violentmonkey. This means that if you set the @author meta property, you can check if that exists via GM_info.script.author.

// ==UserScript==
// @name         Greasemonkey Check
// @description  Checks if the script is loaded by Greasemonkey or not
// @author       @TinyGiant
// @grant        none
// ==/UserScript==

const isGM = 'undefined' === typeof GM_info.script.author;
console.log(`Is Greasemonkey? ${isGM}`);
1

Checking what manager is running is a poor approach, which will prove to be brittle and high maintenance. The smart thing to do is to check if this mysterious function exists, or works as needed.

This is the same type of problem as "browser sniffing" and the answer is the same: Use feature detection instead.
EG:

if (typeof dicyFunc == "function") {
    //-- Use the function
    dicyFunc ();
}
else {
    console.error ("This userscript engine does not support dicyFunc.");
}

Update for user comment: Sometimes you might also need a try... catch block. EG:

try {
    REALLY_dicyFunc ();
}
catch (zError) {
    console.error ("REALLY_dicyFunc fail on this engine: ", zError);
}

You need to give a concrete example (Make an MCVE) for more.


If you insist on engine detection, then see this answer to a near duplicate question. Essentially, you would use GM_info.scriptHandler property, possibly backed up by the GM_info.version property.

For best results, make a feature request for Greasemonkey to support the scriptHandler property. (Tampermonkey and ViolentMonkey already do.) There is a recently closed pull request for this for Greasemonkey, so maybe it will be in the next version?

Brock Adams
  • 90,639
  • 22
  • 233
  • 295
  • Thanks for your answer. `GM_info.scriptHandler` is a good idea. See [my response](https://stackoverflow.com/q/46121912#comment79211327_46121912) to [Tomáš Zato's](https://stackoverflow.com/users/607407) for more information on why checking if the function works is not a viable solution (Greasemonkey ceases to execute as soon as it sees the function), and why I feel that an MCVE is not required for this question to be answerable and on-topic. I am specifically looking for a method of detecting which userscript manager is running the script, so I would like to keep the question as such. – Random Logic Sep 08 '17 at 20:55
  • Note: I did not downvote this answer (it does present a reasonable solution). – Random Logic Sep 08 '17 at 20:56
  • 1
    I didn't even realize that `GM_info.scriptHandler` was a thing. @RandomLogic I would probably use that instead of relying on Greasemonkey not supporting `@author` as that may change in the future. –  Sep 08 '17 at 21:08
  • @RandomLogic, checking for the function is always a viable solution. See the updated answer. – Brock Adams Sep 08 '17 at 21:14
  • @Brock It reports as it is a function, the script still ceases to execute when executing the function. – Random Logic Sep 08 '17 at 21:15
  • Whelp, then you need that MCVE... (and *maybe* a try.. catch block.) – Brock Adams Sep 08 '17 at 21:16
  • This is not a debugging style question, I don't want to turn it into a debugging style question, and I don't want to spend any more time fighting with it. I only want to determine which userscript manager is running the script, and your suggestion of using `GM_info.scriptHandler` is the perfect answer to my question. I have accepted your answer for that reason, but I feel that your insistence on me not doing what I'm asking how to do when it is a perfectly reasonable task is detracting from your answer. – Random Logic Sep 08 '17 at 21:20
  • Re: your update to use the try catch block, I had already updated my question stating that that in fact does not work. Regardless it doesn't matter as none of that is relevant to the question that I asked. – Random Logic Sep 08 '17 at 21:21
  • Oh, sorry. Those edits crossed in the ether. And yes, GM can be that way, but haven't seen it in years. – Brock Adams Sep 08 '17 at 21:22
  • So you acknowledge that there may be situations where determining which userscript manager is running the script is the solution. Would you mind expanding that part of your answer a bit and making a bit less of a "You should never ever do this" kind of thing? It doesn't really matter either way, but I think that would be most useful for future readers who are facing similar issues. – Random Logic Sep 08 '17 at 21:25
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/153985/discussion-between-brock-adams-and-random-logic). – Brock Adams Sep 08 '17 at 21:25