diff --git a/README.md b/README.md index 3eda3d2..91fd528 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,6 @@ A web application that provides a GUI for applying custom [kobopatch](https://github.com/pgaskin/kobopatch) patches to Kobo e-readers. It uses the File System Access API (Chromium) to interface with connected Kobo devices, or falls back to manual model/firmware selection on other browsers. - - The app makes it easy to configure which patches to apply, downloads the correct firmware from Kobo's servers, runs the patcher (compiled to WebAssembly), and places the resulting `KoboRoot.tgz` on the device. The user then reboots to apply. Fully client-side — no backend needed, can be hosted as a static site. Patches are community-contributed via [MobileRead](https://www.mobileread.com/) and need to be manually updated when new Kobo firmware versions come out. diff --git a/kobopatch-wasm/build.sh b/kobopatch-wasm/build.sh index 23494d5..4a56a70 100755 --- a/kobopatch-wasm/build.sh +++ b/kobopatch-wasm/build.sh @@ -23,8 +23,10 @@ echo "Copying artifacts to $PUBLIC_DIR..." cp kobopatch.wasm "$PUBLIC_DIR/kobopatch.wasm" cp wasm_exec.js "$PUBLIC_DIR/wasm_exec.js" -# Update the cache-busting timestamp in the worker +# Update cache-busting timestamps sed -i "s|kobopatch\.wasm?ts=[0-9]*|kobopatch.wasm?ts=$TS|g" "$PUBLIC_DIR/patch-worker.js" +sed -i "s|\.js?ts=[0-9]*|.js?ts=$TS|g" "$PUBLIC_DIR/index.html" +sed -i "s|\.css?ts=[0-9]*|.css?ts=$TS|g" "$PUBLIC_DIR/index.html" echo "Build timestamp: $TS" echo "Done." diff --git a/screenshot.png b/screenshot.png deleted file mode 100644 index 76f3a95..0000000 Binary files a/screenshot.png and /dev/null differ diff --git a/web/public/app.js b/web/public/app.js index f82e471..c744953 100644 --- a/web/public/app.js +++ b/web/public/app.js @@ -41,7 +41,8 @@ const deviceStatus = document.getElementById('device-status'); const patchContainer = document.getElementById('patch-container'); const buildStatus = document.getElementById('build-status'); - const writeSuccess = document.getElementById('write-success'); + const writeInstructions = document.getElementById('write-instructions'); + const downloadInstructions = document.getElementById('download-instructions'); const firmwareVersionLabel = document.getElementById('firmware-version-label'); const firmwareDeviceLabel = document.getElementById('firmware-device-label'); const patchCountHint = document.getElementById('patch-count-hint'); @@ -306,7 +307,6 @@ } btnBuild.addEventListener('click', async () => { - hideNav(); showStep(stepBuilding); buildLog.textContent = ''; buildProgress.textContent = 'Starting...'; @@ -337,32 +337,52 @@ buildStatus.textContent = 'Patching complete. KoboRoot.tgz is ' + (resultTgz.length / 1024).toFixed(0) + ' KB.'; - writeSuccess.hidden = true; const doneLog = document.getElementById('done-log'); doneLog.textContent = buildLog.textContent; - doneLog.scrollTop = doneLog.scrollHeight; + // Reset install step state. btnWrite.hidden = manualMode; - hideNav(); + btnWrite.disabled = false; + btnWrite.className = 'primary'; + btnWrite.textContent = 'Write to Kobo'; + btnDownload.disabled = false; + writeInstructions.hidden = true; + downloadInstructions.hidden = true; + + setNavStep(4); showStep(stepDone); + + // Scroll log to bottom after the step becomes visible. + requestAnimationFrame(() => { + doneLog.scrollTop = doneLog.scrollHeight; + }); } catch (err) { showError('Build failed: ' + err.message, buildLog.textContent); } }); - // --- Done step --- + // --- Install step --- btnWrite.addEventListener('click', async () => { if (!resultTgz || !device.directoryHandle) return; + btnWrite.disabled = true; + btnWrite.textContent = 'Writing...'; + downloadInstructions.hidden = true; + try { const koboDir = await device.directoryHandle.getDirectoryHandle('.kobo'); const fileHandle = await koboDir.getFileHandle('KoboRoot.tgz', { create: true }); const writable = await fileHandle.createWritable(); await writable.write(resultTgz); await writable.close(); - writeSuccess.hidden = false; + + btnWrite.textContent = 'Written'; + btnWrite.className = 'btn-success'; + writeInstructions.hidden = false; } catch (err) { + btnWrite.disabled = false; + btnWrite.textContent = 'Write to Kobo'; showError('Failed to write KoboRoot.tgz: ' + err.message); } }); @@ -376,6 +396,9 @@ a.download = 'KoboRoot.tgz'; a.click(); URL.revokeObjectURL(url); + + writeInstructions.hidden = true; + downloadInstructions.hidden = false; }); // --- Error / Retry --- @@ -398,7 +421,6 @@ manualMode = false; selectedPrefix = null; patchesLoaded = false; - btnWrite.hidden = false; btnDeviceNext.hidden = false; if (hasFileSystemAccess) { diff --git a/web/public/index.html b/web/public/index.html index 2288268..f410abc 100644 --- a/web/public/index.html +++ b/web/public/index.html @@ -4,7 +4,7 @@
Connect your Kobo e-reader via USB. It should appear as a removable drive.
Then click the button below and select the root of the Kobo drive.
@@ -38,6 +44,11 @@
Tip: if you use Chrome or Edge, this tool can auto-detect your device
and write patched files directly to it. Even easier, but sadly requires a Chromium based browser.
@@ -122,22 +133,31 @@
- Place the downloaded KoboRoot.tgz in the .kobo directory
- on your Kobo's USB drive, then safely eject and reboot the device.
-
- KoboRoot.tgz has been written to your Kobo.
- Safely eject the device and reboot it to apply the patches.
-
+ KoboRoot.tgz has been written to your Kobo.
+ Safely eject the device before unplugging the USB cable — it will reboot and apply the patches automatically.
+ Build log
+
+
+
+