Conversation
Renders .musicxml and .mxl with opensheetmusicdisplay, so sheet music opens where every other file does. The renderer is two megabytes, so it is imported inside the component rather than at the top of the module: the handler's own chunk is 3 kB and the renderer is fetched the first time somebody opens a score, never for anyone who only opens photos. Two things the format needs that the other handlers do not. A .mxl is a zip holding the score, so the file goes to the renderer as the bytes it arrived as rather than as text. And the viewer keeps a handler hidden until it reports having loaded, which leaves nothing to measure and a score drawn zero pixels wide, so this one reports first and draws once the frame it was given is really there. Only the two score types are claimed. The earlier attempt at this also registered application/octet-stream, because the extensions had no mapping then and a score arrived as an unknown binary; they map since server 32, and claiming that type would have handed this handler every unrecognised file on the server. Co-authored-by: bneumann <bneumann@users.noreply.github.com> Assisted-by: ClaudeCode:claude-opus-5 Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #52 +/- ##
==========================================
+ Coverage 88.11% 88.62% +0.50%
==========================================
Files 37 39 +2
Lines 2625 2742 +117
Branches 558 561 +3
==========================================
+ Hits 2313 2430 +117
Misses 305 305
Partials 7 7 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
bneumann
left a comment
There was a problem hiding this comment.
Oh man this is brills. Thanks for picking up what I abandoned. To be honest I totally forgot about my work here, so it is also really nice to mention me.
For the code: It looks good, there are even tests which are - in my opinion - only plausibility tests because you need to see some bigger scores for yourself to make sure they render correctly. But then again that is more an OSMD problem.
The loading and rendering part looks good, you are using watch for the bigger scores and preventing the 0 height and 0 width problems with that.
From my experience with OSMD it looks ready to merge
Sheet music opens in the viewer, rendered with opensheetmusicdisplay. Picks up nextcloud/viewer#2752 by @bneumann, which has been open since March 2025 and closes nextcloud/viewer#424. Written fresh for this package rather than cherry-picked, but the idea and the choice of renderer are theirs and the commit carries their
Co-authored-by.The blocker that PR asked about is gone
They registered
application/octet-streamalongside the two score types and sniffed the extension inside the component, and said so in the description: at the time the extensions had no mapping, so a score arrived as an unknown binary. They map since server 32:So only those two are claimed here. Registering the fallback type would have handed this handler every unrecognised file on the server, and there is a test pinning that it does not.
Two megabytes, loaded by the people who want it
opensheetmusicdisplayunpacks to 2 MB. It is imported inside the component rather than at the top of the module, so it does not sit in the path every viewer user walks:The renderer stays a bare external import inside that chunk, so a consuming bundler gives it a chunk of its own and fetches it the first time someone opens a score. Opening a photo never touches it.
Two things this format needs that the others do not
A
.mxlis a zip holding the score, so the file is handed to the renderer as the bytes it arrived as, not as text. Both forms are tested.The bigger one: the viewer keeps a handler hidden until it emits
loaded, and an element that is not displayed has no width. Drawing first and reporting afterwards deadlocks — the score renders into a frame of zero width and comes out as<svg width="0">. That is what the first four attempts here did, and it is visible in the debugging:element.offsetWidthwas0at render time even after a frame. So this handler reports loaded once the score is parsed, then waits for the frame to have a width before drawing. The other handlers never meet this because an image sizes itself.Covered
352 unit tests, 4 new: both score mimes enable the handler, a JPEG does not, and
application/octet-streamdoes not.52 e2e across Chromium and Firefox, 3 new, against two real fixtures added to the playground. They assert the score is actually drawn rather than that the modal opened: more than ten
<path>elements inside the rendered SVG, and the title read out of the file (Viewer test score, andViewer test score compressedfor the zipped one, so the two cannot pass for each other). A third opens a JPEG and asserts no sheet-music element appears.Note
Tested against the playground, not a live server. The mimes come from the server mapping above, so a score uploaded to a real instance should arrive as the right type, but that is worth confirming when you try it.
Not attempted: page navigation, zoom, transposition or playback. This renders the score and nothing more.
👾 This pull request was assisted by Claude Code, commits carry an
Assisted-bytrailer.