Fix compressed .mxl handling

This commit is contained in:
2024-12-30 23:12:25 +01:00
parent fc64f77335
commit 52933e617a
5 changed files with 78 additions and 13 deletions

View File

@@ -25,6 +25,7 @@
"clsx": "catalog:",
"common": "workspace:^",
"effect": "catalog:",
"jszip": "catalog:",
"lucide-react": "catalog:",
"opensheetmusicdisplay": "catalog:",
"react": "catalog:",

View File

@@ -67,13 +67,21 @@ const router = createBrowserRouter([
path: "/login",
Component: Login,
},
]);
], {
future: {
v7_fetcherPersist: true,
v7_normalizeFormMethod: true,
v7_partialHydration: true,
v7_relativeSplatPath: true,
v7_skipActionErrorRevalidation: true,
},
});
const rootElement = document.getElementById("root") as HTMLDivElement;
const root = createRoot(rootElement);
root.render(
<StrictMode>
<RouterProvider router={router} />
<RouterProvider router={router} future={{ v7_startTransition: true }} />
</StrictMode>,
);

View File

@@ -1,8 +1,9 @@
import { client } from "@/client";
import { useLoading } from "@/hooks/useLoading.ts";
import { AttachmentId, PieceId } from "common";
import JSZip from "jszip";
import { OpenSheetMusicDisplay } from "opensheetmusicdisplay";
import { useEffect, useRef } from "react";
import { useCallback, useEffect, useRef } from "react";
import { useParams } from "react-router-dom";
export default function Attachment() {
@@ -14,33 +15,81 @@ export default function Attachment() {
const { isLoading, error, data } = useLoading(() => client.piece({ pieceId }).attachment({ attachmentId }).get(), [pieceId, attachmentId]);
const containerRef = useRef<HTMLDivElement>(null);
const renderFn = useRef<null | (() => void)>(null);
const load = useCallback(async () => {
useEffect(() => {
if (isLoading || error !== null) return;
const url = URL.createObjectURL(data);
let musixXmlBlob: Blob = data;
const render = () => osmd.render();
/* If the file is the compressed .mxl file, we do the uncompression
* ourselves, because apparently OpenSheetMusicDisplay is incapable.
*/
if (data.type === "application/vnd.recordare.musicxml") {
const zip = new JSZip();
await zip.loadAsync(data);
const containerFile = zip.file("META-INF/container.xml");
if (containerFile === null) {
console.error("Missing META-INF/container.xml in the .mxl file");
return;
}
const containerText = await containerFile.async("text");
const containerXml = new DOMParser().parseFromString(containerText, "application/xml");
const rootFile = containerXml.querySelector("rootfile[media-type=\"application/vnd.recordare.musicxml+xml\"], rootfile:not([media-type])");
if (rootFile === null) {
console.error("Missing root MusicXML file in META-INF/container.xml");
return;
}
const fullPath = rootFile.getAttribute("full-path");
if (fullPath === null) {
console.error("Missing full-path attribute in rootfile element");
return;
}
const musicXmlFile = zip.file(fullPath);
if (musicXmlFile === null) {
console.error(`Missing ${fullPath} file in the .mxl archive`);
return;
}
musixXmlBlob = await musicXmlFile.async("blob");
}
const musicXml = await musixXmlBlob.text();
const osmd = new OpenSheetMusicDisplay(containerRef.current!, {
autoResize: false,
drawTitle: false,
drawComposer: false,
drawMeasureNumbers: true,
drawMeasureNumbersOnlyAtSystemStart: true,
//measureNumberInterval: 5,
//renderSingleHorizontalStaffline: true,
drawMeasureNumbersOnlyAtSystemStart: false,
measureNumberInterval: 1,
renderSingleHorizontalStaffline: true,
});
osmd.load(url).then(render, (error) => console.error(error));
const render = () => osmd.render();
await osmd.load(musicXml);
render();
renderFn.current = render;
}, [data, error, isLoading]);
useEffect(() => void load(), [load]);
useEffect(() => {
const render = () => renderFn.current?.();
window.addEventListener("resize", render);
return () => {
URL.revokeObjectURL(url);
window.removeEventListener("resize", render);
};
}, [data, error, isLoading]);
}, []);
if (isLoading) {
return (

6
pnpm-lock.yaml generated
View File

@@ -66,6 +66,9 @@ catalogs:
eslint-plugin-react-hooks:
specifier: ^5.1.0
version: 5.1.0
jszip:
specifier: ^3.10.1
version: 3.10.1
kysely:
specifier: ^0.27.4
version: 0.27.4
@@ -192,6 +195,9 @@ importers:
effect:
specifier: 'catalog:'
version: 3.11.4
jszip:
specifier: 'catalog:'
version: 3.10.1
lucide-react:
specifier: 'catalog:'
version: 0.462.0(react@18.3.1)

View File

@@ -22,6 +22,7 @@ catalog:
effect: '^3.11.4'
elysia: '^1.1.25'
eslint-plugin-react-hooks: '^5.1.0'
jszip: '^3.10.1'
kysely: '^0.27.4'
kysely-bun-sqlite: '^0.3.2'
lucide-react: '^0.462.0'