Skip to content
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

fix(caa upload): compatibility with Greasemonkey #224

Merged
merged 16 commits into from
Nov 13, 2021
Merged

Conversation

ROpdebee
Copy link
Owner

@ROpdebee ROpdebee commented Nov 7, 2021

Closes #123.

  • Use correct run-at value
  • Migrate to GM.* API by default and polyfill them when the userscript engine doesn't support them.
    • We request grants for both the GM.* and GM_* version, one of the two (or both) will be granted. If the GM_ version is granted, we polyfill the GM.* version based on that. This is done through the gm4-polyfill requirement.
    • gm4-polyfill is injected into the script itself rather than @required so that we can transpile it for compatibility with older browsers. It's currently included as a submodule, so if you want to build it locally, you may have to init and update the submodule first. The build process is a bit hack-y since gm4-polyfill requires this, which isn't available in a rolled-up IIFE, so we patch it to have one. Eventually, I'd like to separate that out of the IIFE (perhaps as a separate @require).
    • Added a compatibility layer to dispatch to the correct API, depending on which one exists.
    • The switch to GM.* APIs also means we have to make some changes for IMU. Most importantly, we now have to deal with IMU's exports possibly being defined asynchronously, because GM.getValue and GM.setValue are asynchronous.
  • The main changes are in handling situations where we might be running in the content context instead of the page context. Under Greasemonkey, userscripts run in the content context and therefore have no access to window globals defined by the page itself. This includes window.MB and jQuery. Although we can access those globals through unsafeWindow, we can't provide our content globals to the page without cloning it first.
    • fetch doesn't support relative URLs, so we're using absolute ones now.
    • We can't easily use MB.CoverArt.validate_file in content scripts, since we provide content context functions to be called by page content, which leads to permission errors. Therefore, we duplicate MB's implementation.
    • Similarly, triggering the jQuery event to enqueue images leads to permission errors, so we clone the event into the page content and trigger the handler manually to prevent jQuery from calling into content context functions.
    • NB: We might be able to still have the page context call our content context functions if we clone those too.
    • NB: Because content scripts cannot access page script globals, any polyfills injected by MB won't be visible to the userscript in Greasemonkey, so old Firefox + Greasemonkey likely still won't work (although it seemed to work properly with FF82).

Tested with:

  • Firefox 95.0a1 Violentmonkey, Tampermonkey, Greasemonkey
  • Chromium 97.0.4672.0 Violentmonkey, Tampermonkey
  • Firefox 82 Greasemonkey (I can't test on any older versions because they don't want to run on my OS...)
  • Waterfox Classic 2021.10 w/ Greasemonkey 3.17

`document-load` doesn't exist. I meant `document-end`...
Greasemonkey scripts run in the content context, not the page context,
so the `fetch` calls don't properly resolve relative URLs. Easiest
way to resolve this is by providing absolute URLs.
…hanges

`GM_xmlhttpRequest` -> `GM.xmlHttpRequest`
`GM_getResourceURL` -> `GM.getResourceUrl`
These changes ensure the GM API is polyfilled only after the core-js
polyfills are added and that they are transpiled by babel.
We cannot access the MB object defined in `window` since we're not
running in a page context in Greasemonkey. Although we could
circumvent this using `unsafeWindow`, this leads to issues with
permission errors because we're crossing context boundaries with
callback functions.
Greasemonkey scripts that use granted APIs run in the content context,
not the page context, and therefore have no access to the jQuery object
defined by MB. We "escape" this through `unsafeWindow` and `cloneInto`
to trigger the event. We also trigger the handler manually rather than
triggering the event via jQuery, since jQuery tries to call some
functions defined on the event but the page scripts don't have that
permission.
ImageMaxUrl only exports after all `GM.setValue` and `GM.getValue`
calls have been done. With `GM.*` APIs, these are asynchronous, but
there's no way for us to await them. Therefore, we retry on a timeout
until IMU is exported.
@ROpdebee ROpdebee added bug Something isn't working mb_enhanced_cover_art_uploads labels Nov 7, 2021
@ROpdebee ROpdebee requested a review from kellnerd November 7, 2021 22:54
@ROpdebee
Copy link
Owner Author

ROpdebee commented Nov 7, 2021

/deploy-preview

@codecov
Copy link

codecov bot commented Nov 7, 2021

Codecov Report

Merging #224 (fe4a7e0) into main (8eb249c) will not change coverage.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff            @@
##              main      #224   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           39        39           
  Lines          857       860    +3     
  Branches       158       158           
=========================================
+ Hits           857       860    +3     
Impacted Files Coverage Δ
src/lib/MB/EditNote.ts 100.00% <100.00%> (ø)
src/lib/MB/URLs.ts 100.00% <100.00%> (ø)
src/lib/util/blob.ts 100.00% <100.00%> (ø)
src/lib/util/xhr.ts 100.00% <100.00%> (ø)
src/mb_enhanced_cover_art_uploads/fetch.ts 100.00% <100.00%> (ø)
src/mb_enhanced_cover_art_uploads/form.ts 100.00% <100.00%> (ø)
src/mb_enhanced_cover_art_uploads/maximise.ts 100.00% <100.00%> (ø)
.../mb_enhanced_cover_art_uploads/providers/amazon.ts 100.00% <100.00%> (ø)
...rc/mb_enhanced_cover_art_uploads/providers/base.ts 100.00% <100.00%> (ø)
...c/mb_enhanced_cover_art_uploads/providers/qobuz.ts 100.00% <100.00%> (ø)
... and 1 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 8eb249c...fe4a7e0. Read the comment docs.

ROpdebee added a commit that referenced this pull request Nov 7, 2021
@ROpdebee
Copy link
Owner Author

ROpdebee commented Nov 7, 2021

Deploying a preview is currently broken because it doesn't clone the submodules (will be fixed when PR is merged though), so here's one I made manually: https://github.com/ROpdebee/mb-userscripts/raw/dist-preview-224/mb_enhanced_cover_art_uploads.user.js

@Freso could you give the preview above a try and see if it works for you?

Copy link
Collaborator

@kellnerd kellnerd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good, I also tested with GM, TM and VM in Firefox 94 and everything I tried is working as it should.

@Freso
Copy link

Freso commented Nov 8, 2021

@Freso could you give the preview above a try and see if it works for you?

Seems like it’s working for me now! :)
image

@ROpdebee
Copy link
Owner Author

ROpdebee commented Nov 8, 2021

It still doesn't work in GM <4, see https://chatlogs.metabrainz.org/libera/musicbrainz/msg/4904321/. Tested with Waterfox Classic 2021.10, running GM3.17.

Root cause is another piece of context switching between page and content scripts, more specifically in the derivation of the mime type. It seems to be related to greasemonkey/greasemonkey#2034. The script freezes once it gets to this line:

if ((uint32view[0] & 0x00FFFFFF) === 0x00FFD8FF) {

For @CatQuest, it throws a (surprisingly helpful) error about TypedArrays and Xrays, for me personally, it just freezes without any error and doesn't get past that line.

In short: FileReader is W3C, Uint32Array is ES. Therefore, Uint32Array is defined in the userscript sandbox, whereas FileReader comes from the page itself and is Xrayed (proxied, sort of). Accessing the Uint32Array contents leads to xraying to some underlying ArrayBuffer which exists in the page context, which Firefox (Waterfox) refuses to do because of performance issues. Reference: https://bugzilla.mozilla.org/show_bug.cgi?id=1122687#c8

Solution: use unsafeWindow.Uint32Array instead of bare Uint32Array. This prevents the freeze for me at least. Will apply it later. Should also be applied to hexEncode since that also uses FileReader with Uint8Array

For some reason, under GM4.1 in the same Waterfox version, it works just fine. I guess it uses a different implementation of the sandbox.

We're using the compat layer now.
They exist to ensure compatibility between different userscript
engines and browsers, so they belong there.
Under GM3, the script wasn't properly switching contexts when
processing `Uint*Array` instances created from `ArrayBuffer`s.
See #224 (comment)
@ROpdebee
Copy link
Owner Author

/deploy-preview should work again now because we're not using git submodules anymore

@github-actions
Copy link

This PR changes 1 built userscript(s):

See all changes

github-actions bot added a commit that referenced this pull request Nov 11, 2021
fix(caa upload): compatibility with Greasemonkey (#224)
Copy link
Collaborator

@kellnerd kellnerd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good without the unnecessary polyfills and hacks to make those work, thanks.

@ROpdebee ROpdebee merged commit 1a35ef5 into main Nov 13, 2021
ROpdebee added a commit that referenced this pull request Nov 13, 2021
Under GM3, the script wasn't properly switching contexts when
processing `Uint*Array` instances created from `ArrayBuffer`s.
See #224 (comment)
@ROpdebee ROpdebee deleted the ecau-greasemonkey branch November 13, 2021 18:09
@github-actions
Copy link

🚀 Released 1 new userscript version(s):

  • mb_enhanced_cover_art_uploads 2021.11.13 in 28eb59b

github-actions bot added a commit that referenced this pull request Nov 13, 2021
fix(caa upload): compatibility with Greasemonkey (#224)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support Greasemonkey
3 participants