mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-02-27 18:22:41 -08:00
238 lines
8.6 KiB
TypeScript
238 lines
8.6 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import type { AnilistMediaGuess } from '../../../core/services/anilist/anilist-updater';
|
|
import { composeAnilistTrackingHandlers } from './anilist-tracking-composer';
|
|
|
|
test('composeAnilistTrackingHandlers returns callable handlers and forwards calls to deps', async () => {
|
|
const refreshSavedTokens: string[] = [];
|
|
let refreshCachedToken: string | null = null;
|
|
|
|
let mediaKeyState: string | null = 'media-key';
|
|
let mediaDurationSecState: number | null = null;
|
|
let mediaGuessState: AnilistMediaGuess | null = null;
|
|
let mediaGuessPromiseState: Promise<AnilistMediaGuess | null> | null = null;
|
|
let lastDurationProbeAtMsState = 0;
|
|
let requestMpvDurationCalls = 0;
|
|
let guessAnilistMediaInfoCalls = 0;
|
|
|
|
let retryUpdateCalls = 0;
|
|
let maybeRunUpdateCalls = 0;
|
|
|
|
const composed = composeAnilistTrackingHandlers({
|
|
refreshClientSecretMainDeps: {
|
|
getResolvedConfig: () => ({ anilist: { accessToken: 'refresh-token' } }),
|
|
isAnilistTrackingEnabled: () => true,
|
|
getCachedAccessToken: () => refreshCachedToken,
|
|
setCachedAccessToken: (token) => {
|
|
refreshCachedToken = token;
|
|
},
|
|
saveStoredToken: (token) => {
|
|
refreshSavedTokens.push(token);
|
|
},
|
|
loadStoredToken: () => null,
|
|
setClientSecretState: () => {},
|
|
getAnilistSetupPageOpened: () => false,
|
|
setAnilistSetupPageOpened: () => {},
|
|
openAnilistSetupWindow: () => {},
|
|
now: () => 100,
|
|
},
|
|
getCurrentMediaKeyMainDeps: {
|
|
getCurrentMediaPath: () => ' media-key ',
|
|
},
|
|
resetMediaTrackingMainDeps: {
|
|
setMediaKey: (value) => {
|
|
mediaKeyState = value;
|
|
},
|
|
setMediaDurationSec: (value) => {
|
|
mediaDurationSecState = value;
|
|
},
|
|
setMediaGuess: (value) => {
|
|
mediaGuessState = value;
|
|
},
|
|
setMediaGuessPromise: (value) => {
|
|
mediaGuessPromiseState = value;
|
|
},
|
|
setLastDurationProbeAtMs: (value) => {
|
|
lastDurationProbeAtMsState = value;
|
|
},
|
|
},
|
|
getMediaGuessRuntimeStateMainDeps: {
|
|
getMediaKey: () => mediaKeyState,
|
|
getMediaDurationSec: () => mediaDurationSecState,
|
|
getMediaGuess: () => mediaGuessState,
|
|
getMediaGuessPromise: () => mediaGuessPromiseState,
|
|
getLastDurationProbeAtMs: () => lastDurationProbeAtMsState,
|
|
},
|
|
setMediaGuessRuntimeStateMainDeps: {
|
|
setMediaKey: (value) => {
|
|
mediaKeyState = value;
|
|
},
|
|
setMediaDurationSec: (value) => {
|
|
mediaDurationSecState = value;
|
|
},
|
|
setMediaGuess: (value) => {
|
|
mediaGuessState = value;
|
|
},
|
|
setMediaGuessPromise: (value) => {
|
|
mediaGuessPromiseState = value;
|
|
},
|
|
setLastDurationProbeAtMs: (value) => {
|
|
lastDurationProbeAtMsState = value;
|
|
},
|
|
},
|
|
resetMediaGuessStateMainDeps: {
|
|
setMediaGuess: (value) => {
|
|
mediaGuessState = value;
|
|
},
|
|
setMediaGuessPromise: (value) => {
|
|
mediaGuessPromiseState = value;
|
|
},
|
|
},
|
|
maybeProbeDurationMainDeps: {
|
|
getState: () => ({
|
|
mediaKey: mediaKeyState,
|
|
mediaDurationSec: mediaDurationSecState,
|
|
mediaGuess: mediaGuessState,
|
|
mediaGuessPromise: mediaGuessPromiseState,
|
|
lastDurationProbeAtMs: lastDurationProbeAtMsState,
|
|
}),
|
|
setState: (state) => {
|
|
mediaKeyState = state.mediaKey;
|
|
mediaDurationSecState = state.mediaDurationSec;
|
|
mediaGuessState = state.mediaGuess;
|
|
mediaGuessPromiseState = state.mediaGuessPromise;
|
|
lastDurationProbeAtMsState = state.lastDurationProbeAtMs;
|
|
},
|
|
durationRetryIntervalMs: 0,
|
|
now: () => 1000,
|
|
requestMpvDuration: async () => {
|
|
requestMpvDurationCalls += 1;
|
|
return 120;
|
|
},
|
|
logWarn: () => {},
|
|
},
|
|
ensureMediaGuessMainDeps: {
|
|
getState: () => ({
|
|
mediaKey: mediaKeyState,
|
|
mediaDurationSec: mediaDurationSecState,
|
|
mediaGuess: mediaGuessState,
|
|
mediaGuessPromise: mediaGuessPromiseState,
|
|
lastDurationProbeAtMs: lastDurationProbeAtMsState,
|
|
}),
|
|
setState: (state) => {
|
|
mediaKeyState = state.mediaKey;
|
|
mediaDurationSecState = state.mediaDurationSec;
|
|
mediaGuessState = state.mediaGuess;
|
|
mediaGuessPromiseState = state.mediaGuessPromise;
|
|
lastDurationProbeAtMsState = state.lastDurationProbeAtMs;
|
|
},
|
|
resolveMediaPathForJimaku: (value) => value,
|
|
getCurrentMediaPath: () => '/tmp/media.mkv',
|
|
getCurrentMediaTitle: () => 'Episode title',
|
|
guessAnilistMediaInfo: async () => {
|
|
guessAnilistMediaInfoCalls += 1;
|
|
return { title: 'Episode title', episode: 7, source: 'guessit' };
|
|
},
|
|
},
|
|
processNextRetryUpdateMainDeps: {
|
|
nextReady: () => ({ key: 'retry-key', title: 'Retry title', episode: 1 }),
|
|
refreshRetryQueueState: () => {},
|
|
setLastAttemptAt: () => {},
|
|
setLastError: () => {},
|
|
refreshAnilistClientSecretState: async () => 'retry-token',
|
|
updateAnilistPostWatchProgress: async () => {
|
|
retryUpdateCalls += 1;
|
|
return { status: 'updated', message: 'ok' };
|
|
},
|
|
markSuccess: () => {},
|
|
rememberAttemptedUpdateKey: () => {},
|
|
markFailure: () => {},
|
|
logInfo: () => {},
|
|
now: () => 1,
|
|
},
|
|
maybeRunPostWatchUpdateMainDeps: {
|
|
getInFlight: () => false,
|
|
setInFlight: () => {},
|
|
getResolvedConfig: () => ({ tracking: true }),
|
|
isAnilistTrackingEnabled: () => true,
|
|
getCurrentMediaKey: () => 'media-key',
|
|
hasMpvClient: () => true,
|
|
getTrackedMediaKey: () => 'media-key',
|
|
resetTrackedMedia: () => {},
|
|
getWatchedSeconds: () => 500,
|
|
maybeProbeAnilistDuration: async () => 600,
|
|
ensureAnilistMediaGuess: async () => ({
|
|
title: 'Episode title',
|
|
episode: 2,
|
|
source: 'guessit',
|
|
}),
|
|
hasAttemptedUpdateKey: () => false,
|
|
processNextAnilistRetryUpdate: async () => ({ ok: true, message: 'ok' }),
|
|
refreshAnilistClientSecretState: async () => 'run-token',
|
|
enqueueRetry: () => {},
|
|
markRetryFailure: () => {},
|
|
markRetrySuccess: () => {},
|
|
refreshRetryQueueState: () => {},
|
|
updateAnilistPostWatchProgress: async () => {
|
|
maybeRunUpdateCalls += 1;
|
|
return { status: 'updated', message: 'updated from maybeRun' };
|
|
},
|
|
rememberAttemptedUpdateKey: () => {},
|
|
showMpvOsd: () => {},
|
|
logInfo: () => {},
|
|
logWarn: () => {},
|
|
minWatchSeconds: 10,
|
|
minWatchRatio: 0.5,
|
|
},
|
|
});
|
|
|
|
assert.equal(typeof composed.refreshAnilistClientSecretState, 'function');
|
|
assert.equal(typeof composed.getCurrentAnilistMediaKey, 'function');
|
|
assert.equal(typeof composed.resetAnilistMediaTracking, 'function');
|
|
assert.equal(typeof composed.getAnilistMediaGuessRuntimeState, 'function');
|
|
assert.equal(typeof composed.setAnilistMediaGuessRuntimeState, 'function');
|
|
assert.equal(typeof composed.resetAnilistMediaGuessState, 'function');
|
|
assert.equal(typeof composed.maybeProbeAnilistDuration, 'function');
|
|
assert.equal(typeof composed.ensureAnilistMediaGuess, 'function');
|
|
assert.equal(typeof composed.processNextAnilistRetryUpdate, 'function');
|
|
assert.equal(typeof composed.maybeRunAnilistPostWatchUpdate, 'function');
|
|
|
|
const refreshed = await composed.refreshAnilistClientSecretState({ force: true });
|
|
assert.equal(refreshed, 'refresh-token');
|
|
assert.deepEqual(refreshSavedTokens, ['refresh-token']);
|
|
|
|
assert.equal(composed.getCurrentAnilistMediaKey(), 'media-key');
|
|
composed.resetAnilistMediaTracking('next-key');
|
|
assert.equal(mediaKeyState, 'next-key');
|
|
assert.equal(mediaDurationSecState, null);
|
|
|
|
composed.setAnilistMediaGuessRuntimeState({
|
|
mediaKey: 'media-key',
|
|
mediaDurationSec: 90,
|
|
mediaGuess: { title: 'Known', episode: 3, source: 'fallback' },
|
|
mediaGuessPromise: null,
|
|
lastDurationProbeAtMs: 11,
|
|
});
|
|
assert.equal(composed.getAnilistMediaGuessRuntimeState().mediaDurationSec, 90);
|
|
|
|
composed.resetAnilistMediaGuessState();
|
|
assert.equal(composed.getAnilistMediaGuessRuntimeState().mediaGuess, null);
|
|
|
|
mediaKeyState = 'media-key';
|
|
mediaDurationSecState = null;
|
|
const probedDuration = await composed.maybeProbeAnilistDuration('media-key');
|
|
assert.equal(probedDuration, 120);
|
|
assert.equal(requestMpvDurationCalls, 1);
|
|
|
|
mediaGuessState = null;
|
|
await composed.ensureAnilistMediaGuess('media-key');
|
|
assert.equal(guessAnilistMediaInfoCalls, 1);
|
|
|
|
const retryResult = await composed.processNextAnilistRetryUpdate();
|
|
assert.deepEqual(retryResult, { ok: true, message: 'ok' });
|
|
assert.equal(retryUpdateCalls, 1);
|
|
|
|
await composed.maybeRunAnilistPostWatchUpdate();
|
|
assert.equal(maybeRunUpdateCalls, 1);
|
|
});
|