mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-09-22 05:16:22 -07:00
fix(anki): honor unlimited duration in stats mining (#258)
This commit is contained in:
@@ -160,6 +160,52 @@ test('manual clipboard subtitle update replaces audio in the configured field',
|
||||
);
|
||||
});
|
||||
|
||||
test('manual clipboard mining treats a zero media duration cap as unlimited', async () => {
|
||||
const audioRanges: Array<{ start: number; end: number; padding: number | undefined }> = [];
|
||||
const scenarios = [
|
||||
{ maxMediaDuration: 0, expectedEnd: 14 },
|
||||
{ maxMediaDuration: 1, expectedEnd: 13 },
|
||||
];
|
||||
|
||||
for (const scenario of scenarios) {
|
||||
const { service } = createManualUpdateService({
|
||||
getConfig: () =>
|
||||
({
|
||||
deck: 'Mining',
|
||||
fields: {
|
||||
word: 'Expression',
|
||||
sentence: 'Sentence',
|
||||
audio: 'ExpressionAudio',
|
||||
},
|
||||
media: {
|
||||
generateAudio: true,
|
||||
generateImage: false,
|
||||
audioPadding: 0.25,
|
||||
maxMediaDuration: scenario.maxMediaDuration,
|
||||
},
|
||||
behavior: {},
|
||||
ai: false,
|
||||
}) as AnkiConnectConfig,
|
||||
mediaGenerator: {
|
||||
generateAudio: async (_path, start, end, padding) => {
|
||||
audioRanges.push({ start, end, padding });
|
||||
return Buffer.from('audio');
|
||||
},
|
||||
generateScreenshot: async () => null,
|
||||
generateAnimatedImage: async () => null,
|
||||
},
|
||||
});
|
||||
|
||||
await service.updateLastAddedFromClipboard('字幕');
|
||||
|
||||
assert.deepEqual(audioRanges.at(-1), {
|
||||
start: 12,
|
||||
end: scenario.expectedEnd,
|
||||
padding: 0.25,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test('manual clipboard word-card update uses configured fields with Lapis and Kiku enabled', async () => {
|
||||
const { service, updatedFields } = createManualUpdateService({
|
||||
getConfig: () =>
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
resolveAudioStreamIndexForMediaGeneration,
|
||||
type MediaGenerationInputResolverOptions,
|
||||
} from './media-source';
|
||||
import { clampMediaEndTime } from './media-duration';
|
||||
import { resolveWordCardKind } from './note-field-utils';
|
||||
import type { PendingYoutubeMediaUpdate } from './pending-youtube-media';
|
||||
import { resolveMpvVolumeScale } from './mpv-volume';
|
||||
@@ -233,11 +234,12 @@ export class CardCreationService {
|
||||
let rangeEnd = Math.max(...timings.map((entry) => entry.endTime));
|
||||
|
||||
const maxMediaDuration = this.deps.getConfig().media?.maxMediaDuration ?? 30;
|
||||
if (maxMediaDuration > 0 && rangeEnd - rangeStart > maxMediaDuration) {
|
||||
const cappedRangeEnd = clampMediaEndTime(rangeStart, rangeEnd, maxMediaDuration);
|
||||
if (cappedRangeEnd !== rangeEnd) {
|
||||
log.warn(
|
||||
`Media range ${(rangeEnd - rangeStart).toFixed(1)}s exceeds cap of ${maxMediaDuration}s, clamping`,
|
||||
);
|
||||
rangeEnd = rangeStart + maxMediaDuration;
|
||||
rangeEnd = cappedRangeEnd;
|
||||
}
|
||||
|
||||
this.deps.showOsdNotification('Updating card from clipboard...');
|
||||
@@ -437,9 +439,7 @@ export class CardCreationService {
|
||||
}
|
||||
|
||||
const maxMediaDuration = this.deps.getConfig().media?.maxMediaDuration ?? 30;
|
||||
if (maxMediaDuration > 0 && endTime - startTime > maxMediaDuration) {
|
||||
endTime = startTime + maxMediaDuration;
|
||||
}
|
||||
endTime = clampMediaEndTime(startTime, endTime, maxMediaDuration);
|
||||
|
||||
this.deps.showOsdNotification('Marking card as audio card...');
|
||||
await this.deps.withUpdateProgress('Marking audio card', async () => {
|
||||
@@ -600,11 +600,12 @@ export class CardCreationService {
|
||||
}
|
||||
|
||||
const maxMediaDuration = this.deps.getConfig().media?.maxMediaDuration ?? 30;
|
||||
if (maxMediaDuration > 0 && endTime - startTime > maxMediaDuration) {
|
||||
const cappedEndTime = clampMediaEndTime(startTime, endTime, maxMediaDuration);
|
||||
if (cappedEndTime !== endTime) {
|
||||
log.warn(
|
||||
`Sentence card media range ${(endTime - startTime).toFixed(1)}s exceeds cap of ${maxMediaDuration}s, clamping`,
|
||||
);
|
||||
endTime = startTime + maxMediaDuration;
|
||||
endTime = cappedEndTime;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
/** Zero or a negative cap leaves the requested end time unchanged. */
|
||||
export function clampMediaEndTime(
|
||||
startTime: number,
|
||||
endTime: number,
|
||||
maxMediaDuration: number,
|
||||
): number {
|
||||
return maxMediaDuration > 0 && endTime - startTime > maxMediaDuration
|
||||
? startTime + maxMediaDuration
|
||||
: endTime;
|
||||
}
|
||||
Reference in New Issue
Block a user