Skip to content

PICARD-3040: Register a custom protocol handler for browser integration - #2596

Closed
phw wants to merge 1 commit into
metabrainz:masterfrom
phw:custom-protocol
Closed

PICARD-3040: Register a custom protocol handler for browser integration#2596
phw wants to merge 1 commit into
metabrainz:masterfrom
phw:custom-protocol

Conversation

@phw

@phw phw commented Mar 5, 2025

Copy link
Copy Markdown
Member

Summary

  • This is a…
    • Bug fix
    • Feature addition
    • Refactoring
    • Minor / simple change (like a typo)
    • Other
  • Describe this change in 1-2 sentences:

Problem

This PR implements a custom URL handler in an attempt to provide a solution for PICARD-3040. This PR focuses on adding the ability to handle the protocol to Picard and register the handler on various systems.

The handler allows opening URIs like org.musicbrainz.picard:openalbum?id=3fd4b04a-28fa-45b7-89d7-bcb883be287c.

Solution

  • Implement the protocol handler based on the existing browser integration
  • Enable support for handling the custom URLs via command line (Linux and Windows) and via a handler registered with QDesktopServices.setUrlHandler (macOS).
  • Register the handler on macOS, Linux and Windows. This depends both on the system and the installation method.

Action

  • Test on different systems
  • This PR does not in any way actually use the handler. For OAuth this would require setting the callback URL accordingly (which currently requires us to register a separate "App" on MusicBrainz.org with the custom handler). For tagger buttons this would need some changes on MusicBrainz.org itself.

@phw

phw commented Mar 5, 2025

Copy link
Copy Markdown
Member Author

To test this on Linux, run python setup.py build_desktop_file and copy the generated org.musicbrainz.Picard.desktop file to ~/.local/share/applications.

Edit the Exec line in the file to open Picard from the source. I have set it to:

Exec=/home/phw/devel/musicbrainz/picard/tagger.py -c /home/phw/devel/musicbrainz/picard/picard3.ini --no-plugins %U

Afterwards run:

update-desktop-database ~/.local/share/applications

It should now be possible to run xdg-open with a custom protocol URI:

xdg-open "org.musicbrainz.picard:openalbum?id=3fd4b04a-28fa-45b7-89d7-bcb883be287c"

It also works from within browsers, but at least with Firefox and Chrome it is a bit special. Pasting the custom URI into the address bar just triggers web searches. But if it is part of a link (e.g. <a href="org.musicbrainz.picard:openalbum?id=3fd4b04a-28fa-45b7-89d7-bcb883be287c">Tagger</a>, it is being used and the browser will ask whether the handler shall be called.

Comment thread installer/picard-setup.nsi.in
Comment thread picard.spec Outdated
Comment thread appxmanifest.xml.in
Comment thread picard/__init__.py Outdated
@phw
phw force-pushed the custom-protocol branch 2 times, most recently from b1dcda6 to 9aad628 Compare March 6, 2025 07:58
@phw

phw commented Mar 6, 2025

Copy link
Copy Markdown
Member Author

The URL handler on macOS is not called. The app is started and brought to the foreground, but the handler never receives the URL. There is a bug report https://bugreports.qt.io/browse/QTBUG-131741 for Qt 6.
8.0 and 6.8.1 which looks related. But it is marked as fixed in 6.8.2, which we already use for the macOS builds.

@phw
phw force-pushed the custom-protocol branch 6 times, most recently from 7b64040 to 281b1c7 Compare March 6, 2025 15:12
Comment thread picard/browser/browser.py Outdated
@phw
phw force-pushed the custom-protocol branch from 281b1c7 to 92a148e Compare March 7, 2025 17:09
@phw

phw commented Mar 7, 2025

Copy link
Copy Markdown
Member Author

I tested this on Windows and macOS.

On Windows using the installer everything works as expected. Windows, like Linux, passes the custom URL via command line (hooray for single instance mode), and it gets processed as expected. The installer registers the protocol handler via registry and this also gets cleaned up again on uninstalling.

I still need to test this with the appx package (as used for the store). Theoretically this works the same, but protocol registration happens via the appxmanifest metadata. Testing this needs code signing to work (only signed appx packages can be installed), and I need to do the proper setup for this on my machine.

Unfortunately the macOS test results are a bit mixed. Registering the protocol handler via the app package metadata (info.plist) works as expected. The handler works (tried with Safari and command line open command) and the app gets started or raised.

But event processing is not working as expected in Qt. Like with file open macOS handles the protocol by sending an event to the app. The Qt documentation for QDesktopServices suggest that it should work when registering the handler via QDesktopServices.setUrlHandler. But the handler was never invoked.

I first assumed our custom event handling in https://github.com/metabrainz/picard/blob/master/picard/tagger.py#L792-L804 is interfering, so I made sure no event is processed there and super() gets called. But made no difference.

Then I figured out that with Qt 6.7 the event with the custom protocol URL ends up as a FileOpen event. So I patched our even handling to handle URLs with our scheme explicitly in https://github.com/metabrainz/picard/pull/2596/files#diff-754164b29034aa27e27d501630b16fe491c78108500b10caeab6b272bc240fbdR814 and call the handler directly. This feels like a workaround, though.

Unfortunately with Qt 6.8.2 the event neither shows up as a FileOpen event nor does it call the registered handler.

So far I think this is a Qt bug. As mentioned above there is the suspicious bug https://bugreports.qt.io/browse/QTBUG-131741 , but it is marked as resolved for 6.8.2. I'll see that I can create a small reproducer and report this to Qt.

@phw
phw force-pushed the custom-protocol branch from 6993ce8 to 169a4e0 Compare August 26, 2026 06:17
@phw

phw commented Aug 31, 2026

Copy link
Copy Markdown
Member Author

I'm going to close this for now, but keep the branch. We might want to re-investigate this later, also maybe for oauth callbacks.

But generally I fear that this is rather difficult to deploy cross-platform, and we need the local loopback fallback regardless. Even on platforms where this works well it is dependent on deployment method. E.g. on Linux it requires a .desktop file, and on Windows it requires registry changes (which makes this difficult for the portable build). Also the technical issues on macOS.

@phw phw closed this Aug 31, 2026
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.

2 participants