From 8badd2d8262da845faf957da16f0f4b4b977cd5c Mon Sep 17 00:00:00 2001 From: daylightsavings Date: Fri, 3 Jul 2026 02:13:24 -0400 Subject: [PATCH] Update for netmd-js 4.x and Web MiniDisc Pro The current Web MiniDisc Pro client uses netmd-js 4.x, which this server had not been updated for. Against a 4.x netmd-js the old code fails: EKBOpenSource is no longer exported and MDSession resolves the EKB internally. - MDSession: drop the EKBOpenSource argument; init() derives the EKB from the device's vendor/product IDs. new MDSession(device). - Track converters: report SP as SPS (stereo) / SPM (mono) and MDLP as AT3 with a bitrate, matching what the current client sends and displays. - /upload: accept the SPS/SPM codec names the current client sends (both map to the PCM wireformat) and record SPM with the mono disc format. - normalizeGroups: a blank disc returns an empty groups array from netmd-js; synthesize the ungrouped bucket the client expects, and make the group/track converters null-safe. - package.json: depend on the published netmd-js ^4.4.1. Tested live against a Sony MZ-N505 (SP and LP2 uploads, disc listing, group rewrite). Happy to keep the file:../netmd-js dependency style if preferred. --- index.js | 52 ++++++++++++++++++++++++++++++++++++---------------- package.json | 2 +- 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/index.js b/index.js index 367287c..8faca6f 100644 --- a/index.js +++ b/index.js @@ -26,21 +26,29 @@ import { DevicesIds, rewriteDiscGroups, prepareDownload, - EKBOpenSource, MDSession, - Wireformat + Wireformat, + DiscFormat } from 'netmd-js'; import { Mutex } from 'async-mutex'; +// A blank disc can come back from netmd-js with an empty groups array; +// Web MiniDisc expects at least the "ungrouped" bucket to exist. +function normalizeGroups(groups){ + return (groups && groups.length) + ? groups + : [{ index: 0, title: null, fullWidthTitle: null, tracks: [] }]; +} + // Compatibility methods. Do NOT use these unless absolutely necessary!! export function convertDiscToWMD(source){ return { ...source, left: Math.ceil(source.left / 512), total: Math.ceil(source.total / 512), - groups: source.groups.map(convertGroupToWMD), + groups: normalizeGroups(source.groups).map(convertGroupToWMD), }; } @@ -49,32 +57,36 @@ export function convertDiscToNJS(source){ ...source, left: source.left * 512, total: source.total * 512, - groups: source.groups.map(convertGroupToNJS), + groups: normalizeGroups(source.groups).map(convertGroupToNJS), }; } export function convertGroupToWMD(source){ return { ...source, - tracks: source.tracks.map(convertTrackToWMD) + tracks: (source.tracks || []).map(convertTrackToWMD) }; } export function convertGroupToNJS(source){ return { ...source, - tracks: source.tracks.map(convertTrackToNJS), + tracks: (source.tracks || []).map(convertTrackToNJS), }; } +// Web MiniDisc Pro reports SP as SPS (stereo) / SPM (mono) and MDLP as AT3 with +// a bitrate, rather than the older SP/LP2/LP4 codec names. export function convertTrackToWMD(source){ return ({ ...source, duration: Math.ceil(source.duration / 512), encoding: ({ - [Encoding.sp]: { codec: "SP" }, - [Encoding.lp2]: { codec: "LP2" }, - [Encoding.lp4]: { codec: "LP4" }, + [Encoding.sp]: source.channel === 1 + ? { codec: "SPM", bitrate: 146 } + : { codec: "SPS", bitrate: 292 }, + [Encoding.lp2]: { codec: "AT3", bitrate: 132 }, + [Encoding.lp4]: { codec: "AT3", bitrate: 66 }, })[source.encoding], }); } @@ -83,11 +95,11 @@ export function convertTrackToNJS(source){ return { ...source, duration: source.duration * 512, - encoding: ({ - "SP": Encoding.sp, - "LP2": Encoding.lp2, - "LP4": Encoding.lp4, - })[["SP", "LP2", "LP4"].includes(source.encoding.codec) ? source.encoding.codec : "SP"], + encoding: source.encoding.codec.startsWith("SP") + ? Encoding.sp + : source.encoding.bitrate === 132 + ? Encoding.lp2 + : Encoding.lp4, } } @@ -535,7 +547,9 @@ function setup(app) { let session = null; app.get('/prepareUpload', async (req, res) => { await prepareDownload(device); - session = new MDSession(device, new EKBOpenSource()); + // netmd-js 4.x resolves the EKB internally in init() from the device's + // vendor/product IDs; MDSession takes (NetMDInterface, hexSessionKey?). + session = new MDSession(device); await session.init(); success(res); }); @@ -562,12 +576,18 @@ function setup(app) { } = req.query; if (!fullWidthTitle) fullWidthTitle = ''; if (title === undefined || title === null || format === undefined || format === null) ws.close(); + // Accept both the wireformat names (SP/LP2/LP4) and the codec names + // the current Web MiniDisc Pro client sends (SPS = SP stereo, + // SPM = SP mono). SPM additionally records with a mono disc format. const WireformatDict = { SP: Wireformat.pcm, + SPS: Wireformat.pcm, + SPM: Wireformat.pcm, LP2: Wireformat.lp2, LP105: Wireformat.l105kbps, LP4: Wireformat.lp4, }; + const discFormat = format === "SPM" ? DiscFormat.spMono : undefined; format = WireformatDict[format]; let written = 0; @@ -615,7 +635,7 @@ function setup(app) { }) => { written = writtenBytes; updateProgress(); - }); + }, discFormat); flushCache(); ws.send(JSON.stringify({ terminate: true })); diff --git a/package.json b/package.json index 5becd72..eca70e7 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "async-mutex": "^0.3.2", "express": "^4.17.1", "express-ws": "^5.0.2", - "netmd-js": "file:../netmd-js-workingtree", + "netmd-js": "^4.4.1", "usb": "^2.7.0", "yargs": "^17.3.1" }