New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[FireMonkey] Userscript Compatibility #429
Comments
https://github.com/syhyz1990/baiduyun This doesn't work with FireMonkey. I guess you don't have a baiduyun account so if there is any info needed I'm more than happy to provide it. I guess |
Has the developer commented about compatibility with FM? |
It works with VM but not with GM. In the README they say that VM or TM is required. |
VM doesn't support |
I'll report this issue there and come back. Thanks! |
https://greasyfork.org/en/scripts/432387-general-url-cleaner-revived doesn't work as intended. It might be a problem of how Firemonkey doesn't inject on all frames or whatever. Developer of this script is willing to make it Firemonkey compatible. ReCAPTCHA Solver, Hcaptcha Solver and other like them also victim of this. |
Replied to the topic
At a glance, I dont see any issues. It has to be checked by the developers.
At a glance, I dont see any issues. Too large to debug. // ==/UserScript==
/*jshint esversion: 6 */
window.nova_plugins = []; Results in:
Declares but never uses
At a glance, I dont see any issues. Does it work with Greasemonkey?
Userscript should have the UI for the users tos et values. TM has the UI to view/update storage values, but that should not be a replaemnet for userscript's own UI. Anyway, since the userscript is very small, users can manually set values here, but the code doesnt updates its value, so it has to be uninstalled and reinstalled. GM_setValue('Default_Volume', 20); //Save the Default YT Volume as 20% TBH, the code uses static value which makes // ==UserScript==
// @name Auto Set Youtube Volume
// @namespace YTVol
// @version 0.2
// @description Choose the default volume for YouTube videos!
// @author hacker09
// @match https://www.youtube.com/embed/*
// @match https://www.youtube.com/watch?v=*
// @icon https://www.youtube.com/s/desktop/03f86491/img/favicon.ico
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
const defaultVolume = 20;
const data = {
data: {
volume: defaultVolume,
muted: false,
creation: Date.now()
}
};
window.sessionStorage.setItem('yt-player-volume', JSON.stringify(data)); //Set the Default YT Volume
})(); User can manually change the 📌 AFA feature to edit userscript storage, let me think about it 🤔
As per that topic, there is way to have custom setting by using |
Sorry I might not be clear first time. For general URL cleaner revived, if you go any site where they use disqus.com for comment, FM doesn't inject that script where TM and VM do. In case of ReCAPTCHA Solver, when you trigger captcha in sites TM and VM run that script but not FM. This happens with similar scripts across different websites. So, reporting all of them to make Firemonkey compatible might not be a viable solution and all developers might not be friendly like you. Instead, if you inspect the problem in your spare time to make Firemonkey support most script might be better. https://greasyfork.org/en/scripts/428651-tabview-youtube doesn't work at all. |
I see ... in that case, it seems to be the issue of In majority of cases, the top frame is enough and avoids extra overheads of injecting into sub-frames unnecessarily. However, captcha, disqus, etc are usually included as iframes. Therefore, userscript dealing with them should be set to inject into all frames. Set |
Already tried that with URL cleaner from another issue you solved but doesn't work here. Solved ReCAPTCHA Solver though. |
URL cleaner issue doesn't relate to |
Ok then, hope he will solve the issue. Looking forward to seeing future feature implementation and better scripts compatibility in firemonkey. Thank you. |
v2.45 |
https://greasyfork.org/en/scripts/7543-google-search-extra-buttons Doesn't load unless explicitly asked to via the run command, probably something to do with run-on but beyond my ken I'm sorry |
The patterns have issues e.g. I found the reason for not injecting which is due to the processing order when patterns like For now, if you only use
|
https://greasyfork.org/en/scripts/436115-return-youtube-dislike The userscript is not working in FireMonkey v2.44. |
Unfortunately it is due to the CORS restriction Bug 1715249 in
|
Just for reference, ViolentMonkey and TamperMonkey are working with the script at https://greasyfork.org/en/scripts/436115-return-youtube-dislike |
GM|TM|VM inject into Note: Script declares Here is the same script, with added compatibility with FireMonkey as well (line 219-234 no other changes): // ==UserScript==
// @name Return YouTube Dislike
// @namespace https://www.returnyoutubedislike.com/
// @homepage https://www.returnyoutubedislike.com/
// @version 0.9.0
// @encoding utf-8
// @description Return of the YouTube Dislike, Based off https://www.returnyoutubedislike.com/
// @icon https://github.com/Anarios/return-youtube-dislike/raw/main/Icons/Return%20Youtube%20Dislike%20-%20Transparent.png
// @author Anarios & JRWR
// @match *://*.youtube.com/*
// @exclude *://music.youtube.com/*
// @exclude *://*.music.youtube.com/*
// @compatible chrome
// @compatible firefox
// @compatible opera
// @compatible safari
// @compatible edge
// @grant GM.xmlHttpRequest
// @connect youtube.com
// @grant GM_addStyle
// @run-at document-end
// ==/UserScript==
const LIKED_STATE = "LIKED_STATE";
const DISLIKED_STATE = "DISLIKED_STATE";
const NEUTRAL_STATE = "NEUTRAL_STATE";
let previousState = 3; //1=LIKED, 2=DISLIKED, 3=NEUTRAL
let likesvalue = 0;
let dislikesvalue = 0;
let isMobile = location.hostname == "m.youtube.com";
let mobileDislikes = 0;
function cLog(text, subtext = "") {
subtext = subtext.trim() === "" ? "" : `(${subtext})`;
console.log(`[Return YouTube Dislikes] ${text} ${subtext}`);
}
function getButtons() {
if (isMobile) {
return document.querySelector(".slim-video-action-bar-actions");
}
if (document.getElementById("menu-container")?.offsetParent === null) {
return document.querySelector("ytd-menu-renderer.ytd-watch-metadata > div");
} else {
return document
.getElementById("menu-container")
?.querySelector("#top-level-buttons-computed");
}
}
function getLikeButton() {
return getButtons().children[0];
}
function getDislikeButton() {
return getButtons().children[1];
}
function isVideoLiked() {
if (isMobile) {
return (
getLikeButton().querySelector("button").getAttribute("aria-label") ==
"true"
);
}
return getLikeButton().classList.contains("style-default-active");
}
function isVideoDisliked() {
if (isMobile) {
return (
getDislikeButton().querySelector("button").getAttribute("aria-label") ==
"true"
);
}
return getDislikeButton().classList.contains("style-default-active");
}
function isVideoNotLiked() {
if (isMobile) {
return !isVideoLiked();
}
return getLikeButton().classList.contains("style-text");
}
function isVideoNotDisliked() {
if (isMobile) {
return !isVideoDisliked();
}
return getDislikeButton().classList.contains("style-text");
}
function checkForUserAvatarButton() {
if (isMobile) {
return;
}
if (document.querySelector('#avatar-btn')) {
return true
} else {
return false
}
}
function getState() {
if (isVideoLiked()) {
return LIKED_STATE;
}
if (isVideoDisliked()) {
return DISLIKED_STATE;
}
return NEUTRAL_STATE;
}
function setLikes(likesCount) {
if (isMobile) {
getButtons().children[0].querySelector(".button-renderer-text").innerText =
likesCount;
return;
}
getButtons().children[0].querySelector("#text").innerText = likesCount;
}
function setDislikes(dislikesCount) {
if (isMobile) {
mobileDislikes = dislikesCount;
return;
}
getButtons().children[1].querySelector("#text").innerText = dislikesCount;
}
(typeof GM_addStyle != "undefined"
? GM_addStyle
: (styles) => {
let styleNode = document.createElement("style");
styleNode.type = "text/css";
styleNode.innerText = styles;
document.head.appendChild(styleNode);
})(`
#return-youtube-dislike-bar-container {
background: var(--yt-spec-icon-disabled);
border-radius: 2px;
}
#return-youtube-dislike-bar {
background: var(--yt-spec-text-primary);
border-radius: 2px;
transition: all 0.15s ease-in-out;
}
.ryd-tooltip {
position: relative;
display: block;
height: 2px;
top: 9px;
}
.ryd-tooltip-bar-container {
width: 100%;
height: 2px;
position: absolute;
padding-top: 6px;
padding-bottom: 28px;
top: -6px;
}
`);
function createRateBar(likes, dislikes) {
if (isMobile) {
return;
}
let rateBar = document.getElementById("return-youtube-dislike-bar-container");
const widthPx =
getButtons().children[0].clientWidth +
getButtons().children[1].clientWidth +
8;
const widthPercent =
likes + dislikes > 0 ? (likes / (likes + dislikes)) * 100 : 50;
if (!rateBar && !isMobile) {
document.getElementById("menu-container").insertAdjacentHTML(
"beforeend",
`
<div class="ryd-tooltip" style="width: ${widthPx}px">
<div class="ryd-tooltip-bar-container">
<div
id="return-youtube-dislike-bar-container"
style="width: 100%; height: 2px;"
>
<div
id="return-youtube-dislike-bar"
style="width: ${widthPercent}%; height: 100%"
></div>
</div>
</div>
<tp-yt-paper-tooltip position="top" id="ryd-dislike-tooltip" class="style-scope ytd-sentiment-bar-renderer" role="tooltip" tabindex="-1">
<!--css-build:shady-->${likes.toLocaleString()} / ${dislikes.toLocaleString()}
</tp-yt-paper-tooltip>
</div>
`
);
} else {
document.getElementById(
"return-youtube-dislike-bar-container"
).style.width = widthPx + "px";
document.getElementById("return-youtube-dislike-bar").style.width =
widthPercent + "%";
document.querySelector(
"#ryd-dislike-tooltip > #tooltip"
).innerHTML = `${likes.toLocaleString()} / ${dislikes.toLocaleString()}`;
}
}
function setState() {
cLog("Fetching votes...");
let statsSet = false;
if (GM_info.scriptHandler === 'FireMonkey') {
GM.fetch(`https://returnyoutubedislikeapi.com/votes?videoId=${getVideoId()}`, {responseType: 'json'})
.then((response) => response.json)
.then((json) => {
if (json && !("traceId" in json) && !statsSet) {
const { dislikes, likes } = json;
cLog(`Received count: ${dislikes}`);
likesvalue = likes;
dislikesvalue = dislikes;
setDislikes(numberFormat(dislikes));
createRateBar(likes, dislikes);
}
});
setState = function(){};
return;
}
fetch(
`https://returnyoutubedislikeapi.com/votes?videoId=${getVideoId()}`
).then((response) => {
response.json().then((json) => {
if (json && !("traceId" in response) && !statsSet) {
const { dislikes, likes } = json;
cLog(`Received count: ${dislikes}`);
likesvalue = likes;
dislikesvalue = dislikes;
setDislikes(numberFormat(dislikes));
createRateBar(likes, dislikes);
}
});
});
setState = function(){};
}
function likeClicked() {
if (checkForUserAvatarButton() == true) {
if (previousState == 1) {
likesvalue--;
createRateBar(likesvalue, dislikesvalue);
setDislikes(numberFormat(dislikesvalue));
previousState = 3
} else if (previousState == 2) {
likesvalue++;
dislikesvalue--;
setDislikes(numberFormat(dislikesvalue))
createRateBar(likesvalue, dislikesvalue);
previousState = 1
} else if (previousState == 3) {
likesvalue++;
createRateBar(likesvalue, dislikesvalue)
previousState = 1
}
}
}
function dislikeClicked() {
if (checkForUserAvatarButton() == true) {
if (previousState == 3) {
dislikesvalue++;
setDislikes(numberFormat(dislikesvalue));
createRateBar(likesvalue, dislikesvalue);
previousState = 2
} else if (previousState == 2) {
dislikesvalue--;
setDislikes(numberFormat(dislikesvalue));
createRateBar(likesvalue, dislikesvalue);
previousState = 3
} else if (previousState == 1) {
likesvalue--;
dislikesvalue++;
setDislikes(numberFormat(dislikesvalue));
createRateBar(likesvalue, dislikesvalue);
previousState = 2
}
}
}
function setInitialState() {
setState();
}
function getVideoId() {
const urlObject = new URL(window.location.href);
const pathname = urlObject.pathname;
if (pathname.startsWith("/clip")) {
return document.querySelector("meta[itemprop='videoId']").content;
} else {
return urlObject.searchParams.get("v");
}
}
function isVideoLoaded() {
if (isMobile) {
return document.getElementById("player").getAttribute("loading") == "false";
}
const videoId = getVideoId();
return (
document.querySelector(`ytd-watch-flexy[video-id='${videoId}']`) !== null
);
}
function roundDown(num) {
if (num < 1000) return num;
const int = Math.floor(Math.log10(num) - 2);
const decimal = int + (int % 3 ? 1 : 0);
const value = Math.floor(num / 10 ** decimal);
return value * 10 ** decimal;
}
function numberFormat(numberState) {
let userLocales;
try {
userLocales = new URL(
Array.from(document.querySelectorAll("head > link[rel='search']"))
?.find((n) => n?.getAttribute("href")?.includes("?locale="))
?.getAttribute("href")
)?.searchParams?.get("locale");
} catch {}
const formatter = Intl.NumberFormat(
document.documentElement.lang || userLocales || navigator.language,
{
notation: "compact",
}
);
return formatter.format(roundDown(numberState));
}
function setEventListeners(evt) {
let jsInitChecktimer;
function checkForJS_Finish(check) {
console.log();
if (getButtons()?.offsetParent && isVideoLoaded()) {
clearInterval(jsInitChecktimer);
const buttons = getButtons();
if (!window.returnDislikeButtonlistenersSet) {
cLog("Registering button listeners...");
buttons.children[0].addEventListener("click", likeClicked);
buttons.children[1].addEventListener("click", dislikeClicked);
window.returnDislikeButtonlistenersSet = true;
}
setInitialState();
}
}
cLog("Setting up...");
jsInitChecktimer = setInterval(checkForJS_Finish, 111);
}
(function () {
"use strict";
window.addEventListener("yt-navigate-finish", setEventListeners, true);
setEventListeners();
})();
if (isMobile) {
let originalPush = history.pushState;
history.pushState = function (...args) {
window.returnDislikeButtonlistenersSet = false;
setEventListeners(args[2]);
return originalPush.apply(history, args);
};
setInterval(() => {
getDislikeButton().querySelector(".button-renderer-text").innerText =
mobileDislikes;
}, 1000);
} |
I write some scripts that use GM_openInTab and window.focus and window.close: |
// ==UserScript==
// @name window.close test
// @match *://*.example.com/*
// @match *://github.com/*
// ==/UserScript==
if (location.hostname.endsWith('github.com')) {
window.setTimeout(() => GM.openInTab('https://example.com/'), 2000);
}
else {
window.setTimeout(() => window.close(), 2000);
} |
Yes, need later. |
https://greasyfork.org/en/scripts/428651-tabview-youtube The userscript is not working in FireMonkey v2.45. |
At first glance, I don't see any issues. The script to too large and has large minified If the developer points out the issue, I will see what can be done. PS. I posted to Return YouTube Dislike with the code but there is no response so far. |
The script at https://greasyfork.org/en/scripts/436115-return-youtube-dislike with your changes is working in FireMonkey v2.45. Thank you. Just for reference, ViolentMonkey and TamperMonkey are working with the script at https://greasyfork.org/en/scripts/428651-tabview-youtube |
https://greasyfork.org/en/scripts/419825-opera-browser-rocker-mouse-gestures-search-highlight script does not work as expected. Units and currency converters of this script not working with FM. You can use this page to check currency conversion. |
It could the be due to Bug 1715249 as the script uses I am waiting for the bug to be fixed. |
Maybe. But no CORS errors are displayed in the console and enabling CORS with extension doesn't help. Also i do not understand a thing about those (or any of those hard code you write😯). So I am leaving all the hard work upon you🤣. Thanks again. |
Yup ! But there seems to be more profound issues with the support. Stuff like the jquery I'm unsure how to debug this, tbh. But I thought it might be helpful to give you more example of bigger scripts that are incompatible. I believe the |
It could be the
In my FM v2.68, all scripts are injected. The console log also shows that the script is running but I don't know what it is supposed to. |
Odd. I doesn't load at all on my end, either with all extensions disabled or in private browsing (with only FM active). The script just doesn't load and when I try to run it manually (using FM's popup menu) I get a
If you want to contact me privately / on IM, I'm on telegram @CyberFoxar ! I can also do IRC, but you'll need to give me a place x) |
My previous test was with Firefox Nightly 113 & FireMonkey 2.68. It might be something to do with the changes in the v2.68. 🤔 |
Error with this script (v 0.4.0):
Tampermonkey 4.18.1 works. Firemonkey version is 2.67. Firefox 102.3.0esr |
The script checks for line 11,432 function request2(options2) {
return isWebOptionsPage() ? ask({
method: "request",
data: options2
}) : isMonkey() || isDeno() ? (options2.fetchPolyfill = globalThis.GM_fetch, request(options2)) : sendMessage({
method: "fetch",
data: options2
});
} Adding this to top of the script, eliminates the error. Line 67 (() => { globalThis.GM_fetch = null; I haven't checked it thoroughly though. |
It works, thanks. If you're interested, this is what script author said about the issue:
It seems that teddit.net doesn't work tho, Failed to sync latest adaptive rules |
https://greasyfork.org/en/scripts/437291-open-source-alternative-redirector
But Tampermonkey works for me, weirdly. |
I am guessing that he is not aware that FireMonkey injects into the dedicated & isolated AFA teddit error, TBH, the script is too large for me to test & debug. The script developer can look into it.
|
@eberhardweber I came across PotcFdk/SteamDiscoveryQueueAutoSkipper#11 and had another look at the script. The main problem is
As per FireMonkey Help: Quick Fixes, "Use Wrap code in IIFE". That would eliminate the error. If the script still doesn't run as expected, "Try setting |
This script doesn't work but even wierder using it together with Firemonkey breaks network connection of many websites, causing them to break/not fully loaded, do you have any idea ? Doesn't happen with Violentmonkey, Tampermonkey... I used a new profile to test, so it can't be my profile issues. |
@GunGunGun re: M3U8 Video Detector and Downloader At a glance, these are some of the issues which you can share with the developer if you want. 1Since FireMonkey 2.42, if both However, script starts using
2There might be an issue with I don't know how it will end up // in FireMoneky
fetch -> window.fetch
unsafeWindow -> window.wrappedJSObject;
// result in M3U8 Video Detector and Downloader
unsafeWindow.fetch -> window.wrappedJSObject.fetch 3Although not a problem, line 61 has a |
@erosman Thanks, I tried to fix the script and it looks like I've found the issue, it's because of this code to override xmlHttprequest.prototype.open:
Removing this part fixed the network issue, but it works on all other userscript Managers like VM, TM... But I don't really want to remove above part because it affects ability to grab m3u8 from xmlHttprequest, result in script grabbing less video urls.
There must be something differences between FM and VM/TM ? Here's my modified code, I replaced all GM_set/get with GM.:
|
Because the above post is too long, I'll use this post to update what I've found: window.XMLHttpRequest.prototype.open has become:
Normally it should be:
With Violentmonkey it became:
This should be the root of the issue. |
@GunGunGun Are you the developer of M3U8 Video Detector and Downloader?
Of course. In current MV2 (MV3 will be different for all userScript/userStyle mangers), FM injection context and GM|TM|VM injection context are different. Injection Context
Window
unsafeWindow
Testing in a userscript console.log(XMLHttpRequest.prototype.open);
// function open()
console.log(unsafeWindow.XMLHttpRequest.prototype.open);
// function open() Regarding the following test in Web Developer Tools window.XMLHttpRequest.prototype.open
// Restricted { } It is due to the rewriting of |
@erosman I'm not the dev of this script, honestly this script is a mess, I deleted so many things from this script to make it close to work So far what I've found
Combining my above modified code with
And do you think this change needs to be restored ? Because |
@GunGunGun Good job with the script 👍
The behaviour was set in FM 2.42. To start with, there is no synchronous extension storage in modern browsers. The storage API is asynchronous (has been since Firefox 57). Userscript developers have been reluctant to update their userscripts and therefore, userscript managers (TM|VM) kept the
Due to requests, FireMonkey also implemented a workaround to imitate the synchronous
Updating old userscripts for the modern // GM3 sync code
(() => {
const value = GM_getValue('key');
// --- some code
})();
// GM4 async code
(async() => {
const value = await GM.getValue('key');
// --- some code
})(); There are some who complain about the delay in See also: |
@erosman Thank you very much for the detailed information, so it looks like getting asynchronous is a huge upgrade and if it's possible use async GM.getValue in most case to improve performance. |
Please open individual topics for the userscript script compatibility issue. |
Hi, Super-preloader script works on 2.68 version.
|
@Orriky It would be easier to open a new topic.
Did you enable iframe in User Metadata?
What is that rule for/from? |
@erosman
Currently there is no option to modify the non-isolated environment (some userscripts are doing the direct access to the DOM properties, modifying web APIs, prototype of the native objects like Event) If the userscript is simple without any setValue getValue GM menu, it can be injected into the page context and problem solves. Therefore I think giving option to user that FireMonkey can also use GM functions in page context but bear the risks by themselves would make users happy. |
@cyfung1031
Please note that while most userscripts are compatible with TM|VM, there are differences between the two and some userscripts are not compatible with both. (Read FireMonkey Help for more info) |
FireMonkey 2.44 should be compatible with 98% of userscripts.
Please read Help for more information.
Please post any userscript issues here for further investigation.
The text was updated successfully, but these errors were encountered: