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:
sudacode committed 2026-07-31 17:21:12 -07:00
1 parent b204d4dd6e
commit e64ff1a0ee
117 files changed
+7565 -529

No files matched your search

@@ -0,0 +1,72 @@
import assert from 'node:assert/strict';
import test, { beforeEach } from 'node:test';
import {
isDockIconRetained,
releaseDockIcon,
resetDockIconRetentionForTests,
retainDockIcon,
} from './dock-icon-visibility';
function createDockRecorder() {
const calls: string[] = [];
return {
calls,
dock: {
show: () => {
calls.push('show');
},
hide: () => {
calls.push('hide');
},
},
};
}
beforeEach(() => {
resetDockIconRetentionForTests();
});
test('retainDockIcon shows the dock once and marks retention on darwin', () => {
const recorder = createDockRecorder();
retainDockIcon({ dock: recorder.dock, platform: 'darwin' });
retainDockIcon({ dock: recorder.dock, platform: 'darwin' });
assert.deepEqual(recorder.calls, ['show']);
assert.equal(isDockIconRetained(), true);
});
test('releaseDockIcon rehides only when the last retainer releases and overlay still needs it', () => {
const recorder = createDockRecorder();
retainDockIcon({ dock: recorder.dock, platform: 'darwin' });
retainDockIcon({ dock: recorder.dock, platform: 'darwin' });
releaseDockIcon({ dock: recorder.dock, platform: 'darwin', shouldRehide: () => true });
assert.deepEqual(recorder.calls, ['show']);
assert.equal(isDockIconRetained(), true);
releaseDockIcon({ dock: recorder.dock, platform: 'darwin', shouldRehide: () => true });
assert.deepEqual(recorder.calls, ['show', 'hide']);
assert.equal(isDockIconRetained(), false);
});
test('releaseDockIcon leaves the dock visible when no overlay needs the accessory transform', () => {
const recorder = createDockRecorder();
retainDockIcon({ dock: recorder.dock, platform: 'darwin' });
releaseDockIcon({ dock: recorder.dock, platform: 'darwin', shouldRehide: () => false });
assert.deepEqual(recorder.calls, ['show']);
assert.equal(isDockIconRetained(), false);
});
test('release without retain and non-darwin platforms are no-ops', () => {
const recorder = createDockRecorder();
releaseDockIcon({ dock: recorder.dock, platform: 'darwin', shouldRehide: () => true });
retainDockIcon({ dock: recorder.dock, platform: 'linux' });
releaseDockIcon({ dock: recorder.dock, platform: 'win32', shouldRehide: () => true });
assert.deepEqual(recorder.calls, []);
assert.equal(isDockIconRetained(), false);
});