1
0
Files
kobopatch-webui/web/public/index.html

453 lines
29 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>KoboPatch Web UI</title>
<meta name="description" content="A website that lets you customize your Kobo e-reader with NickelMenu or custom patches, directly via your browser.">
<link rel="icon" type="image/svg+xml" href="/favicon/favicon.svg">
<link rel="icon" type="image/png" sizes="96x96" href="/favicon/favicon-96x96.png">
<link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png">
<link rel="manifest" href="/favicon/site.webmanifest">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Google+Sans:ital,opsz,wght@0,17..18,400..700;1,17..18,400..700&display=swap" rel="stylesheet">
<!-- Inline critical styles so the hero + loader render before style.css arrives on slow connections -->
<style>
body { background: #f5f5f7; color: #111827; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif; margin: 0; }
main { max-width: 640px; margin: 0 auto; padding: 2rem 1.5rem 4rem; }
.hero { margin-bottom: 1.5rem; padding-bottom: 1rem; border-bottom: 1px solid #e5e7eb; }
h1 { font-size: 1.75rem; font-weight: 700; letter-spacing: -0.02em; margin: 0; }
.hero-accent { color: #00bedf; font-weight: 600; }
.beta-pill { font-size: 0.7rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; background: #00bedf; color: #fff; padding: 0.35rem 0.7rem; border-radius: 10px; vertical-align: middle; position: relative; top: -0.15rem; margin-left: 5px; }
.subtitle { color: #6b7280; font-size: 0.95rem; margin-top: 0.25rem; }
.initial-loader { display: flex; align-items: center; justify-content: center; gap: 0.75rem; padding: 2rem 0; }
.initial-loader p { margin: 0; font-size: 0.93rem; color: #6b7280; }
.spinner { width: 22px; height: 22px; border: 2.5px solid #e5e7eb; border-top-color: #00bedf; border-radius: 50%; animation: spin 0.7s linear infinite; flex-shrink: 0; }
@keyframes spin { to { transform: rotate(360deg); } }
[hidden] { display: none !important; }
</style>
<link rel="stylesheet" href="css/style.css?ts=1773916731">
<script src="js/jszip.min.js"></script>
</head>
<body>
<main>
<header class="hero">
<h1>KoboPatch <span class="hero-accent">Web UI</span> <span class="beta-pill">beta</span></h1>
<p class="subtitle">Customise your Kobo e-reader with NickelMenu or custom patches.</p>
</header>
<!-- Shown until JS initialises -->
<div id="initial-loader" class="initial-loader">
<div class="spinner"></div>
<p>Loading&hellip;</p>
</div>
<!-- Step indicator (populated dynamically by app.js) -->
<nav id="step-nav" class="step-nav" hidden>
<ol></ol>
</nav>
<!-- Step 1: Choose connection method -->
<section id="step-connect" class="step" hidden>
<div class="warning">
<b>Patching modifies system files on your Kobo, and <u>will void your warranty</u>.</b> This process allows for custom modifications to be applied, or undone. If something has gone wrong,
you may need to <a href="https://help.kobo.com/hc/en-us/articles/360017605314-Manual-reset-your-Kobo-Clara-HD-Kobo-Nia-Kobo-Elipsa-Kobo-Clara-2E-Kobo-Elipsa-2E" target="_blank">manually reset your device</a>.
</div>
<p>How would you like to set up your Kobo?</p>
<div class="mode-cards">
<button id="btn-connect" class="mode-card mode-card-btn">
<svg class="mode-card-icon" xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 16 16" fill="currentColor"><path d="m7.792.312-1.533 2.3A.25.25 0 0 0 6.467 3H7.5v7.319a2.5 2.5 0 0 0-.515-.298L5.909 9.56A1.5 1.5 0 0 1 5 8.18v-.266a1.5 1.5 0 1 0-1 0v.266a2.5 2.5 0 0 0 1.515 2.298l1.076.461a1.5 1.5 0 0 1 .888 1.129 2.001 2.001 0 1 0 1.021-.006v-.902a1.5 1.5 0 0 1 .756-1.303l1.484-.848A2.5 2.5 0 0 0 11.995 7h.755a.25.25 0 0 0 .25-.25v-2.5a.25.25 0 0 0-.25-.25h-2.5a.25.25 0 0 0-.25.25v2.5c0 .138.112.25.25.25h.741a1.5 1.5 0 0 1-.747 1.142L8.76 8.99a2.584 2.584 0 0 0-.26.17V3h1.033a.25.25 0 0 0 .208-.389L8.208.312a.25.25 0 0 0-.416 0Z"/></svg>
<div class="mode-card-body">
<div class="mode-card-title">
Connect my Kobo
<span class="recommended-pill">recommended</span>
</div>
<div class="mode-card-desc">Connect your Kobo via USB and select its drive. You will have the option to apply these changes directly, or you can download a ZIP.</div>
</div>
</button>
<button id="btn-manual" class="mode-card mode-card-btn">
<svg class="mode-card-icon" xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
<div class="mode-card-body">
<div class="mode-card-title">
Build downloadable archive
</div>
<div class="mode-card-desc">You may need to identify your device based on model number. Go through the wizard, download the files and copy them to your Kobo yourself. Works in any browser, but a bit more complicated. Recommended for tinkerers.</div>
</div>
</button>
</div>
<p id="connect-unsupported-hint" class="fallback-hint" hidden>
<b>Note:</b> Your browser does not support direct device access via the <a href="https://caniuse.com/native-filesystem-api">native filesystem API</a>, which is required for a seamless patching experience. Directly connecting to your Kobo is not available because of this. Use Chrome, Edge or Opera to connect your Kobo directly, or choose the manual download option.
</p>
</section>
<!-- Step 1b (manual): Select device model + firmware for custom patches -->
<section id="step-manual-version" class="step" hidden>
<p class="fallback-hint">
<strong>Select the version number currently installed on your device.</strong> If it does not appear in this list, your software version is not supported for custom patching. You can go back and choose NickelMenu instead, which works with all versions.
</p>
<select id="manual-version">
<option value="">-- Select software version --</option>
</select>
<p id="manual-version-hint" class="fallback-hint">
You can find the version number on your Kobo under <strong>More &gt; Settings &gt; Device information</strong> &gt; <strong>Software version</strong>.
</p>
<select id="manual-model" hidden>
<option value="">-- Select your Kobo model --</option>
</select>
<p id="manual-model-hint" class="fallback-hint" hidden>
Match the first characters of your serial number (e.g. N428) to the list above. You can find it under <strong>More &gt; Settings &gt; Device information</strong>.
</p>
<div class="step-actions" style="margin-top: 25px">
<button id="btn-manual-version-back" class="secondary">&#x2039; Back</button>
<button id="btn-manual-confirm" class="primary" disabled>Continue &#x203A;</button>
</div>
</section>
<!-- Step 1c: Device detected (auto mode info card) -->
<section id="step-device" class="step" hidden>
<div id="device-info" class="info-card">
<div class="info-row">
<span class="label">Model</span>
<span id="device-model" class="value">--</span>
</div>
<div class="info-row">
<span class="label">Serial</span>
<span id="device-serial" class="value">--</span>
</div>
<div class="info-row">
<span class="label">Software</span>
<span id="device-firmware" class="value">--</span>
</div>
</div>
<p id="device-status"></p>
<p id="device-unknown-warning" class="warning" hidden>
You seem to have a Kobo device that isn't currently being detected. While you can continue since a supported software version seems to be installed, please
<a href="https://github.com/nicoverbruggen/kobopatch-webui/issues/new" target="_blank">file an issue on GitHub</a>
so the developer can add this device to the list.
</p>
<label id="device-unknown-ack" class="device-unknown-ack" hidden>
<input type="checkbox" id="device-unknown-checkbox">
<span>I understand that this model is likely not officially supported by NickelMenu yet, but I wish to continue regardless, and I understand it may not work correctly.</span>
</label>
<div class="step-actions">
<button id="btn-device-restore" class="secondary">Restore Software</button>
<button id="btn-device-next" class="primary">Continue &#x203A;</button>
</div>
</section>
<!-- Step 2: Mode selection -->
<section id="step-mode" class="step" hidden>
<p>What would you like to do?</p>
<div class="mode-cards">
<label class="mode-card mode-card-selected">
<input type="radio" name="mode" value="nickelmenu" checked>
<div class="mode-card-body">
<div class="mode-card-title">Install or remove NickelMenu <span class="recommended-pill">recommended</span></div>
<div class="mode-card-desc">Installs a custom menu and various tweaks for your device. Works with most Kobo devices. The safest solution, as it has a lot of error checking and a failsafe mechanism which will automatically uninstall it as a last resort. </div>
</div>
</label>
<label class="mode-card">
<input type="radio" name="mode" value="patches">
<div class="mode-card-body">
<div class="mode-card-title">Custom Patches</div>
<div class="mode-card-desc">Apply community patches to your Kobo's system software. Requires a supported software version and supported device.</div>
</div>
</label>
</div>
<p id="mode-patches-hint" class="fallback-hint" hidden>Custom patches are not available for your software version. You can still install NickelMenu and choose what you want to do with your Kobo.</p>
<div class="step-actions">
<button id="btn-mode-back" class="secondary">&#x2039; Back</button>
<button id="btn-mode-next" class="primary">Continue &#x203A;</button>
</div>
</section>
<!-- Step 2b: NickelMenu configuration -->
<section id="step-nickelmenu" class="step" hidden>
<p>Choose what to do with your Kobo.</p>
<div class="nm-options">
<label class="nm-option">
<input type="radio" name="nm-option" value="sample">
<div class="nm-option-body">
<div class="nm-option-title">Install NickelMenu with preset</div>
<div class="nm-option-desc">Installs NickelMenu with a curated set of menu options. You get to decide which optional features you'd like to enable.</div>
</div>
</label>
<div id="nm-config-options" class="nm-config-options" hidden>
<label class="nm-config-item">
<input type="checkbox" name="nm-cfg-menu" checked disabled>
<div class="nm-config-text">
<span>Set up custom menu (required)</span>
<span class="nm-config-desc">Adds menu items for dark mode, screenshots, and more. A new tab will be added in the bottom navigation that is labelled "Tweak".</span>
</div>
</label>
<label class="nm-config-item">
<input type="checkbox" name="nm-cfg-fonts" checked>
<div class="nm-config-text">
<span>Install Readerly fonts (recommended)</span>
<span class="nm-config-desc">Adds the Readerly font family. These fonts are optically similar to Bookerly. When you are reading a book, you will be able to select this font from the dropdown as "KF Readerly".</span>
</div>
</label>
<label class="nm-config-item">
<input type="checkbox" name="nm-cfg-screensaver">
<div class="nm-config-text">
<span>Copy screensaver (optional)</span>
<span class="nm-config-desc">Replaces the default sleep screen with a custom screensaver image. You can always add your own in the <code>/.kobo/screensaver</code> folder.</span>
</div>
</label>
<label class="nm-config-item">
<input type="checkbox" name="nm-cfg-simplify-tabs">
<div class="nm-config-text">
<span>Hide certain navigation tabs (minimalist)</span>
<span class="nm-config-desc">This will hide the Notebook and Discover tabs from the bottom navigation. For minimalists who want fewer distractions.</span>
</div>
</label>
<label class="nm-config-item">
<input type="checkbox" name="nm-cfg-simplify-home">
<div class="nm-config-text">
<span>Hide certain home screen elements (minimalist)</span>
<span class="nm-config-desc">If you are reading only one book, no recommendations will appear next to your current read, and third row on your homescreen with advertisements for Kobo Plus and the Kobo Store will be hidden. For minimalists who want fewer distractions.</span>
</div>
</label>
<a href="https://github.com/nicoverbruggen/kobo-config" target="_blank" class="nm-config-link">Learn more about these customisations &#x203A;</a>
</div>
<label class="nm-option">
<input type="radio" name="nm-option" value="nickelmenu-only">
<div class="nm-option-body">
<div class="nm-option-title">Install NickelMenu only</div>
<div class="nm-option-desc">Installs just NickelMenu without any configuration. You can set it up yourself later.</div>
</div>
</label>
<label id="nm-option-remove" class="nm-option nm-option-disabled nm-option-remove">
<input type="radio" name="nm-option" value="remove" disabled>
<div class="nm-option-body">
<div class="nm-option-title">Remove NickelMenu</div>
<div class="nm-option-desc" id="nm-remove-desc">Removes NickelMenu from your device. (Only available when a Kobo with NickelMenu installed is connected.)</div>
</div>
</label>
</div>
<div class="step-actions">
<button id="btn-nm-back" class="secondary">&#x2039; Back</button>
<button id="btn-nm-next" class="primary">Continue &#x203A;</button>
</div>
</section>
<!-- Step 2c: NickelMenu review -->
<section id="step-nm-review" class="step" hidden>
<p id="nm-review-summary"></p>
<ul id="nm-review-list" class="selected-patches-list"></ul>
<p>Before continuing, make sure you these are the changes you want. You can always use the wizard again to uninstall NickelMenu, if you want to.</p>
<div id="nm-review-actions" class="step-actions">
<button id="btn-nm-review-back" class="secondary">&#x2039; Back</button>
<div class="step-actions-right">
<button id="btn-nm-download" class="secondary">Download ZIP</button>
<button id="btn-nm-write" class="primary">Write to Kobo</button>
</div>
</div>
</section>
<!-- NickelMenu installing -->
<section id="step-nm-installing" class="step" hidden>
<div class="build-header">
<div class="spinner"></div>
<p id="nm-progress">Starting...</p>
</div>
</section>
<!-- NickelMenu done -->
<section id="step-nm-done" class="step" hidden>
<p id="nm-done-status" class="install-summary"></p>
<div id="nm-write-instructions" class="install-instructions" hidden>
<p class="hint">
Files have been written to your Kobo.
<strong>Safely eject</strong> the device before unplugging the USB cable &mdash; it will reboot and install NickelMenu automatically.
</p>
</div>
<div id="nm-download-instructions" class="install-instructions" hidden>
<ol class="install-steps">
<li>Connect your Kobo via USB so it appears as a removable drive.</li>
<li>Extract the downloaded ZIP to the <strong>root</strong> of the Kobo drive, preserving the folder structure.</li>
<li id="nm-download-conf-step" hidden>
Open <strong>.kobo/Kobo/Kobo eReader.conf</strong> in a text editor.<br>
Find the <code>[FeatureSettings]</code> section (or add it at the end) and add the following line:<br>
<code>ExcludeSyncFolders=(calibre|\.(?!kobo|adobe|calibre).+|([^.][^/]*/)+\..+)</code><br>
This prevents the Kobo from discovering books in these folders during a sync.</li>
<li><strong>Safely eject</strong> the Kobo &mdash; do not just unplug the cable.</li>
<li>The device will reboot and install NickelMenu automatically.</li>
</ol>
</div>
<div id="nm-reboot-instructions" class="install-instructions" hidden>
<p class="hint">
<strong>Safely eject</strong> your Kobo and let it reboot. NickelMenu will be automatically removed during the reboot.
</p>
</div>
</section>
<!-- Step 2 (patches path): Configure patches -->
<section id="step-patches" class="step" hidden>
<p>Enable or disable patches below. Patches in the same group are mutually exclusive.</p>
<div id="patch-container" class="patch-container-scroll"></div>
<div class="step-actions">
<button id="btn-patches-back" class="secondary">&#x2039; Back</button>
<button id="btn-patches-next" class="primary" disabled>Continue &#x203A;</button>
</div>
<p id="patch-count-hint" class="fallback-hint"></p>
</section>
<!-- Step 3: Review & Build -->
<section id="step-firmware" class="step" hidden>
<p id="firmware-auto-info">
Software update <strong id="firmware-version-label"></strong> for
<strong id="firmware-device-label"></strong>
<span id="firmware-description">will be downloaded automatically from Kobo's servers and will be patched after the download completes.</span>
</p>
<p id="selected-patches-heading" hidden>The following patches will be applied:</p>
<ul id="selected-patches-list" class="selected-patches-list"></ul>
<details class="log-details">
<summary>Software download URL</summary>
<code id="firmware-download-url"></code>
<p id="firmware-verify-notice" class="fallback-hint">
You can verify if this URL matches your Kobo's model on
<a href="https://help.kobo.com/hc/en-us/articles/35059171032727" target="_blank">Kobo's support page</a>. The most important bit is that "koboXX" matches, for example "kobo13" for Kobo Libra Color.
</p>
</details>
<div class="step-actions">
<button id="btn-build-back" class="secondary">&#x2039; Back</button>
<button id="btn-build" class="primary">Build Patched Software</button>
</div>
</section>
<!-- Step 4: Building -->
<section id="step-building" class="step" hidden>
<div class="build-header">
<div class="spinner"></div>
<p id="build-progress">Starting...</p>
</div>
<pre id="build-log" class="build-log"></pre>
<p id="build-wait-hint" class="fallback-hint">Please wait while the patch is being applied...</p>
</section>
<!-- Step 5: Install -->
<section id="step-done" class="step" hidden>
<p id="build-status" class="install-summary"></p>
<div id="existing-tgz-warning" class="warning" hidden>
An <b>existing</b> KoboRoot.tgz file was found on your Kobo. This means an update has not been applied yet. If you choose to write the new file to your Kobo, the existing one will be overwritten.
</div>
<details class="log-details">
<summary>Build log</summary>
<pre id="done-log" class="build-log done-log"></pre>
</details>
<div id="build-actions">
<button id="btn-write" class="primary">Write to Kobo</button>
<button id="btn-download" class="secondary">Download KoboRoot.tgz</button>
</div>
<div id="write-instructions" class="install-instructions" hidden>
<p class="hint">
KoboRoot.tgz has been written to your Kobo.
<strong>Safely eject</strong> the device before unplugging the USB cable — it will reboot and apply the patches automatically.
</p>
</div>
<div id="download-instructions" class="install-instructions" hidden>
<ol class="install-steps">
<li>Connect your <span id="download-device-name">Kobo</span> via USB so it appears as a removable drive.</li>
<li>Copy <strong>KoboRoot.tgz</strong> into the <strong>.kobo</strong> folder on the Kobo drive.</li>
<li><strong>Safely eject</strong> the Kobo — do not just unplug the cable, as this can corrupt data.</li>
<li>The device will reboot and apply the patches automatically.</li>
</ol>
</div>
</section>
<!-- Error state -->
<section id="step-error" class="step" hidden>
<h2>Something went wrong</h2>
<p id="error-message" class="error"></p>
<pre id="error-log" class="error-log" hidden></pre>
<button id="btn-retry" class="secondary">Start Over</button>
</section>
</main>
<footer class="site-footer">
<p>
<a href="#" id="btn-how-it-works">How does this work?</a><br/>
<br/>
Built on <a href="https://github.com/pgaskin/kobopatch" target="_blank">kobopatch</a> by pgaskin.
Patches and discussion on the <a href="https://www.mobileread.com/forums/forumdisplay.php?f=247" target="_blank">MobileRead forums</a>.
</p>
<p>
Source code available <a href="https://github.com/nicoverbruggen/kobopatch-webui" target="_blank">on GitHub</a>. This project is not affiliated with Rakuten Kobo Inc.
</p>
</footer>
<dialog id="how-it-works-dialog" class="modal">
<div class="modal-content">
<div class="modal-header">
<h2>How does this work?</h2>
<button id="btn-close-dialog" class="modal-close" aria-label="Close">&times;</button>
</div>
<div class="modal-body">
<p>
KoboPatch Web UI is a fully client-side web application for customising
Kobo e-readers. Nothing is uploaded to a server &mdash; everything runs in your browser.
</p>
<h3>NickelMenu</h3>
<p>
<a href="https://pgaskin.net/NickelMenu/" target="_blank">NickelMenu</a> adds custom menu items
and tweaks to your Kobo. This tool can install NickelMenu along with an optional curated
configuration (custom menus, fonts, screensavers) or remove it. NickelMenu works with
most Kobo devices and includes a failsafe that automatically uninstalls itself if
something goes wrong.
</p>
<h3>Custom patches</h3>
<ol>
<li><strong>Device selection</strong> &mdash; On Chromium-based browsers (Chrome, Edge), the app can
auto-detect your Kobo via the File System Access API when connected over USB.
On other browsers, you manually select your model and software version.</li>
<li><strong>Patch configuration</strong> &mdash; You choose which
<a href="https://github.com/pgaskin/kobopatch" target="_blank">kobopatch</a> patches
to enable or disable. Patches in the same group are mutually exclusive.
The patches themselves are community-contributed via the
<a href="https://www.mobileread.com/forums/forumdisplay.php?f=247" target="_blank">MobileRead forums</a>.</li>
<li><strong>Build</strong> &mdash; The correct software update is downloaded directly from Kobo's servers
(<code>ereaderfiles.kobo.com</code>). The patcher, compiled from Go to WebAssembly, runs
inside a Web Worker so the UI stays responsive. It extracts
<code>KoboRoot.tgz</code>, applies your selected patches as in-place byte replacements
to the ELF binaries, validates the results (ELF headers, file sizes, archive consistency),
and produces a new <code>KoboRoot.tgz</code>.</li>
<li><strong>Install</strong> &mdash; On Chromium, the patched file is written directly to the
<code>.kobo</code> folder on the device. On other browsers, you download the file
and copy it manually. After safely ejecting, the Kobo reboots and applies the update.</li>
</ol>
<h3>Restoring original software</h3>
<p>
You can also use this tool to restore the original unpatched software. In that case,
no patches are applied &mdash; the original <code>KoboRoot.tgz</code> is extracted
from the software update as-is.
</p>
<h3>Safety</h3>
<p>
NickelMenu includes a built-in failsafe mechanism. For custom patches, each patched binary
is validated before being included in the output: ELF magic bytes,
32-bit ARM architecture, file size (must match the original), and archive integrity are
all checked. If anything looks wrong, the build fails with an error. That said, both
NickelMenu and custom patches modify system files, so you should know how to
<a href="https://help.kobo.com/hc/en-us/articles/360017605314" target="_blank">manually reset your Kobo</a>
if needed.
</p>
</div>
</div>
</dialog>
<!-- wasm_exec.js loaded by patch-worker.js inside the Web Worker -->
<script src="js/kobo-device.js?ts=1773916731"></script>
<script src="js/kobopatch.js?ts=1773916731"></script>
<script src="js/patch-ui.js?ts=1773916731"></script>
<script src="js/nickelmenu.js?ts=1773916731"></script>
<script src="js/app.js?ts=1773916731"></script>
</body>
</html>