feat(anime): add anime browser powered by Aniyomi extensions

- Add `subminer anime` / `--anime` and a tray entry to open a browser that searches installed Aniyomi extension sources, shows cover art and episodes, and plays into mpv with overlay/mining attached
- Add an Extensions tab to add repos and install/update/remove sources, and per-source settings for sources needing config
- Support searching all sources at once with streaming, per-source results and status
- Prefer Japanese audio/subtitle tracks from the source and keep the primary subtitle slot reserved for Japanese
- Fix window/tray/Dock handling so the browser and mpv can be switched between without quitting the app or losing the Dock icon
- Add anime.repos, anime.extensionsDir, anime.preferredQuality config keys (no bundled repos or discovery)
This commit is contained in:
2026-07-31 17:16:49 -07:00
parent b204d4dd6e
commit e64ff1a0ee
117 changed files with 7565 additions and 529 deletions
+1
View File
@@ -327,6 +327,7 @@ const sidebar: DefaultTheme.SidebarItem[] = [
{ text: 'Anki', link: '/anki-integration' },
{ text: 'Jellyfin', link: '/jellyfin-integration' },
{ text: 'YouTube', link: '/youtube-integration' },
{ text: 'Anime Browser', link: '/anime-browser' },
{ text: 'Jimaku', link: '/jimaku-integration' },
{ text: 'TsukiHime', link: '/tsukihime-integration' },
{ text: 'AniList', link: '/anilist-integration' },
+6 -2
View File
@@ -45,7 +45,9 @@
border: 1px solid var(--vp-c-border);
border-radius: 0;
background: var(--vp-c-bg);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3), 0 24px 64px rgba(0, 0, 0, 0.2);
box-shadow:
0 8px 32px rgba(0, 0, 0, 0.3),
0 24px 64px rgba(0, 0, 0, 0.2);
overflow: hidden;
}
@@ -62,7 +64,9 @@
font-family: var(--tui-font-mono);
font-size: 12px;
cursor: pointer;
transition: border-color 180ms ease, color 180ms ease;
transition:
border-color 180ms ease,
color 180ms ease;
}
.mermaid-modal__close:hover {
@@ -10,7 +10,5 @@ test('status line file path formats version archive home without trailing slash'
});
test('status line file path keeps normal docs routes as markdown files', () => {
expect(formatStatusLineFilePath('/v/0.12.0/configuration')).toBe(
'v/0.12.0/configuration.md',
);
expect(formatStatusLineFilePath('/v/0.12.0/configuration')).toBe('v/0.12.0/configuration.md');
});
+59 -38
View File
@@ -22,17 +22,8 @@
:root {
--tui-font-mono: 'JetBrains Mono', 'Cascadia Code', 'Fira Code', monospace;
--tui-font-body:
'Manrope Default',
'M PLUS 1',
'Manrope',
'Noto Sans CJK JP',
'Noto Sans JP',
'Hiragino Kaku Gothic ProN',
'Meiryo',
'Yu Gothic',
'Hiragino Sans',
system-ui,
sans-serif;
'Manrope Default', 'M PLUS 1', 'Manrope', 'Noto Sans CJK JP', 'Noto Sans JP',
'Hiragino Kaku Gothic ProN', 'Meiryo', 'Yu Gothic', 'Hiragino Sans', system-ui, sans-serif;
--tui-transition: 180ms ease;
/* Theme-specific values — overridden in .dark below */
@@ -96,8 +87,11 @@ button,
.VPFeature,
.VPNavBarMenuLink,
.VPSidebarItem .text {
transition: color var(--tui-transition), background var(--tui-transition),
border-color var(--tui-transition), opacity var(--tui-transition);
transition:
color var(--tui-transition),
background var(--tui-transition),
border-color var(--tui-transition),
opacity var(--tui-transition);
}
/* === Nav bar === */
@@ -218,8 +212,7 @@ button,
background: var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
color: var(--vp-c-brand-1);
font-family: var(--tui-font-mono), 'M PLUS 1', 'Noto Sans CJK JP', 'Noto Sans JP',
monospace;
font-family: var(--tui-font-mono), 'M PLUS 1', 'Noto Sans CJK JP', 'Noto Sans JP', monospace;
font-variant-ligatures: none;
}
@@ -228,8 +221,7 @@ button,
border-radius: 0;
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-alt) !important;
font-family: var(--tui-font-mono), 'M PLUS 1', 'Noto Sans CJK JP', 'Noto Sans JP',
monospace;
font-family: var(--tui-font-mono), 'M PLUS 1', 'Noto Sans CJK JP', 'Noto Sans JP', monospace;
font-variant-ligatures: none;
}
@@ -273,7 +265,9 @@ button,
.vp-doc a {
text-decoration: none;
border-bottom: 1px solid var(--tui-link-underline);
transition: border-color var(--tui-transition), color var(--tui-transition);
transition:
border-color var(--tui-transition),
color var(--tui-transition);
}
.vp-doc a:hover {
@@ -312,20 +306,45 @@ button,
border-left-width: 1px;
}
.vp-doc .custom-block.tip { border-color: var(--vp-c-brand-1); }
.vp-doc .custom-block.tip::before { content: '-- tip'; color: var(--vp-c-brand-1); }
.vp-doc .custom-block.tip {
border-color: var(--vp-c-brand-1);
}
.vp-doc .custom-block.tip::before {
content: '-- tip';
color: var(--vp-c-brand-1);
}
.vp-doc .custom-block.info { border-color: var(--vp-c-brand-2); }
.vp-doc .custom-block.info::before { content: '-- info'; color: var(--vp-c-brand-2); }
.vp-doc .custom-block.info {
border-color: var(--vp-c-brand-2);
}
.vp-doc .custom-block.info::before {
content: '-- info';
color: var(--vp-c-brand-2);
}
.vp-doc .custom-block.warning { border-color: var(--vp-c-warning-1); }
.vp-doc .custom-block.warning::before { content: '-- warning'; color: var(--vp-c-warning-1); }
.vp-doc .custom-block.warning {
border-color: var(--vp-c-warning-1);
}
.vp-doc .custom-block.warning::before {
content: '-- warning';
color: var(--vp-c-warning-1);
}
.vp-doc .custom-block.danger { border-color: var(--vp-c-danger-1); }
.vp-doc .custom-block.danger::before { content: '-- danger'; color: var(--vp-c-danger-1); }
.vp-doc .custom-block.danger {
border-color: var(--vp-c-danger-1);
}
.vp-doc .custom-block.danger::before {
content: '-- danger';
color: var(--vp-c-danger-1);
}
.vp-doc .custom-block.details { border-color: var(--vp-c-divider); }
.vp-doc .custom-block.details::before { content: '-- details'; color: var(--vp-c-text-2); }
.vp-doc .custom-block.details {
border-color: var(--vp-c-divider);
}
.vp-doc .custom-block.details::before {
content: '-- details';
color: var(--vp-c-text-2);
}
.vp-doc .custom-block .custom-block-title {
font-family: var(--tui-font-mono);
@@ -413,11 +432,15 @@ button,
}
@keyframes tui-blink {
0%, 100% { opacity: 1; }
50% { opacity: 0; }
0%,
100% {
opacity: 1;
}
50% {
opacity: 0;
}
}
/* === Statusline === */
.tui-statusline {
position: fixed;
@@ -457,7 +480,7 @@ button,
margin-left: -12px;
}
.tui-statusline__mode[data-mode="HOME"] {
.tui-statusline__mode[data-mode='HOME'] {
background: var(--vp-c-brand-2);
}
@@ -561,7 +584,9 @@ body {
.VPFeatures .VPFeature {
border-radius: 8px !important;
border: 1px solid var(--vp-c-divider) !important;
transition: border-color var(--tui-transition), background var(--tui-transition),
transition:
border-color var(--tui-transition),
background var(--tui-transition),
transform var(--tui-transition);
position: relative;
overflow: hidden;
@@ -672,11 +697,7 @@ body {
transform: translateX(-50%);
width: 600px;
height: 400px;
background: radial-gradient(
ellipse at center,
var(--tui-hero-glow) 0%,
transparent 70%
);
background: radial-gradient(ellipse at center, var(--tui-hero-glow) 0%, transparent 70%);
pointer-events: none;
z-index: -1;
}