mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-08-15 13:55:51 -07:00
fix(anki): snapshot mining media clip timing (#197)
This commit is contained in:
@@ -16,6 +16,7 @@ export {
|
||||
export { createOverlayShortcutRuntimeHandlers } from './overlay-shortcut-handler';
|
||||
export { createCliCommandDepsRuntime, handleCliCommand } from './cli-command';
|
||||
export {
|
||||
captureLiveSubtitleMiningContext,
|
||||
copyCurrentSubtitle,
|
||||
handleMineSentenceDigit,
|
||||
handleMultiCopyDigit,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import {
|
||||
captureLiveSubtitleMiningContext,
|
||||
copyCurrentSubtitle,
|
||||
handleMineSentenceDigit,
|
||||
handleMultiCopyDigit,
|
||||
@@ -345,3 +346,46 @@ test('handleMineSentenceDigit joins per-entry secondary subtitles when available
|
||||
tracker.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
test('captureLiveSubtitleMiningContext snapshots the current line and timings', () => {
|
||||
const context = captureLiveSubtitleMiningContext(
|
||||
{ currentSubText: ' 食べる ', currentSubStart: 12.5, currentSubEnd: 15.25 },
|
||||
() => 1234,
|
||||
);
|
||||
|
||||
assert.deepEqual(context, {
|
||||
source: 'overlay',
|
||||
text: '食べる',
|
||||
startTime: 12.5,
|
||||
endTime: 15.25,
|
||||
capturedAtMs: 1234,
|
||||
});
|
||||
});
|
||||
|
||||
test('captureLiveSubtitleMiningContext rejects missing client, empty text and bad timings', () => {
|
||||
assert.equal(captureLiveSubtitleMiningContext(null), null);
|
||||
assert.equal(
|
||||
captureLiveSubtitleMiningContext({
|
||||
currentSubText: ' ',
|
||||
currentSubStart: 1,
|
||||
currentSubEnd: 2,
|
||||
}),
|
||||
null,
|
||||
);
|
||||
assert.equal(
|
||||
captureLiveSubtitleMiningContext({
|
||||
currentSubText: 'line',
|
||||
currentSubStart: 5,
|
||||
currentSubEnd: 5,
|
||||
}),
|
||||
null,
|
||||
);
|
||||
assert.equal(
|
||||
captureLiveSubtitleMiningContext({
|
||||
currentSubText: 'line',
|
||||
currentSubStart: NaN,
|
||||
currentSubEnd: 2,
|
||||
}),
|
||||
null,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { SubtitleTimingBlock } from '../../subtitle-timing-tracker';
|
||||
import type { SubtitleMiningContext } from '../../types/subtitle';
|
||||
|
||||
interface SubtitleTimingTrackerLike {
|
||||
getRecentBlocks: (count: number) => string[];
|
||||
@@ -54,6 +55,27 @@ export function handleMultiCopyDigit(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Snapshot the live mpv subtitle line and its timings as a mining context. Media
|
||||
* generation can run tens of seconds after the user mines (slow audio extraction),
|
||||
* so anything that reads `currentSubStart`/`currentSubEnd` lazily clips whichever
|
||||
* line is on screen by then; callers capture here at mining time instead.
|
||||
*/
|
||||
export function captureLiveSubtitleMiningContext(
|
||||
client: Pick<MpvClientLike, 'currentSubText' | 'currentSubStart' | 'currentSubEnd'> | null,
|
||||
now: () => number = Date.now,
|
||||
): SubtitleMiningContext | null {
|
||||
if (!client) {
|
||||
return null;
|
||||
}
|
||||
const text = client.currentSubText?.trim();
|
||||
const { currentSubStart: startTime, currentSubEnd: endTime } = client;
|
||||
if (!text || !Number.isFinite(startTime) || !Number.isFinite(endTime) || endTime <= startTime) {
|
||||
return null;
|
||||
}
|
||||
return { source: 'overlay', text, startTime, endTime, capturedAtMs: now() };
|
||||
}
|
||||
|
||||
export function copyCurrentSubtitle(deps: {
|
||||
subtitleTimingTracker: SubtitleTimingTrackerLike | null;
|
||||
writeClipboardText: (text: string) => void;
|
||||
|
||||
Reference in New Issue
Block a user