From 8b930687805db0bf85674b3e16467aa30b142688 Mon Sep 17 00:00:00 2001 From: Will Knowles Date: Tue, 6 Oct 2026 01:47:17 +0100 Subject: [PATCH 1/2] Build with the kit's config(): the asking installer, Open With on Linux, appId and busy - electron-builder.cjs, from config(): package.json's build moves there, with the 22 types as fileTypes and "Convert with Diamond File Converter" on files and folders as contextMenu. installer.nsh goes: the kit's installer writes the same key, asks who it's for (upgrading an install for everyone in place), and asks for each type and the right-click entry. On Linux, the .deb and .rpm put the app in Open With for each type. - start({ appId }): Windows groups the window under its pinned icon and shows its notifications. - mountShell({ busy }): Restart Now asks first while a conversion or a join runs. - README's installation, the design-system note, and a beta.6 section in MANUAL-TESTING.md. --- README.md | 4 +- docs/MANUAL-TESTING.md | 47 +++++++++++ docs/design-system/build.js | 2 +- docs/design-system/shell/context-menu.html | 2 +- electron-builder.cjs | 61 ++++++++++++++ installer.nsh | 17 ---- package-lock.json | 8 +- package.json | 95 +--------------------- src/main.js | 3 + src/renderer.js | 2 + test/kit.test.js | 27 ++++-- 11 files changed, 141 insertions(+), 127 deletions(-) create mode 100644 electron-builder.cjs delete mode 100644 installer.nsh diff --git a/README.md b/README.md index ee296b2..aa62f45 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Download the files for your system from the [releases page](https://github.com/d ### Windows -Download **Diamond-File-Converter-Setup-``.exe** and run it. It installs for all users, so it will ask for administrator rights. +Download **Diamond-File-Converter-Setup-``.exe** and run it. It asks who it's for: only you (the default, with no administrator prompt) or everyone on the computer. If Diamond File Converter is already installed for everyone, as every version before 2.0.0-beta.6 was, that copy is updated instead. It then asks which file types to open with it, all ticked, and whether to add **Convert with Diamond File Converter** to the menu files and folders show when you right-click them. > [!NOTE] > You may get a Windows SmartScreen popup when trying to run the installer. This is normal as the installer is not signed. @@ -45,7 +45,7 @@ Download **Diamond-File-Converter-Setup-``.exe** and run it. It install - **Fedora, openSUSE and others using RPM:** download **Diamond-File-Converter-``.rpm** and install it with your package manager, such as `sudo dnf install ./Diamond-File-Converter-.rpm`. - **Anywhere else:** download **Diamond-File-Converter-``.AppImage**, make it executable with `chmod +x`, and run it. -Linux builds start with 2.0. For now, the app isn't offered in "Open with" for media files on Linux, and the dock may show a generic icon for its window; opening files from a terminal (`diamond-file-converter file.mp4`) works. +Linux builds start with 2.0. With the `.deb` or `.rpm`, the app is in your file manager's "Open with" for the files it converts. Opening files from a terminal (`diamond-file-converter file.mp4`) works too. ### On every system diff --git a/docs/MANUAL-TESTING.md b/docs/MANUAL-TESTING.md index 271310b..de3e18c 100644 --- a/docs/MANUAL-TESTING.md +++ b/docs/MANUAL-TESTING.md @@ -2716,3 +2716,50 @@ Use a video long enough to convert for ten seconds or more (a few minutes of format select all work again. Advanced Options opens, and Apply says **Settings applied to 1 file.** - [ ] Bulk Edit still works on a selection when nothing is converting. + +## 2.0.0-beta.6: the kit's installer, and electron-kit 0.1.0-beta.8 (2026-10-06) + +DFC moves its build config to the kit's `config()` (`electron-builder.cjs`), so +the Windows installer is the kit's asking installer and `installer.nsh` is gone. +It also passes its `appId` to the kit, says when it's busy, and takes the kit's +Update tab changes since 0.1.0-beta.3. + +> **Status: not yet run.** + +### Upgrading an install for everyone (every earlier version's) + +- [ ] With beta.5 installed (for everyone), run the beta.6 installer. It does + not ask who it's for: it upgrades that copy, and Settings > Apps lists + Diamond File Converter once. +- [ ] Right-click a file, then a folder: **Convert with Diamond File + Converter** is there once on each (Windows 11: under "Show more + options"), with the app's icon, and opens the file or folder in the app. +- [ ] Right-click an `.mp3`, Open with: Diamond File Converter is offered. + +### A fresh install, only for me + +- [ ] Uninstall, then run the installer again: it asks who it's for, "Only for + me" chosen, and installs with no administrator prompt. +- [ ] The file types page shows the 22 types in three groups, all ticked, and + the right-click box ticked. Untick **WMA** and the right-click box. +- [ ] After the install, a `.wma` doesn't offer the app in Open with, an + `.mp3` does, and there's no Convert entry on right-click. +- [ ] Install the same build again over it: WMA and the right-click box start + unticked. +- [ ] Uninstall: the app is gone from Open with for every type. + +### The Update tab and Restart Now + +- [ ] Open the app and go straight to Settings > Update: the status line is + never empty. It says "Updates haven't been checked yet." for a moment + at most, then "Checking for updates…", then the result. +- [ ] Open Settings > Update only after ten seconds: one check has run, and + Check for Updates runs another. +- [ ] With an update downloaded, start a long conversion and press **Restart + Now**: it asks first ("A conversion is running."), and Cancel keeps the + conversion going. The same while a join runs ("A join is running."). + +### Notifications and the taskbar (Windows) + +- [ ] Pin the app to the taskbar and open it: its window groups under the + pinned icon, not a second one. diff --git a/docs/design-system/build.js b/docs/design-system/build.js index a0324bf..d4092c3 100644 --- a/docs/design-system/build.js +++ b/docs/design-system/build.js @@ -833,7 +833,7 @@ card("shell/context-menu.html", "Context Menu", !macro customUninstall DeleteRegKey HKCR "*\\shell\\<App>" !macroend -

Lives in installer.nsh, referenced from build.nsis.include. Always pair customInstall with customUninstall — an uninstall that leaves the key behind puts a dead entry in every user's context menu.

+

Made by electron-kit's config() from contextMenu in electron-builder.cjs: the installer asks before adding it, and uninstalling takes it away. An app never writes its own installer.nsh.

The batching problem

Windows launches one process per selected file. Selecting 30 files spawns 30 processes, 29 of which hit the single-instance lock and forward their path through second-instance. Collect those arrivals and debounce for 500ms before handing them to the renderer, or the queue is rebuilt 30 times. Dropgate's BATCH_DEBOUNCE_MS is the reference.

diff --git a/docs/design-system/shell/context-menu.html b/docs/design-system/shell/context-menu.html index 5e86b0a..6eeb878 100644 --- a/docs/design-system/shell/context-menu.html +++ b/docs/design-system/shell/context-menu.html @@ -71,7 +71,7 @@

How it is registered

!macro customUninstall DeleteRegKey HKCR "*\shell\<App>" !macroend -

Lives in installer.nsh, referenced from build.nsis.include. Always pair customInstall with customUninstall — an uninstall that leaves the key behind puts a dead entry in every user's context menu.

+

Made by electron-kit's config() from contextMenu in electron-builder.cjs: the installer asks before adding it, and uninstalling takes it away. An app never writes its own installer.nsh.

The batching problem

Windows launches one process per selected file. Selecting 30 files spawns 30 processes, 29 of which hit the single-instance lock and forward their path through second-instance. Collect those arrivals and debounce for 500ms before handing them to the renderer, or the queue is rebuilt 30 times. Dropgate's BATCH_DEBOUNCE_MS is the reference.

diff --git a/electron-builder.cjs b/electron-builder.cjs new file mode 100644 index 0000000..f136772 --- /dev/null +++ b/electron-builder.cjs @@ -0,0 +1,61 @@ +"use strict"; + +// The desktop app's electron-builder config, made by the kit's config() on its +// base (NSIS in the Diamond Digital Development menu folder; AppImage, .deb and +// .rpm). It's .cjs, never .js: on Windows, electron-builder typed in this +// folder would run electron-builder.js with Windows Script Host instead. +// +// - The installer asks who it's for (an install for everyone, as every one +// before 2.0.0-beta.6 was, is upgraded in place), then which of the 22 types +// to open and whether to add "Convert with Diamond File Converter" to the +// menu files and folders have when they're right-clicked. It replaced +// installer.nsh, and keeps its registry key, so an upgrade never shows the +// entry twice. On Linux, the app is in Open With for each type. +// - ffmpeg and ffprobe are packed per platform, where main.js looks for them; +// the packages' own binaries stay out of app.asar.unpacked (415 MB in 2.0.0). +const { config } = require("@diamonddigitaldev/electron-kit/builder"); + +module.exports = config(require("./package.json"), { + build: { + appId: "com.diamonddigitaldev.diamondfileconverter", + productName: "Diamond File Converter", + artifactName: "Diamond-File-Converter-${version}.${ext}", + files: [ + "**/*", + "!test-media", + "!test-media/**/*", + "!node_modules/ffmpeg-static/ffmpeg{,.exe}", + "!node_modules/ffprobe-static/bin/**", + ], + publish: { + provider: "github", + owner: "diamonddigitaldev", + repo: "Diamond-File-Converter", + }, + win: { + icon: "src/assets/diamondfileconverter.ico", + extraResources: [ + { from: "node_modules/ffmpeg-static/ffmpeg.exe", to: "ffmpeg/ffmpeg.exe" }, + { from: "node_modules/ffprobe-static/bin/win32/x64/ffprobe.exe", to: "ffmpeg/ffprobe.exe" }, + ], + }, + linux: { + icon: "src/assets/diamondfileconverter.png", + category: "AudioVideo", + extraResources: [ + { from: "node_modules/ffmpeg-static/ffmpeg", to: "ffmpeg/ffmpeg" }, + { from: "node_modules/ffprobe-static/bin/linux/x64/ffprobe", to: "ffmpeg/ffprobe" }, + ], + }, + // The installer's name is what its update files point at: unchanged from 2.0.0. + nsis: { + artifactName: "Diamond-File-Converter-Setup-${version}.${ext}", + }, + }, + fileTypes: [ + { name: "Audio File", ext: ["mp3", "wav", "flac", "ogg", "aac", "m4a", "opus", "wma"] }, + { name: "Video File", ext: ["mp4", "mkv", "webm", "avi", "mov", "wmv", "flv"] }, + { name: "Image File", ext: ["jpg", "jpeg", "png", "webp", "gif", "bmp", "tiff"] }, + ], + contextMenu: { label: "Convert with Diamond File Converter", folders: true }, +}); diff --git a/installer.nsh b/installer.nsh deleted file mode 100644 index 022eeb5..0000000 --- a/installer.nsh +++ /dev/null @@ -1,17 +0,0 @@ -!macro customInstall - ; Add "Convert with Diamond File Converter" to the context menu with icon - WriteRegStr HKCR "*\shell\DiamondFileConverter" "" "Convert with Diamond File Converter" - WriteRegStr HKCR "*\shell\DiamondFileConverter" "Icon" "$INSTDIR\${APP_EXECUTABLE_FILENAME}" - WriteRegStr HKCR "*\shell\DiamondFileConverter\command" "" '"$INSTDIR\${APP_EXECUTABLE_FILENAME}" "%1"' - - ; Add the same entry for directories, so a whole folder can be queued - WriteRegStr HKCR "Directory\shell\DiamondFileConverter" "" "Convert with Diamond File Converter" - WriteRegStr HKCR "Directory\shell\DiamondFileConverter" "Icon" "$INSTDIR\${APP_EXECUTABLE_FILENAME}" - WriteRegStr HKCR "Directory\shell\DiamondFileConverter\command" "" '"$INSTDIR\${APP_EXECUTABLE_FILENAME}" "%1"' -!macroend - -!macro customUninstall - ; Clean up the registry keys on uninstall - DeleteRegKey HKCR "*\shell\DiamondFileConverter" - DeleteRegKey HKCR "Directory\shell\DiamondFileConverter" -!macroend diff --git a/package-lock.json b/package-lock.json index a503b95..bd147d9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "2.0.0-beta.5", "license": "Apache-2.0", "dependencies": { - "@diamonddigitaldev/electron-kit": "0.1.0-beta.3", + "@diamonddigitaldev/electron-kit": "0.1.0-beta.7", "bootstrap": "^5.3.3", "electron-store": "^11.0.2", "electron-updater": "^6.8.9", @@ -40,9 +40,9 @@ } }, "node_modules/@diamonddigitaldev/electron-kit": { - "version": "0.1.0-beta.3", - "resolved": "https://registry.npmjs.org/@diamonddigitaldev/electron-kit/-/electron-kit-0.1.0-beta.3.tgz", - "integrity": "sha512-s9fTQ4LpI1FrJ1kzXtVDfDwLlGfxzr40liRZsWyTt9F839JZ8BkpC3Y4Y+L87kpexCBgGPZR/swLepwFCxuA+A==", + "version": "0.1.0-beta.7", + "resolved": "https://registry.npmjs.org/@diamonddigitaldev/electron-kit/-/electron-kit-0.1.0-beta.7.tgz", + "integrity": "sha512-MsuGaHCWyqTufWKZTzXvgENGhKPOUqsKxTao1VGnc50mFBl6adXToz/rWrB2MI3Mp6RX04TNFxzHsoQK/PeErA==", "license": "Apache-2.0", "engines": { "node": ">=24.0.0" diff --git a/package.json b/package.json index a52dea7..6a0df52 100644 --- a/package.json +++ b/package.json @@ -16,99 +16,6 @@ "type": "git", "url": "https://github.com/diamonddigitaldev/Diamond-File-Converter" }, - "build": { - "extends": "@diamonddigitaldev/electron-kit/builder/base.json", - "appId": "com.diamonddigitaldev.diamondfileconverter", - "files": [ - "**/*", - "!test-media", - "!test-media/**/*", - "!node_modules/ffmpeg-static/ffmpeg{,.exe}", - "!node_modules/ffprobe-static/bin/**" - ], - "productName": "Diamond File Converter", - "artifactName": "Diamond-File-Converter-${version}.${ext}", - "fileAssociations": [ - { - "ext": [ - "mp3", - "wav", - "flac", - "ogg", - "aac", - "m4a", - "opus", - "wma" - ], - "name": "Audio File", - "role": "Editor" - }, - { - "ext": [ - "mp4", - "mkv", - "webm", - "avi", - "mov", - "wmv", - "flv" - ], - "name": "Video File", - "role": "Editor" - }, - { - "ext": [ - "jpg", - "jpeg", - "png", - "webp", - "gif", - "bmp", - "tiff" - ], - "name": "Image File", - "role": "Editor" - } - ], - "publish": { - "provider": "github", - "owner": "diamonddigitaldev", - "repo": "Diamond-File-Converter" - }, - "win": { - "icon": "src/assets/diamondfileconverter.ico", - "extraResources": [ - { - "from": "node_modules/ffmpeg-static/ffmpeg.exe", - "to": "ffmpeg/ffmpeg.exe" - }, - { - "from": "node_modules/ffprobe-static/bin/win32/x64/ffprobe.exe", - "to": "ffmpeg/ffprobe.exe" - } - ] - }, - "linux": { - "icon": "src/assets/diamondfileconverter.png", - "category": "AudioVideo", - "extraResources": [ - { - "from": "node_modules/ffmpeg-static/ffmpeg", - "to": "ffmpeg/ffmpeg" - }, - { - "from": "node_modules/ffprobe-static/bin/linux/x64/ffprobe", - "to": "ffmpeg/ffprobe" - } - ] - }, - "nsis": { - "artifactName": "Diamond-File-Converter-Setup-${version}.${ext}", - "perMachine": true, - "createDesktopShortcut": true, - "include": "installer.nsh" - } - }, "keywords": [], "author": "Diamond Digital Development ", "license": "Apache-2.0", @@ -117,7 +24,7 @@ "electron-builder": "^26.15.3" }, "dependencies": { - "@diamonddigitaldev/electron-kit": "0.1.0-beta.3", + "@diamonddigitaldev/electron-kit": "0.1.0-beta.7", "bootstrap": "^5.3.3", "electron-store": "^11.0.2", "electron-updater": "^6.8.9", diff --git a/src/main.js b/src/main.js index af12b65..4f436ec 100644 --- a/src/main.js +++ b/src/main.js @@ -42,6 +42,9 @@ function extensionsOfKind(kind) { const kit = require("@diamonddigitaldev/electron-kit/main").start({ // package.json's name is the npm name, which names the userData folder too. name: APP_NAME, + // electron-builder.cjs's appId: Windows shows the app's notifications, and + // groups its windows under its pinned icon, only when the two match. + appId: "com.diamonddigitaldev.diamondfileconverter", settings: { defaults: SETTINGS_DEFAULTS, // Version 2: the settings v1 wrote that 2.0 can't show, and the store diff --git a/src/renderer.js b/src/renderer.js index 8461135..7350ea8 100644 --- a/src/renderer.js +++ b/src/renderer.js @@ -2024,6 +2024,8 @@ document.addEventListener("DOMContentLoaded", async () => { toolbar: $("toolbar"), credits: { logo: "assets/diamondfileconverter.png" }, onViewChange, + // Restart Now asks first while a conversion or a join runs: the restart would stop it. + busy: () => (converting ? "A conversion is running." : joinRunning ? "A join is running." : null), }); FORMATS = await api.getFormats(); diff --git a/test/kit.test.js b/test/kit.test.js index f78a96c..b35e241 100644 --- a/test/kit.test.js +++ b/test/kit.test.js @@ -53,12 +53,23 @@ test("the updater is the kit's: DFC passes updates, and has no updater or update assert.equal(version.isOfferableUpdate("1.0.0", "2.0.0-alpha.1", "stable"), false); }); -test("the build extends the kit's base config, and keeps DFC's own", () => { - const pkg = require("../package.json"); - assertBuildExtendsKit(pkg); - assert.deepEqual(pkg.build.publish, { provider: "github", owner: "diamonddigitaldev", repo: "Diamond-File-Converter" }); - assert.equal(pkg.build.nsis.perMachine, true); - assert.equal(pkg.build.nsis.include, "installer.nsh"); +test("the build is the kit's config(), with DFC's own: its 22 types and its right-click entry, on files and folders", () => { + const build = require("../electron-builder.cjs"); + assertBuildExtendsKit(build); + assert.equal(require("../package.json").build, undefined, "electron-builder would read package.json's build first"); + assert.ok(!fs.existsSync(path.join(__dirname, "..", "installer.nsh")), "the kit's installer adds the right-click entry"); + assert.deepEqual(build.publish, { provider: "github", owner: "diamonddigitaldev", repo: "Diamond-File-Converter" }); + assert.equal(build.appId, "com.diamonddigitaldev.diamondfileconverter"); + // The same ID in main.js, for Windows' notifications and taskbar grouping. + assert.match(read("main.js"), /\.start\(\{[^]*?appId: "com\.diamonddigitaldev\.diamondfileconverter",/); + assert.equal(build.fileAssociations, undefined, "the kit's installer asks for each type instead"); + const script = fs.readFileSync(build.nsis.include, "utf8"); + for (const ext of ["mp3", "wma", "mp4", "flv", "jpg", "tiff"]) assert.ok(script.includes(`DiamondFileConverter.${ext}`), ext); + assert.equal(script.match(/WriteRegStr SHELL_CONTEXT "Software\\Classes\\\.[a-z0-9]+\\OpenWithProgids"/g)?.length, 22); + // The key installer.nsh wrote, so an install upgraded from it shows the entry once. + assert.ok(script.includes("Software\\Classes\\*\\shell\\DiamondFileConverter")); + assert.ok(script.includes("Software\\Classes\\Directory\\shell\\DiamondFileConverter")); + assert.ok(script.includes("Convert with Diamond File Converter")); }); test("the Credits tab is given the app's name, not package.json's npm name", () => { @@ -161,7 +172,7 @@ test("every icon is hidden from screen readers, and every icon-only button has a }); test("ffmpeg and ffprobe are packed per platform, where main.js looks for them, and only once", () => { - const { build } = require("../package.json"); + const build = require("../electron-builder.cjs"); const main = read("main.js"); const exe = { win: ".exe", linux: "" }; for (const platform of ["win", "linux"]) { @@ -179,7 +190,7 @@ test("ffmpeg and ffprobe are packed per platform, where main.js looks for them, }); test("the Windows installer is the one called Setup: Linux's files are named for the app and version only", () => { - const { build } = require("../package.json"); + const build = require("../electron-builder.cjs"); assert.equal(build.artifactName, "Diamond-File-Converter-${version}.${ext}"); // The installer's name is what its update files point at: unchanged from 2.0.0. assert.equal(build.nsis.artifactName, "Diamond-File-Converter-Setup-${version}.${ext}"); From 851b7aaa73fbdfd3c1b057e998c825c8199389eb Mon Sep 17 00:00:00 2001 From: Will Knowles Date: Tue, 6 Oct 2026 03:01:22 +0100 Subject: [PATCH 2/2] chore: 2.0.0-beta.6, on electron-kit 0.1.0-beta.8 --- package-lock.json | 12 ++++++------ package.json | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index bd147d9..b85f8a0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "diamond-file-converter", - "version": "2.0.0-beta.5", + "version": "2.0.0-beta.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "diamond-file-converter", - "version": "2.0.0-beta.5", + "version": "2.0.0-beta.6", "license": "Apache-2.0", "dependencies": { - "@diamonddigitaldev/electron-kit": "0.1.0-beta.7", + "@diamonddigitaldev/electron-kit": "0.1.0-beta.8", "bootstrap": "^5.3.3", "electron-store": "^11.0.2", "electron-updater": "^6.8.9", @@ -40,9 +40,9 @@ } }, "node_modules/@diamonddigitaldev/electron-kit": { - "version": "0.1.0-beta.7", - "resolved": "https://registry.npmjs.org/@diamonddigitaldev/electron-kit/-/electron-kit-0.1.0-beta.7.tgz", - "integrity": "sha512-MsuGaHCWyqTufWKZTzXvgENGhKPOUqsKxTao1VGnc50mFBl6adXToz/rWrB2MI3Mp6RX04TNFxzHsoQK/PeErA==", + "version": "0.1.0-beta.8", + "resolved": "https://registry.npmjs.org/@diamonddigitaldev/electron-kit/-/electron-kit-0.1.0-beta.8.tgz", + "integrity": "sha512-fqGnYFxONG5eg76QT0ZvZTdcdapHy3Mxlm4vvIMDA7Z9x6s0a6RE5gnoq6dXLc6iqelrmc1HvbaYs4AB2FDYcw==", "license": "Apache-2.0", "engines": { "node": ">=24.0.0" diff --git a/package.json b/package.json index 6a0df52..8cd5658 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "diamond-file-converter", - "version": "2.0.0-beta.5", + "version": "2.0.0-beta.6", "description": "An Electron-based desktop app for converting audio, video, and image files.", "main": "src/main.js", "funding": { @@ -24,7 +24,7 @@ "electron-builder": "^26.15.3" }, "dependencies": { - "@diamonddigitaldev/electron-kit": "0.1.0-beta.7", + "@diamonddigitaldev/electron-kit": "0.1.0-beta.8", "bootstrap": "^5.3.3", "electron-store": "^11.0.2", "electron-updater": "^6.8.9",