mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-03-27 06:12:05 -07:00
chore: prepare v0.9.3 release
This commit is contained in:
@@ -1,29 +0,0 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { retimeYoutubeSubtitle } from './retime';
|
||||
|
||||
test('retimeYoutubeSubtitle uses the downloaded subtitle path as-is', async () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'subminer-youtube-retime-'));
|
||||
try {
|
||||
const primaryPath = path.join(root, 'primary.vtt');
|
||||
const referencePath = path.join(root, 'reference.vtt');
|
||||
fs.writeFileSync(primaryPath, 'WEBVTT\n', 'utf8');
|
||||
fs.writeFileSync(referencePath, 'WEBVTT\n', 'utf8');
|
||||
|
||||
const result = await retimeYoutubeSubtitle({
|
||||
primaryPath,
|
||||
secondaryPath: referencePath,
|
||||
});
|
||||
|
||||
assert.equal(result.ok, true);
|
||||
assert.equal(result.strategy, 'none');
|
||||
assert.equal(result.path, primaryPath);
|
||||
assert.equal(result.message, 'Using downloaded subtitle as-is (no automatic retime enabled)');
|
||||
assert.equal(fs.readFileSync(result.path, 'utf8'), 'WEBVTT\n');
|
||||
} finally {
|
||||
fs.rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
@@ -1,11 +0,0 @@
|
||||
export async function retimeYoutubeSubtitle(input: {
|
||||
primaryPath: string;
|
||||
secondaryPath: string | null;
|
||||
}): Promise<{ ok: boolean; path: string; strategy: 'none' | 'alass' | 'ffsubsync'; message: string }> {
|
||||
return {
|
||||
ok: true,
|
||||
path: input.primaryPath,
|
||||
strategy: 'none',
|
||||
message: `Using downloaded subtitle as-is${input.secondaryPath ? ' (no automatic retime enabled)' : ''}`,
|
||||
};
|
||||
}
|
||||
12
src/main.ts
12
src/main.ts
@@ -317,7 +317,6 @@ import {
|
||||
acquireYoutubeSubtitleTracks,
|
||||
} from './core/services/youtube/generate';
|
||||
import { resolveYoutubePlaybackUrl } from './core/services/youtube/playback-resolve';
|
||||
import { retimeYoutubeSubtitle } from './core/services/youtube/retime';
|
||||
import { probeYoutubeTracks } from './core/services/youtube/track-probe';
|
||||
import { startStatsServer } from './core/services/stats-server';
|
||||
import { registerStatsOverlayToggle, destroyStatsWindow } from './core/services/stats-window.js';
|
||||
@@ -824,17 +823,6 @@ const youtubeFlowRuntime = createYoutubeFlowRuntime({
|
||||
probeYoutubeTracks: (url: string) => probeYoutubeTracks(url),
|
||||
acquireYoutubeSubtitleTrack: (input) => acquireYoutubeSubtitleTrack(input),
|
||||
acquireYoutubeSubtitleTracks: (input) => acquireYoutubeSubtitleTracks(input),
|
||||
retimeYoutubePrimaryTrack: async ({ primaryTrack, primaryPath, secondaryTrack, secondaryPath }) => {
|
||||
if (primaryTrack.kind !== 'auto') {
|
||||
return primaryPath;
|
||||
}
|
||||
const result = await retimeYoutubeSubtitle({
|
||||
primaryPath,
|
||||
secondaryPath: secondaryTrack ? secondaryPath : null,
|
||||
});
|
||||
logger.info(`Using YouTube subtitle path: ${result.path} (${result.strategy})`);
|
||||
return result.path;
|
||||
},
|
||||
openPicker: async (payload) => {
|
||||
return await openYoutubeTrackPicker(
|
||||
{
|
||||
|
||||
@@ -46,7 +46,6 @@ test('youtube flow can open a manual picker session and load the selected subtit
|
||||
acquireYoutubeSubtitleTrack: async ({ track }) => ({
|
||||
path: `/tmp/${track.id.replace(/[^a-z0-9_-]+/gi, '-')}.vtt`,
|
||||
}),
|
||||
retimeYoutubePrimaryTrack: async ({ primaryPath }) => `${primaryPath}.retimed`,
|
||||
openPicker: async (payload) => {
|
||||
openedPayloads.push(payload);
|
||||
queueMicrotask(() => {
|
||||
@@ -75,7 +74,7 @@ test('youtube flow can open a manual picker session and load the selected subtit
|
||||
lang: 'ja-orig',
|
||||
title: 'primary',
|
||||
external: true,
|
||||
'external-filename': '/tmp/auto-ja-orig.vtt.retimed',
|
||||
'external-filename': '/tmp/auto-ja-orig.vtt',
|
||||
},
|
||||
{
|
||||
type: 'sub',
|
||||
@@ -135,7 +134,7 @@ test('youtube flow can open a manual picker session and load the selected subtit
|
||||
commands.some(
|
||||
(command) =>
|
||||
command[0] === 'sub-add' &&
|
||||
command[1] === '/tmp/auto-ja-orig.vtt.retimed' &&
|
||||
command[1] === '/tmp/auto-ja-orig.vtt' &&
|
||||
command[2] === 'select',
|
||||
),
|
||||
);
|
||||
@@ -157,7 +156,7 @@ test('youtube flow can open a manual picker session and load the selected subtit
|
||||
),
|
||||
),
|
||||
);
|
||||
assert.deepEqual(refreshedSidebarSources, ['/tmp/auto-ja-orig.vtt.retimed']);
|
||||
assert.deepEqual(refreshedSidebarSources, ['/tmp/auto-ja-orig.vtt']);
|
||||
assert.deepEqual(focusOverlayCalls, ['focus-overlay']);
|
||||
});
|
||||
|
||||
@@ -179,7 +178,6 @@ test('youtube flow retries secondary after partial batch subtitle failure', asyn
|
||||
acquireSingleCalls.push(track.id);
|
||||
return { path: `/tmp/${track.id}.vtt` };
|
||||
},
|
||||
retimeYoutubePrimaryTrack: async ({ primaryPath }) => primaryPath,
|
||||
openPicker: async (payload) => {
|
||||
queueMicrotask(() => {
|
||||
void runtime.resolveActivePicker({
|
||||
@@ -281,7 +279,6 @@ test('youtube flow reports probe failure through the configured reporter in manu
|
||||
},
|
||||
acquireYoutubeSubtitleTracks: async () => new Map(),
|
||||
acquireYoutubeSubtitleTrack: async () => ({ path: '/tmp/unused.vtt' }),
|
||||
retimeYoutubePrimaryTrack: async ({ primaryPath }) => primaryPath,
|
||||
openPicker: async () => true,
|
||||
pauseMpv: () => {},
|
||||
resumeMpv: () => {},
|
||||
@@ -322,7 +319,6 @@ test('youtube flow does not report failure when subtitle track binds before cue
|
||||
}),
|
||||
acquireYoutubeSubtitleTracks: async () => new Map(),
|
||||
acquireYoutubeSubtitleTrack: async () => ({ path: '/tmp/auto-ja-orig.vtt' }),
|
||||
retimeYoutubePrimaryTrack: async ({ primaryPath }) => primaryPath,
|
||||
openPicker: async (payload) => {
|
||||
queueMicrotask(() => {
|
||||
void runtime.resolveActivePicker({
|
||||
@@ -389,7 +385,6 @@ test('youtube flow does not fail when mpv reports sub-text as unavailable after
|
||||
}),
|
||||
acquireYoutubeSubtitleTracks: async () => new Map(),
|
||||
acquireYoutubeSubtitleTrack: async () => ({ path: '/tmp/auto-ja-orig.vtt' }),
|
||||
retimeYoutubePrimaryTrack: async ({ primaryPath }) => primaryPath,
|
||||
openPicker: async (payload) => {
|
||||
queueMicrotask(() => {
|
||||
void runtime.resolveActivePicker({
|
||||
@@ -464,7 +459,6 @@ test('youtube flow retries secondary subtitle selection until mpv reports the ex
|
||||
acquireYoutubeSubtitleTrack: async ({ track }) => ({
|
||||
path: `/tmp/${track.id.replace(/[^a-z0-9_-]+/gi, '-')}.vtt`,
|
||||
}),
|
||||
retimeYoutubePrimaryTrack: async ({ primaryPath }) => primaryPath,
|
||||
openPicker: async (payload) => {
|
||||
queueMicrotask(() => {
|
||||
void runtime.resolveActivePicker({
|
||||
@@ -568,7 +562,6 @@ test('youtube flow reuses the matching existing manual secondary track instead o
|
||||
acquireYoutubeSubtitleTrack: async ({ track }) => ({
|
||||
path: `/tmp/${track.id.replace(/[^a-z0-9_-]+/gi, '-')}.vtt`,
|
||||
}),
|
||||
retimeYoutubePrimaryTrack: async ({ primaryPath }) => primaryPath,
|
||||
openPicker: async (payload) => {
|
||||
queueMicrotask(() => {
|
||||
void runtime.resolveActivePicker({
|
||||
@@ -678,7 +671,6 @@ test('youtube flow leaves non-authoritative youtube subtitle tracks untouched af
|
||||
acquireYoutubeSubtitleTrack: async ({ track }) => ({
|
||||
path: `/tmp/${track.id.replace(/[^a-z0-9_-]+/gi, '-')}.vtt`,
|
||||
}),
|
||||
retimeYoutubePrimaryTrack: async ({ primaryPath }) => primaryPath,
|
||||
openPicker: async (payload) => {
|
||||
queueMicrotask(() => {
|
||||
void runtime.resolveActivePicker({
|
||||
@@ -772,7 +764,6 @@ test('youtube flow reuses existing manual youtube subtitle tracks when both requ
|
||||
}
|
||||
throw new Error('should not download secondary track when manual english already exists');
|
||||
},
|
||||
retimeYoutubePrimaryTrack: async ({ primaryPath }) => primaryPath,
|
||||
openPicker: async (payload) => {
|
||||
queueMicrotask(() => {
|
||||
void runtime.resolveActivePicker({
|
||||
@@ -871,7 +862,6 @@ test('youtube flow waits for manual youtube tracks to appear before falling back
|
||||
}
|
||||
throw new Error('should not download secondary track when manual english appears in mpv');
|
||||
},
|
||||
retimeYoutubePrimaryTrack: async ({ primaryPath }) => primaryPath,
|
||||
openPicker: async (payload) => {
|
||||
queueMicrotask(() => {
|
||||
void runtime.resolveActivePicker({
|
||||
@@ -982,7 +972,6 @@ test('youtube flow reuses manual youtube tracks even when mpv exposes external f
|
||||
}
|
||||
throw new Error('should not download secondary track when existing manual english track is reusable');
|
||||
},
|
||||
retimeYoutubePrimaryTrack: async ({ primaryPath }) => primaryPath,
|
||||
openPicker: async () => false,
|
||||
pauseMpv: () => {},
|
||||
resumeMpv: () => {},
|
||||
@@ -1102,7 +1091,6 @@ test('youtube flow falls back to existing auto secondary track when auto seconda
|
||||
}
|
||||
return { path: '/tmp/auto-ja-orig.ja-orig.vtt' };
|
||||
},
|
||||
retimeYoutubePrimaryTrack: async ({ primaryPath }) => primaryPath,
|
||||
openPicker: async () => false,
|
||||
pauseMpv: () => {},
|
||||
resumeMpv: () => {},
|
||||
|
||||
@@ -26,13 +26,6 @@ type YoutubeFlowDeps = {
|
||||
probeYoutubeTracks: (url: string) => Promise<YoutubeTrackProbeResult>;
|
||||
acquireYoutubeSubtitleTrack: typeof acquireYoutubeSubtitleTrack;
|
||||
acquireYoutubeSubtitleTracks: typeof acquireYoutubeSubtitleTracks;
|
||||
retimeYoutubePrimaryTrack: (input: {
|
||||
targetUrl: string;
|
||||
primaryTrack: YoutubeTrackOption;
|
||||
primaryPath: string;
|
||||
secondaryTrack: YoutubeTrackOption | null;
|
||||
secondaryPath: string | null;
|
||||
}) => Promise<string>;
|
||||
openPicker: YoutubeFlowOpenPicker;
|
||||
pauseMpv: () => void;
|
||||
resumeMpv: () => void;
|
||||
@@ -624,14 +617,7 @@ export function createYoutubeFlowRuntime(deps: YoutubeFlowDeps) {
|
||||
track: input.primaryTrack,
|
||||
})
|
||||
).path;
|
||||
primarySidebarPath = await deps.retimeYoutubePrimaryTrack({
|
||||
targetUrl: input.url,
|
||||
primaryTrack: input.primaryTrack,
|
||||
primaryPath: primaryInjectedPath,
|
||||
secondaryTrack: input.secondaryTrack,
|
||||
secondaryPath: null,
|
||||
});
|
||||
primaryInjectedPath = primarySidebarPath;
|
||||
primarySidebarPath = primaryInjectedPath;
|
||||
} else {
|
||||
const acquired = await acquireSelectedTracks({
|
||||
targetUrl: input.url,
|
||||
@@ -640,13 +626,7 @@ export function createYoutubeFlowRuntime(deps: YoutubeFlowDeps) {
|
||||
secondaryTrack: existingSecondaryTrackId === null ? input.secondaryTrack : null,
|
||||
secondaryFailureLabel: input.secondaryFailureLabel,
|
||||
});
|
||||
primarySidebarPath = await deps.retimeYoutubePrimaryTrack({
|
||||
targetUrl: input.url,
|
||||
primaryTrack: input.primaryTrack,
|
||||
primaryPath: acquired.primaryPath,
|
||||
secondaryTrack: input.secondaryTrack,
|
||||
secondaryPath: acquired.secondaryPath,
|
||||
});
|
||||
primarySidebarPath = acquired.primaryPath;
|
||||
primaryInjectedPath = primarySidebarPath;
|
||||
secondaryInjectedPath = acquired.secondaryPath;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user