mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-09-21 17:16:20 -07:00
fix(anki): honor unlimited duration in stats mining (#258)
This commit is contained in:
@@ -1762,6 +1762,60 @@ describe('stats server API routes', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('POST /api/stats/mine-card treats a zero media duration cap as unlimited', async () => {
|
||||
await withTempDir(async (dir) => {
|
||||
const sourcePath = path.join(dir, 'episode.mkv');
|
||||
fs.writeFileSync(sourcePath, 'fake media');
|
||||
const audioRanges: Array<{ start: number; end: number; padding: number | undefined }> = [];
|
||||
const scenarios = [
|
||||
{ maxMediaDuration: 0, expectedEnd: 12 },
|
||||
{ maxMediaDuration: 1, expectedEnd: 11 },
|
||||
];
|
||||
|
||||
for (const scenario of scenarios) {
|
||||
const app = createStatsApp(createMockTracker(), {
|
||||
addYomitanNote: async () => null,
|
||||
createMediaGenerator: () => ({
|
||||
generateAudio: async (_path, start, end, padding) => {
|
||||
audioRanges.push({ start, end, padding });
|
||||
return Buffer.from('audio');
|
||||
},
|
||||
generateScreenshot: async () => null,
|
||||
generateAnimatedImage: async () => null,
|
||||
}),
|
||||
ankiConnectConfig: {
|
||||
deck: 'Mining',
|
||||
media: {
|
||||
generateAudio: true,
|
||||
generateImage: false,
|
||||
audioPadding: 0.25,
|
||||
maxMediaDuration: scenario.maxMediaDuration,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const res = await app.request('/api/stats/mine-card?mode=word', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
sourcePath,
|
||||
startMs: 10_000,
|
||||
endMs: 12_000,
|
||||
sentence: '猫を見た',
|
||||
word: '猫',
|
||||
}),
|
||||
});
|
||||
|
||||
assert.equal(res.status, 502);
|
||||
assert.deepEqual(audioRanges.at(-1), {
|
||||
start: 10,
|
||||
end: scenario.expectedEnd,
|
||||
padding: 0.25,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('POST /api/stats/mine-card requires a non-empty word in word mode', async () => {
|
||||
await withTempDir(async (dir) => {
|
||||
const sourcePath = path.join(dir, 'episode.mkv');
|
||||
|
||||
@@ -4,6 +4,7 @@ import { basename } from 'node:path';
|
||||
import { AnkiConnectClient } from '../../../anki-connect.js';
|
||||
import { getConfiguredWordFieldName } from '../../../anki-field-config.js';
|
||||
import { resolveAnimatedImageLeadInSeconds } from '../../../anki-integration/animated-image-sync.js';
|
||||
import { clampMediaEndTime } from '../../../anki-integration/media-duration.js';
|
||||
import { MediaGenerator } from '../../../media-generator.js';
|
||||
import { statsJson } from '../../../types/stats-http-contract.js';
|
||||
import {
|
||||
@@ -113,8 +114,7 @@ export function registerStatsMiningRoutes(app: Hono, options?: StatsMiningRouteO
|
||||
|
||||
const startSec = startMs / 1000;
|
||||
const endSec = endMs / 1000;
|
||||
const rawDuration = endSec - startSec;
|
||||
const clampedEndSec = rawDuration > maxMediaDuration ? startSec + maxMediaDuration : endSec;
|
||||
const clampedEndSec = clampMediaEndTime(startSec, endSec, maxMediaDuration);
|
||||
|
||||
const highlightedSentence = word
|
||||
? sentence.replace(
|
||||
|
||||
Reference in New Issue
Block a user