Files
SubMiner/src/anime-bridge/media-url.test.ts
T
sudacode e64ff1a0ee 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)
2026-07-31 17:21:12 -07:00

70 lines
2.4 KiB
TypeScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { parseAnimeStatus, resolveBridgeMediaUrl } from './media-url';
const BRIDGE = 'http://127.0.0.1:56037';
test('a loopback proxy url is rebased onto the live bridge port', () => {
assert.equal(
resolveBridgeMediaUrl(BRIDGE, 'http://127.0.0.1:8080/image/cover-uuid'),
'http://127.0.0.1:56037/image/cover-uuid',
);
assert.equal(
resolveBridgeMediaUrl(BRIDGE, 'http://localhost:8080/video/master-token'),
'http://127.0.0.1:56037/video/master-token',
);
});
test('query strings and fragments survive rebasing', () => {
assert.equal(
resolveBridgeMediaUrl(BRIDGE, 'http://127.0.0.1:8080/video/token?quality=1080#t=30'),
'http://127.0.0.1:56037/video/token?quality=1080#t=30',
);
});
test('ipv6 loopback is recognised', () => {
assert.equal(
resolveBridgeMediaUrl(BRIDGE, 'http://[::1]:8080/image/cover'),
'http://127.0.0.1:56037/image/cover',
);
});
test('remote urls are left untouched', () => {
const remote = 'https://cdn.example.com/covers/1.jpg';
assert.equal(resolveBridgeMediaUrl(BRIDGE, remote), remote);
});
test('loopback urls outside the proxy routes are left untouched', () => {
// Only /image and /video are proxy routes; /capabilities is the server's own API.
const other = 'http://127.0.0.1:8080/capabilities';
assert.equal(resolveBridgeMediaUrl(BRIDGE, other), other);
});
test('a base url without a scheme is assumed to be http', () => {
assert.equal(
resolveBridgeMediaUrl('127.0.0.1:56037', 'http://127.0.0.1:8080/image/cover'),
'http://127.0.0.1:56037/image/cover',
);
});
test('unparseable input is returned unchanged rather than throwing', () => {
assert.equal(resolveBridgeMediaUrl(BRIDGE, 'not a url'), 'not a url');
assert.equal(
resolveBridgeMediaUrl('', 'http://127.0.0.1:8080/image/c'),
'http://127.0.0.1:8080/image/c',
);
assert.equal(resolveBridgeMediaUrl(BRIDGE, ''), '');
});
test('parseAnimeStatus maps the SAnime constants', () => {
assert.equal(parseAnimeStatus(1), 'ongoing');
assert.equal(parseAnimeStatus(2), 'completed');
assert.equal(parseAnimeStatus(4), 'publishing-finished');
assert.equal(parseAnimeStatus(5), 'cancelled');
assert.equal(parseAnimeStatus(6), 'on-hiatus');
assert.equal(parseAnimeStatus(0), 'unknown');
assert.equal(parseAnimeStatus(undefined), 'unknown');
// 3 is unused in the SAnime constants.
assert.equal(parseAnimeStatus(3), 'unknown');
});