From 42091343995538ae87971c82400565b9db5f5168 Mon Sep 17 00:00:00 2001 From: sudacode Date: Tue, 22 Sep 2026 00:20:54 -0700 Subject: [PATCH] feat(subtitles): optimize anime stream audio extraction - Prefer matching audio and lower-resolution sources with HLS sampling - Reuse verified audio within sessions and clean temporary files on shutdown - Allow character dictionary sync without loaded subtitles --- README.md | 9 + changes/anime-browser-disclaimer-docs.md | 4 + .../anime-stream-subtitle-generation-docs.md | 3 +- changes/anime-stream-subtitle-generation.md | 2 + ...acter-dictionary-without-subtitles-docs.md | 4 + .../character-dictionary-without-subtitles.md | 4 + docs-site/anime-browser.md | 8 +- docs-site/character-dictionary.md | 4 +- docs-site/subtitle-generation.md | 14 +- docs/architecture/README.md | 2 +- src/core/services/mpv-http-headers.ts | 12 + .../subtitle-generation-alternative.test.ts | 344 ++++++++++++++++++ .../subtitle-generation-alternative.ts | 262 +++++++++++++ .../subtitle-generation-audio-cache.test.ts | 49 +++ .../subtitle-generation-audio-cache.ts | 135 +++++++ .../services/subtitle-generation-audio.ts | 174 +++++++++ .../services/subtitle-generation-hls.test.ts | 230 ++++++++++++ src/core/services/subtitle-generation-hls.ts | 259 +++++++++++++ .../subtitle-generation-network.test.ts | 71 +++- .../services/subtitle-generation-probe.ts | 107 ++++++ .../subtitle-generation-session.test.ts | 44 +++ .../services/subtitle-generation-session.ts | 39 ++ .../services/subtitle-generation-source.ts | 15 + src/core/services/subtitle-generation.ts | 143 +------- src/main.ts | 25 +- .../anime-browser-application-runtime.ts | 9 +- .../runtime/anime-browser-playback.test.ts | 38 ++ src/main/runtime/anime-browser-playback.ts | 24 +- src/main/runtime/anime-browser-runtime.ts | 1 + .../anime-subtitle-generation-sources.test.ts | 34 ++ .../anime-subtitle-generation-sources.ts | 45 +++ .../character-dictionary-auto-sync.test.ts | 82 ++++- .../runtime/character-dictionary-auto-sync.ts | 5 +- .../subtitle-generation-runtime.test.ts | 110 ++++++ .../runtime/subtitle-generation-runtime.ts | 76 +++- 35 files changed, 2226 insertions(+), 161 deletions(-) create mode 100644 changes/anime-browser-disclaimer-docs.md create mode 100644 changes/character-dictionary-without-subtitles-docs.md create mode 100644 changes/character-dictionary-without-subtitles.md create mode 100644 src/core/services/subtitle-generation-alternative.test.ts create mode 100644 src/core/services/subtitle-generation-alternative.ts create mode 100644 src/core/services/subtitle-generation-audio-cache.test.ts create mode 100644 src/core/services/subtitle-generation-audio-cache.ts create mode 100644 src/core/services/subtitle-generation-audio.ts create mode 100644 src/core/services/subtitle-generation-hls.test.ts create mode 100644 src/core/services/subtitle-generation-hls.ts create mode 100644 src/core/services/subtitle-generation-probe.ts create mode 100644 src/core/services/subtitle-generation-session.test.ts create mode 100644 src/core/services/subtitle-generation-session.ts create mode 100644 src/main/runtime/anime-subtitle-generation-sources.test.ts create mode 100644 src/main/runtime/anime-subtitle-generation-sources.ts diff --git a/README.md b/README.md index 9d65c09b..0979f986 100644 --- a/README.md +++ b/README.md @@ -287,6 +287,15 @@ SubMiner builds on the work of these open-source projects: | [Yomitan](https://github.com/yomidevs/yomitan) | Dictionary engine powering all lookups and the morphological parser | | [yomitan-jlpt-vocab](https://github.com/stephenmk/yomitan-jlpt-vocab) | JLPT level tags for vocabulary | +## Disclaimer + +SubMiner is a media player and language-learning tool. The project does not +host, supply, or link to anime, video streams, or subtitle libraries. The anime +browser runs Aniyomi extensions that you install yourself from repositories you +choose; SubMiner bundles none and recommends none. The SubMiner developers are +not affiliated with any content provider and have no control over what those +sources offer, whether they stay available, or the quality of what they serve. + ## License [GNU General Public License v3.0](LICENSE) diff --git a/changes/anime-browser-disclaimer-docs.md b/changes/anime-browser-disclaimer-docs.md new file mode 100644 index 00000000..8c849acd --- /dev/null +++ b/changes/anime-browser-disclaimer-docs.md @@ -0,0 +1,4 @@ +type: docs +area: anime + +- Added a README disclaimer stating that SubMiner hosts no content, ships no anime sources or repositories, is not affiliated with any content provider, and that users are responsible for the content they access. The anime browser docs no longer describe SubMiner as a "host" of extensions. diff --git a/changes/anime-stream-subtitle-generation-docs.md b/changes/anime-stream-subtitle-generation-docs.md index aab688a1..3b678ecc 100644 --- a/changes/anime-stream-subtitle-generation-docs.md +++ b/changes/anime-stream-subtitle-generation-docs.md @@ -1,4 +1,5 @@ type: docs area: subtitles -- Document anime stream generation, cache locations, full-episode processing, supported audio tracks, and stream access limitations. +- Document anime stream generation, audio-only and lower-resolution extraction candidates, concurrent HLS downloads, temporary disk usage, audio cache reuse and limits, full-episode processing, supported audio tracks, and stream access limitations. +- Explain HLS source-check diagnostics and session-only audio cleanup on quit and after crashes. diff --git a/changes/anime-stream-subtitle-generation.md b/changes/anime-stream-subtitle-generation.md index 97060150..ef7122d0 100644 --- a/changes/anime-stream-subtitle-generation.md +++ b/changes/anime-stream-subtitle-generation.md @@ -2,3 +2,5 @@ type: added area: subtitles - Generate Japanese subtitles from finite HTTP/HTTPS anime episode streams in the existing generation modal. Reuse mpv's supported request headers and the anime proxy, transcribe downloaded audio locally, retain generated SRT files in the application cache, and load them only into the matching stream. Local-file generation and the launcher keep their existing behavior. +- Prepare plain HLS episodes with up to four concurrent segment downloads, preserving audio order and timing. Show download progress, cancel active requests together, and retain FFmpeg extraction for complex playlists. +- Reduce anime-stream extraction downloads by preferring separate Japanese audio or lower-resolution video when duration and sampled audio match playback. Sample HLS through short local segment windows, account for timestamp origins, retry empty original samples, and report why candidates are rejected. Selected external HTTP audio tracks are extracted directly with their playback delay preserved. Reuse verified completed audio across transcription retries and model changes within the current app session. Remove downloaded audio and working files on quit, recover abandoned sessions on startup, and preserve saved subtitles. diff --git a/changes/character-dictionary-without-subtitles-docs.md b/changes/character-dictionary-without-subtitles-docs.md new file mode 100644 index 00000000..08c903c8 --- /dev/null +++ b/changes/character-dictionary-without-subtitles-docs.md @@ -0,0 +1,4 @@ +type: docs +area: subtitles + +- Clarify that character dictionary sync works without a subtitle track and explain readiness and import timeouts. diff --git a/changes/character-dictionary-without-subtitles.md b/changes/character-dictionary-without-subtitles.md new file mode 100644 index 00000000..99bd0cc4 --- /dev/null +++ b/changes/character-dictionary-without-subtitles.md @@ -0,0 +1,4 @@ +type: fixed +area: subtitles + +- Let character dictionaries finish syncing when no Japanese subtitles are loaded. Wait for Yomitan extension readiness instead of the first processed subtitle, and report readiness failures instead of leaving the notification stuck on Checking. diff --git a/docs-site/anime-browser.md b/docs-site/anime-browser.md index ea2605b5..c9af5ff9 100644 --- a/docs-site/anime-browser.md +++ b/docs-site/anime-browser.md @@ -43,14 +43,16 @@ extension APK → bridge (JVM) → { url, headers } → mpv → SubMiner ``` Because the extension resolves the stream, whichever sources you install decide -what is available. SubMiner only hosts them. +what is available. SubMiner runs the installed extensions locally and nothing +more. ## Installing extensions **SubMiner ships no extension repositories and bundles no sources.** There is no default repository, no suggested list, and no discovery. Until you add one, the -browser has nothing to search — that is deliberate, and it is what keeps SubMiner -a neutral host rather than a distributor. +browser has nothing to search — that is deliberate. Every repository and +extension comes from you, and SubMiner is not affiliated with any of the sites +they connect to. There are two ways to add extensions. diff --git a/docs-site/character-dictionary.md b/docs-site/character-dictionary.md index 55b01bf0..415552a8 100644 --- a/docs-site/character-dictionary.md +++ b/docs-site/character-dictionary.md @@ -35,6 +35,8 @@ Character dictionary sync is disabled by default. To turn it on: ::: tip The first sync for a media title takes a few seconds while character data and portraits are fetched from AniList. Subsequent launches reuse the cached media match and snapshot without a fresh AniList lookup. + +Dictionary sync does not require a loaded Japanese subtitle track. Once Yomitan is ready, SubMiner can reuse an installed character dictionary even before the first subtitle is processed. If Yomitan readiness times out, the status reports a failure instead of staying on **Checking**. ::: ::: info @@ -168,7 +170,7 @@ These phases are emitted through the configured notification surface. Some phase 2. **generating** - No cache hit: fetch characters from AniList GraphQL, download portraits (250ms throttle between image requests), save snapshot JSON. 3. MRU update (no notification) - add the media ID to the most-recently-used list and evict old entries beyond `maxLoaded`. 4. **building** - Merge active snapshots into a single Yomitan ZIP. A SHA-1 revision hash is computed from the media set - if it matches the previously imported revision, the import is skipped. -5. **importing** - Push the ZIP into Yomitan. Waits for Yomitan mutation readiness (7-second timeout per operation). +5. **importing** - Push the ZIP into Yomitan when the installed revision differs. Dictionary checks and settings updates wait for the extension to be ready, independently of subtitle processing. Readiness and quick operations have bounded timeouts; imports have a separate budget that grows with the ZIP size. 6. **ready** - Dictionary is live. Character names will match on the next subtitle line. **State tracking** is persisted in `character-dictionaries/auto-sync-state.json`. AniList media matches are cached separately in `character-dictionaries/anilist-resolution-cache.json` so snapshot hits do not need another AniList search. diff --git a/docs-site/subtitle-generation.md b/docs-site/subtitle-generation.md index fbcc1adc..5108d868 100644 --- a/docs-site/subtitle-generation.md +++ b/docs-site/subtitle-generation.md @@ -65,11 +65,19 @@ SubMiner saves `