mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-08-16 01:55:51 -07:00
877f350353
- Toggle the player Anime Browser without losing its state - Share active playback state and support rotating fake segment extensions
125 lines
4.3 KiB
TypeScript
125 lines
4.3 KiB
TypeScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import {
|
|
createStreamPlaybackMetadataStore,
|
|
matchRequestedStreamPlaybackMetadata,
|
|
toAnimeBrowserPlaybackState,
|
|
toAnilistMediaGuess,
|
|
toJimakuMediaInfo,
|
|
} from './stream-playback-metadata';
|
|
import type { AnimeStreamMetadata } from '../../anime-bridge/episode-metadata';
|
|
|
|
function metadata(overrides: Partial<AnimeStreamMetadata> = {}): AnimeStreamMetadata {
|
|
return {
|
|
sourceId: '9001',
|
|
animeUrl: '/anime/mushoku',
|
|
episodeUrl: '/watch/ep-4',
|
|
mediaPath: 'http://127.0.0.1:41234/video/abc.m3u8',
|
|
statsPath: 'animebrowser://9001/%2Fanime%2Fmushoku/%2Fwatch%2Fep-4',
|
|
seriesTitle: 'Mushoku Tensei: Jobless Reincarnation',
|
|
seasonNumber: 3,
|
|
episodeNumber: 4,
|
|
episodeTitle: null,
|
|
displayTitle: 'Mushoku Tensei: Jobless Reincarnation S03E04',
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
test('browser playback state keeps the source episode identity and drops other media', () => {
|
|
assert.deepEqual(toAnimeBrowserPlaybackState(metadata()), {
|
|
sourceId: '9001',
|
|
animeUrl: '/anime/mushoku',
|
|
episodeUrl: '/watch/ep-4',
|
|
});
|
|
assert.equal(toAnimeBrowserPlaybackState(null), null);
|
|
});
|
|
|
|
test('the store answers for the stream URL and for the stats path', () => {
|
|
const store = createStreamPlaybackMetadataStore();
|
|
const current = metadata();
|
|
store.set(current);
|
|
|
|
assert.equal(store.match(current.mediaPath), current);
|
|
assert.equal(store.match(current.statsPath), current);
|
|
assert.equal(store.match(` ${current.mediaPath} `), current);
|
|
});
|
|
|
|
test('the store stops answering once the player moves on', () => {
|
|
const store = createStreamPlaybackMetadataStore();
|
|
store.set(metadata());
|
|
|
|
assert.equal(store.match('/home/user/Videos/local.mkv'), null);
|
|
assert.equal(store.match(null), null);
|
|
assert.equal(store.match(''), null);
|
|
|
|
store.clear();
|
|
assert.equal(store.match(metadata().mediaPath), null);
|
|
});
|
|
|
|
test('the store keeps metadata for more than one resolved playlist entry', () => {
|
|
const store = createStreamPlaybackMetadataStore();
|
|
const first = metadata();
|
|
const second = metadata({
|
|
mediaPath: 'http://127.0.0.1:41234/video/def.m3u8',
|
|
statsPath: 'animebrowser://9001/%2Fanime%2Fmushoku/%2Fwatch%2Fep-5',
|
|
episodeNumber: 5,
|
|
});
|
|
store.set(first);
|
|
store.set(second);
|
|
|
|
assert.equal(store.match(first.mediaPath), first);
|
|
assert.equal(store.match(second.mediaPath), second);
|
|
});
|
|
|
|
test('an explicit target path does not inherit the current stream metadata', () => {
|
|
const store = createStreamPlaybackMetadataStore();
|
|
const current = metadata();
|
|
store.set(current);
|
|
|
|
assert.equal(
|
|
matchRequestedStreamPlaybackMetadata(store, '/home/user/Videos/other.mkv', current.mediaPath),
|
|
null,
|
|
);
|
|
assert.equal(matchRequestedStreamPlaybackMetadata(store, null, current.mediaPath), current);
|
|
});
|
|
|
|
test('toJimakuMediaInfo prefills the modals with the source-reported fields', () => {
|
|
assert.deepEqual(toJimakuMediaInfo(metadata()), {
|
|
title: 'Mushoku Tensei: Jobless Reincarnation',
|
|
season: 3,
|
|
episode: 4,
|
|
confidence: 'high',
|
|
filename: 'Mushoku Tensei: Jobless Reincarnation S03E04',
|
|
rawTitle: 'Mushoku Tensei: Jobless Reincarnation S03E04',
|
|
});
|
|
});
|
|
|
|
test('toJimakuMediaInfo drops to low confidence when there is no episode', () => {
|
|
const info = toJimakuMediaInfo(metadata({ episodeNumber: null, seasonNumber: null }));
|
|
assert.equal(info.episode, null);
|
|
assert.equal(info.confidence, 'low');
|
|
assert.equal(info.title, 'Mushoku Tensei: Jobless Reincarnation');
|
|
});
|
|
|
|
test('toJimakuMediaInfo reports low confidence when a fractional episode is omitted', () => {
|
|
const info = toJimakuMediaInfo(metadata({ episodeNumber: 6.5 }));
|
|
assert.equal(info.episode, null);
|
|
assert.equal(info.confidence, 'low');
|
|
});
|
|
|
|
test('toAnilistMediaGuess reports the stream fields verbatim', () => {
|
|
assert.deepEqual(toAnilistMediaGuess(metadata()), {
|
|
title: 'Mushoku Tensei: Jobless Reincarnation',
|
|
season: 3,
|
|
episode: 4,
|
|
source: 'stream',
|
|
});
|
|
});
|
|
|
|
test('toAnilistMediaGuess declines a special so the caller can fall back', () => {
|
|
// AniList progress counts whole episodes; a 6.5 special is not one of them.
|
|
assert.equal(toAnilistMediaGuess(metadata({ episodeNumber: 6.5 })), null);
|
|
assert.equal(toAnilistMediaGuess(metadata({ episodeNumber: null })), null);
|
|
assert.equal(toAnilistMediaGuess(metadata({ seriesTitle: '' })), null);
|
|
});
|