From 516fadd530aa557db4ee80151f05fc6713581b59 Mon Sep 17 00:00:00 2001 From: sudacode Date: Wed, 2 Sep 2026 23:04:39 -0700 Subject: [PATCH] feat(anime): auto-open Jimaku for Anime Browser playback - Add hot-reloadable `anime.autoOpenJimaku` setting - Pause and resume playback around subtitle selection - Brand Anime Browser surfaces with the SubMiner logo --- changes/anime-browser.md | 3 +- config.example.jsonc | 3 +- docs-site/anime-browser.md | 7 ++ docs-site/configuration.md | 2 + docs-site/public/config.example.jsonc | 3 +- scripts/prepare-build-assets.mjs | 2 + scripts/prepare-build-assets.test.ts | 4 + src/animeui/index.html | 7 +- src/animeui/style.css | 35 +++++- src/config/config.test.ts | 1 + .../definitions/defaults-integrations.ts | 1 + .../definitions/options-integrations.ts | 7 ++ src/config/definitions/template-sections.ts | 4 +- src/config/resolve/integrations.test.ts | 29 +++++ src/config/resolve/integrations.ts | 12 +++ src/config/settings/registry.test.ts | 15 +++ src/config/settings/registry.ts | 6 ++ src/core/services/anki-jimaku.test.ts | 6 ++ src/core/services/anki-jimaku.ts | 2 + src/core/services/config-hot-reload.test.ts | 23 ++++ src/core/services/config-hot-reload.ts | 1 + src/main.ts | 41 ++++++- src/main/dependencies.ts | 4 + .../anime-browser-jimaku-auto-open.test.ts | 101 ++++++++++++++++++ .../runtime/anime-browser-jimaku-auto-open.ts | 89 +++++++++++++++ src/types/config.ts | 1 + src/types/integrations.ts | 5 + 27 files changed, 403 insertions(+), 11 deletions(-) create mode 100644 src/main/runtime/anime-browser-jimaku-auto-open.test.ts create mode 100644 src/main/runtime/anime-browser-jimaku-auto-open.ts diff --git a/changes/anime-browser.md b/changes/anime-browser.md index 4a22795c..9554dcfb 100644 --- a/changes/anime-browser.md +++ b/changes/anime-browser.md @@ -11,6 +11,7 @@ area: anime - The source picker offers "All sources", which searches every installed source at once. Results stream in as each source answers, with per-source progress in the status bar. Results are tagged with their source, failures do not blank the grid, and **Load more** appends later pages without duplicating streamed entries. - The Extensions tab opens with an Installed section listing every extension on disk with Remove, including ones added by hand or whose repository has since been removed. It compares APK and repository version codes, enables Update only for newer builds, marks current extensions as Up to date, and offers Update all when multiple updates are waiting. - Added `anime.repos`, `anime.extensionsDir`, and `anime.preferredQuality` config keys. SubMiner ships no extension repositories and performs no discovery. +- The settings app now groups Anime Browser config under an **Aniyomi** section in Integrations. A new `anime.autoOpenJimaku` option pauses newly loaded Anime Browser episodes, closes the in-player browser, opens Jimaku with the episode details filled in, and resumes after a subtitle loads or the modal closes without overriding playback that was already paused. - Anime playback targets Japanese audio: dub-labelled entries are skipped when the source offers an alternative, `alang` prefers Japanese, and the source's own audio and subtitle tracks are loaded into mpv (Japanese selected) instead of being discarded, so all of them can be switched from mpv's track menu. - The primary subtitle slot stays reserved for Japanese: a source that only has, say, English subtitles gets them added with a normalized language tag (`English` → `en`) but not selected, so the regular `secondarySub` auto-load can route them to the secondary slot instead. - HLS streams pass through a local strip proxy that removes fake image headers some hosts glue onto their video segments and gives disguised segment URLs (`.image`, `.jpg`, `.css`, and other rotating fake extensions) a media-safe local alias, so those streams play in mpv and support Anki audio and image extraction with current ffmpeg releases. Upstream responses use identity encoding so playlists remain readable for URL rewriting. @@ -28,6 +29,6 @@ area: anime - Right-clicking an episode opens a menu for marking it watched or unwatched by hand, plus "Mark this and N below watched/unwatched" for the episode and every episode listed under it. Sources list newest first, so a span covers the back catalogue, which is how a series watched elsewhere gets caught up. A filter never narrows what a span covers, and the status bar reports how many episodes were touched. - Marking an episode that was never played creates its stats row, carrying the same series, season and episode fields playback would have recorded. Both stats library views join the lifetime tables, so a manual mark does not show up there as watch time nobody spent, and clearing a mark creates nothing. - Episodes can be queued instead of replacing what is playing. Every episode row has **Play** and **Queue** buttons (clicking the row still plays now), the right-click menu offers the same two, and a queued episode shows its place in line ("next up", "#2 in queue") with a queue count and **Clear queue** in the episode header. The queue spans anime, resolves and appends each episode to mpv's real playlist as soon as it is queued while subtitle tracks cache in the background, so next/previous navigation works immediately and the next episode starts without a resolution pause when the current one ends. Queueing with nothing playing just plays. -- Added an in-player Anime Browser modal on `Ctrl+Alt+A`. The shortcut toggles it without losing its page or scroll position. It stays within the player bounds and shares the active episode, playback queue, source configuration, and watch history with the standalone browser, while each surface keeps independent search and navigation state. The modal validates its embedded page before changing overlay state, so a load setup failure leaves it closed rather than revealing a broken modal. +- Added an in-player Anime Browser modal on `Ctrl+Alt+A`. The shortcut toggles it without losing its page or scroll position. It stays within the player bounds and shares the active episode, playback queue, source configuration, and watch history with the standalone browser, while each surface keeps independent search and navigation state. The modal validates its embedded page before changing overlay state, so a load setup failure leaves it closed rather than revealing a broken modal. The SubMiner logo identifies the Anime Browser in both the modal and standalone window. - The bridge is reused from a package-manager install when one exists: on Arch the AUR `mangatan-extension-server` package (shared with Mangatan) is picked up from `/usr/share/mangatan/extension_server`, so nothing is downloaded and pacman keeps it current. `anime.bridgeDir` points SubMiner at a bundle anywhere else. `subminer-bin` lists the package as an optional dependency. - SubMiner records which bridge release it installed and, once the bridge is running, checks GitHub for a newer one; when there is, the banner offers an **Update to vX** button. The new release is downloaded beside the running bridge, then the bridge restarts on it. The updater waits for a bridge still starting to stop and keeps the previous bundle until the replacement is active. The Extensions tab shows the bridge version, where it lives, and who updates it without describing an unchecked install as current. diff --git a/config.example.jsonc b/config.example.jsonc index 86aa51b6..cf408b98 100644 --- a/config.example.jsonc +++ b/config.example.jsonc @@ -626,9 +626,10 @@ // Anime Browser // Anime browser sources. SubMiner ships no extension repositories and bundles no sources; // add a repository index URL here (or drop .apk files in the extensions directory) to have any. - // Hot-reload: anime changes apply the next time the anime browser opens. + // Hot-reload: autoOpenJimaku applies to the next episode; other anime changes apply the next time the anime browser opens. // ========================================== "anime": { + "autoOpenJimaku": false, // Pause Anime Browser playback and open Jimaku when an episode loads. Playback resumes after a subtitle loads or the modal closes. Values: true | false "extensionsDir": "", // Directory holding Aniyomi extension .apk files. Empty uses /anime-extensions. "repos": [], // Extension repository index URLs (any https .json index, e.g. https://.../index.min.json). Empty by default; SubMiner ships no repositories. "preferredQuality": "", // Preferred stream quality label, matched as a substring (for example: 1080). Empty uses the source order. diff --git a/docs-site/anime-browser.md b/docs-site/anime-browser.md index 2fc614bd..9e9433b7 100644 --- a/docs-site/anime-browser.md +++ b/docs-site/anime-browser.md @@ -202,11 +202,18 @@ there is nowhere to write them and the status bar says so. | Key | Purpose | | ------------------------ | ----------------------------------------------------------------------- | +| `anime.autoOpenJimaku` | Pause new episodes and open Jimaku for Japanese subtitles. | | `anime.repos` | Repository index URLs. Empty by default. | | `anime.extensionsDir` | Where APKs are read from. Empty uses `/anime-extensions`. | | `anime.preferredQuality` | Preferred stream label, matched as a substring (for example `1080`). | | `anime.bridgeDir` | A bridge bundle to run instead of the downloaded one. Empty by default. | +Enable `anime.autoOpenJimaku` to hand each newly loaded Anime Browser episode +to Jimaku. SubMiner pauses playback, closes the in-player browser if it is open, +and opens Jimaku with the source title, season, and episode already filled in. +Playback resumes after the selected subtitle loads. Closing Jimaku also releases +the automatic pause, while playback that was already paused stays paused. + ## Source settings Most extensions need configuration before they return anything — a server diff --git a/docs-site/configuration.md b/docs-site/configuration.md index d4176849..938b6f93 100644 --- a/docs-site/configuration.md +++ b/docs-site/configuration.md @@ -1165,6 +1165,7 @@ Sources for the [anime browser](/anime-browser). SubMiner ships no extension rep ```json { "anime": { + "autoOpenJimaku": false, "extensionsDir": "", "repos": [], "preferredQuality": "" @@ -1174,6 +1175,7 @@ Sources for the [anime browser](/anime-browser). SubMiner ships no extension rep | Option | Type | Default | Description | | ------------------------ | ---------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `anime.autoOpenJimaku` | `boolean` | `false` | Pause Anime Browser playback and open Jimaku when an episode loads. Playback resumes after a subtitle loads or the modal closes. Playback that was already paused stays paused. | | `anime.extensionsDir` | `string` | `""` | Directory holding Aniyomi extension `.apk` files. Empty uses `/anime-extensions`. | | `anime.repos` | `string[]` | `[]` | Extension repository index URLs. Any `https` URL ending in `.json` works; `index.min.json` is only the common name. | | `anime.preferredQuality` | `string` | `""` | Preferred stream quality label, matched as a substring (for example `1080`). Empty keeps the source's own order. A Japanese-audio entry always outranks a higher-quality dub. | diff --git a/docs-site/public/config.example.jsonc b/docs-site/public/config.example.jsonc index 86aa51b6..cf408b98 100644 --- a/docs-site/public/config.example.jsonc +++ b/docs-site/public/config.example.jsonc @@ -626,9 +626,10 @@ // Anime Browser // Anime browser sources. SubMiner ships no extension repositories and bundles no sources; // add a repository index URL here (or drop .apk files in the extensions directory) to have any. - // Hot-reload: anime changes apply the next time the anime browser opens. + // Hot-reload: autoOpenJimaku applies to the next episode; other anime changes apply the next time the anime browser opens. // ========================================== "anime": { + "autoOpenJimaku": false, // Pause Anime Browser playback and open Jimaku when an episode loads. Playback resumes after a subtitle loads or the modal closes. Values: true | false "extensionsDir": "", // Directory holding Aniyomi extension .apk files. Empty uses /anime-extensions. "repos": [], // Extension repository index URLs (any https .json index, e.g. https://.../index.min.json). Empty by default; SubMiner ships no repositories. "preferredQuality": "", // Preferred stream quality label, matched as a substring (for example: 1080). Empty uses the source order. diff --git a/scripts/prepare-build-assets.mjs b/scripts/prepare-build-assets.mjs index 328089ab..721808e5 100644 --- a/scripts/prepare-build-assets.mjs +++ b/scripts/prepare-build-assets.mjs @@ -6,6 +6,7 @@ import { fileURLToPath } from 'node:url'; const scriptDir = path.dirname(fileURLToPath(import.meta.url)); const repoRoot = path.resolve(scriptDir, '..'); +const assetsSourceDir = path.join(repoRoot, 'assets'); const rendererSourceDir = path.join(repoRoot, 'src', 'renderer'); const rendererOutputDir = path.join(repoRoot, 'dist', 'renderer'); const settingsSourceDir = path.join(repoRoot, 'src', 'settings'); @@ -58,6 +59,7 @@ function copyAnimeUiAssets() { 'detail.css', 'panels.css', ]); + copyFile(path.join(assetsSourceDir, 'SubMiner.png'), path.join(animeUiOutputDir, 'SubMiner.png')); } function fallbackToMacosSource() { diff --git a/scripts/prepare-build-assets.test.ts b/scripts/prepare-build-assets.test.ts index f1a48560..350f622c 100644 --- a/scripts/prepare-build-assets.test.ts +++ b/scripts/prepare-build-assets.test.ts @@ -33,6 +33,10 @@ test('anime UI stylesheet files exist and are all staged', () => { source, /copyAssets\(animeUiSourceDir, animeUiOutputDir, 'animeui', \[\s*'style\.css',\s*'detail\.css',\s*'panels\.css',?\s*\]\)/, ); + assert.match( + source, + /copyFile\(\s*path\.join\(assetsSourceDir, 'SubMiner\.png'\),\s*path\.join\(animeUiOutputDir, 'SubMiner\.png'\),?\s*\)/, + ); }); // Regression guard for #213: an untargeted swiftc stamps the build machine's OS diff --git a/src/animeui/index.html b/src/animeui/index.html index d9832dfa..1b564cd4 100644 --- a/src/animeui/index.html +++ b/src/animeui/index.html @@ -14,8 +14,11 @@
-
SubMiner
-
Anime
+ +
+
SubMiner
+
Anime
+