Restore multi-copy digit capture and add AniList selection (#56)

This commit is contained in:
2026-04-25 21:44:55 -07:00
committed by GitHub
parent 7ac51cd5e9
commit d8934647a9
140 changed files with 4097 additions and 326 deletions
+24
View File
@@ -79,6 +79,7 @@ test('parseArgs captures session action forwarding flags', () => {
'--open-jimaku',
'--open-youtube-picker',
'--open-playlist-browser',
'--toggle-primary-subtitle-bar',
'--replay-current-subtitle',
'--play-next-subtitle',
'--shift-sub-delay-prev-line',
@@ -94,6 +95,7 @@ test('parseArgs captures session action forwarding flags', () => {
assert.equal(args.openJimaku, true);
assert.equal(args.openYoutubePicker, true);
assert.equal(args.openPlaylistBrowser, true);
assert.equal(args.togglePrimarySubtitleBar, true);
assert.equal(args.replayCurrentSubtitle, true);
assert.equal(args.playNextSubtitle, true);
assert.equal(args.shiftSubDelayPrevLine, true);
@@ -212,6 +214,22 @@ test('hasExplicitCommand and shouldStartApp preserve command intent', () => {
assert.equal(hasExplicitCommand(anilistRetryQueue), true);
assert.equal(shouldStartApp(anilistRetryQueue), false);
const dictionaryCandidates = parseArgs([
'--dictionary-candidates',
'--dictionary-target',
'/tmp/a.mkv',
]);
assert.equal(dictionaryCandidates.dictionaryCandidates, true);
assert.equal(dictionaryCandidates.dictionaryTarget, '/tmp/a.mkv');
assert.equal(hasExplicitCommand(dictionaryCandidates), true);
assert.equal(shouldStartApp(dictionaryCandidates), true);
const dictionarySelect = parseArgs(['--dictionary-select', '--dictionary-anilist-id', '21355']);
assert.equal(dictionarySelect.dictionarySelect, true);
assert.equal(dictionarySelect.dictionaryAnilistId, 21355);
assert.equal(hasExplicitCommand(dictionarySelect), true);
assert.equal(shouldStartApp(dictionarySelect), true);
const toggleStatsOverlay = parseArgs(['--toggle-stats-overlay']);
assert.equal(toggleStatsOverlay.toggleStatsOverlay, true);
assert.equal(hasExplicitCommand(toggleStatsOverlay), true);
@@ -320,6 +338,12 @@ test('hasExplicitCommand and shouldStartApp preserve command intent', () => {
assert.equal(hasExplicitCommand(background), true);
assert.equal(shouldStartApp(background), true);
const managedPlayback = parseArgs(['--background', '--managed-playback']);
assert.equal(managedPlayback.background, true);
assert.equal(managedPlayback.managedPlayback, true);
assert.equal(hasExplicitCommand(managedPlayback), true);
assert.equal(shouldStartApp(managedPlayback), true);
const setup = parseArgs(['--setup']);
assert.equal((setup as typeof setup & { setup?: boolean }).setup, true);
assert.equal(hasExplicitCommand(setup), true);
+41 -1
View File
@@ -1,5 +1,6 @@
export interface CliArgs {
background: boolean;
managedPlayback: boolean;
start: boolean;
launchMpv: boolean;
launchMpvTargets: string[];
@@ -8,6 +9,7 @@ export interface CliArgs {
stop: boolean;
toggle: boolean;
toggleVisibleOverlay: boolean;
togglePrimarySubtitleBar: boolean;
settings: boolean;
setup: boolean;
show: boolean;
@@ -28,6 +30,7 @@ export interface CliArgs {
toggleSubtitleSidebar: boolean;
openRuntimeOptions: boolean;
openSessionHelp: boolean;
openCharacterDictionary: boolean;
openControllerSelect: boolean;
openControllerDebug: boolean;
openJimaku: boolean;
@@ -46,6 +49,9 @@ export interface CliArgs {
anilistSetup: boolean;
anilistRetryQueue: boolean;
dictionary: boolean;
dictionaryCandidates: boolean;
dictionarySelect: boolean;
dictionaryAnilistId?: number;
dictionaryTarget?: string;
stats: boolean;
statsBackground?: boolean;
@@ -94,6 +100,7 @@ export type CliCommandSource = 'initial' | 'second-instance';
export function parseArgs(argv: string[]): CliArgs {
const args: CliArgs = {
background: false,
managedPlayback: false,
start: false,
launchMpv: false,
launchMpvTargets: [],
@@ -102,6 +109,7 @@ export function parseArgs(argv: string[]): CliArgs {
stop: false,
toggle: false,
toggleVisibleOverlay: false,
togglePrimarySubtitleBar: false,
settings: false,
setup: false,
show: false,
@@ -122,6 +130,7 @@ export function parseArgs(argv: string[]): CliArgs {
toggleSubtitleSidebar: false,
openRuntimeOptions: false,
openSessionHelp: false,
openCharacterDictionary: false,
openControllerSelect: false,
openControllerDebug: false,
openJimaku: false,
@@ -136,6 +145,8 @@ export function parseArgs(argv: string[]): CliArgs {
anilistSetup: false,
anilistRetryQueue: false,
dictionary: false,
dictionaryCandidates: false,
dictionarySelect: false,
stats: false,
statsBackground: false,
statsStop: false,
@@ -192,6 +203,7 @@ export function parseArgs(argv: string[]): CliArgs {
if (!arg || !arg.startsWith('--')) continue;
if (arg === '--background') args.background = true;
else if (arg === '--managed-playback') args.managedPlayback = true;
else if (arg === '--start') args.start = true;
else if (arg.startsWith('--youtube-play=')) {
const value = arg.split('=', 2)[1];
@@ -212,6 +224,7 @@ export function parseArgs(argv: string[]): CliArgs {
} else if (arg === '--stop') args.stop = true;
else if (arg === '--toggle') args.toggle = true;
else if (arg === '--toggle-visible-overlay') args.toggleVisibleOverlay = true;
else if (arg === '--toggle-primary-subtitle-bar') args.togglePrimarySubtitleBar = true;
else if (arg === '--settings' || arg === '--yomitan') args.settings = true;
else if (arg === '--setup') args.setup = true;
else if (arg === '--show') args.show = true;
@@ -232,6 +245,7 @@ export function parseArgs(argv: string[]): CliArgs {
else if (arg === '--toggle-subtitle-sidebar') args.toggleSubtitleSidebar = true;
else if (arg === '--open-runtime-options') args.openRuntimeOptions = true;
else if (arg === '--open-session-help') args.openSessionHelp = true;
else if (arg === '--open-character-dictionary') args.openCharacterDictionary = true;
else if (arg === '--open-controller-select') args.openControllerSelect = true;
else if (arg === '--open-controller-debug') args.openControllerDebug = true;
else if (arg === '--open-jimaku') args.openJimaku = true;
@@ -270,7 +284,15 @@ export function parseArgs(argv: string[]): CliArgs {
else if (arg === '--anilist-setup') args.anilistSetup = true;
else if (arg === '--anilist-retry-queue') args.anilistRetryQueue = true;
else if (arg === '--dictionary') args.dictionary = true;
else if (arg.startsWith('--dictionary-target=')) {
else if (arg === '--dictionary-candidates') args.dictionaryCandidates = true;
else if (arg === '--dictionary-select') args.dictionarySelect = true;
else if (arg.startsWith('--dictionary-anilist-id=')) {
const value = Number(arg.split('=', 2)[1]);
if (Number.isInteger(value) && value > 0) args.dictionaryAnilistId = value;
} else if (arg === '--dictionary-anilist-id') {
const value = Number(readValue(argv[i + 1]));
if (Number.isInteger(value) && value > 0) args.dictionaryAnilistId = value;
} else if (arg.startsWith('--dictionary-target=')) {
const value = arg.split('=', 2)[1];
if (value) args.dictionaryTarget = value;
} else if (arg === '--dictionary-target') {
@@ -440,6 +462,7 @@ export function hasExplicitCommand(args: CliArgs): boolean {
args.stop ||
args.toggle ||
args.toggleVisibleOverlay ||
args.togglePrimarySubtitleBar ||
args.settings ||
args.setup ||
args.show ||
@@ -460,6 +483,7 @@ export function hasExplicitCommand(args: CliArgs): boolean {
args.toggleSubtitleSidebar ||
args.openRuntimeOptions ||
args.openSessionHelp ||
args.openCharacterDictionary ||
args.openControllerSelect ||
args.openControllerDebug ||
args.openJimaku ||
@@ -477,6 +501,8 @@ export function hasExplicitCommand(args: CliArgs): boolean {
args.anilistSetup ||
args.anilistRetryQueue ||
args.dictionary ||
args.dictionaryCandidates ||
args.dictionarySelect ||
args.stats ||
args.jellyfin ||
args.jellyfinLogin ||
@@ -507,6 +533,7 @@ export function isStandaloneTexthookerCommand(args: CliArgs): boolean {
!args.stop &&
!args.toggle &&
!args.toggleVisibleOverlay &&
!args.togglePrimarySubtitleBar &&
!args.settings &&
!args.setup &&
!args.show &&
@@ -527,6 +554,7 @@ export function isStandaloneTexthookerCommand(args: CliArgs): boolean {
!args.toggleSubtitleSidebar &&
!args.openRuntimeOptions &&
!args.openSessionHelp &&
!args.openCharacterDictionary &&
!args.openControllerSelect &&
!args.openControllerDebug &&
!args.openJimaku &&
@@ -544,6 +572,8 @@ export function isStandaloneTexthookerCommand(args: CliArgs): boolean {
!args.anilistSetup &&
!args.anilistRetryQueue &&
!args.dictionary &&
!args.dictionaryCandidates &&
!args.dictionarySelect &&
!args.stats &&
!args.jellyfin &&
!args.jellyfinLogin &&
@@ -569,6 +599,7 @@ export function shouldStartApp(args: CliArgs): boolean {
args.launchMpv ||
args.toggle ||
args.toggleVisibleOverlay ||
args.togglePrimarySubtitleBar ||
args.settings ||
args.setup ||
args.copySubtitle ||
@@ -585,6 +616,7 @@ export function shouldStartApp(args: CliArgs): boolean {
args.toggleSubtitleSidebar ||
args.openRuntimeOptions ||
args.openSessionHelp ||
args.openCharacterDictionary ||
args.openControllerSelect ||
args.openControllerDebug ||
args.openJimaku ||
@@ -598,6 +630,8 @@ export function shouldStartApp(args: CliArgs): boolean {
args.copySubtitleCount !== undefined ||
args.mineSentenceCount !== undefined ||
args.dictionary ||
args.dictionaryCandidates ||
args.dictionarySelect ||
args.stats ||
args.jellyfin ||
args.jellyfinPlay ||
@@ -619,6 +653,7 @@ export function shouldRunSettingsOnlyStartup(args: CliArgs): boolean {
!args.stop &&
!args.toggle &&
!args.toggleVisibleOverlay &&
!args.togglePrimarySubtitleBar &&
!args.show &&
!args.hide &&
!args.setup &&
@@ -638,6 +673,7 @@ export function shouldRunSettingsOnlyStartup(args: CliArgs): boolean {
!args.toggleSubtitleSidebar &&
!args.openRuntimeOptions &&
!args.openSessionHelp &&
!args.openCharacterDictionary &&
!args.openControllerSelect &&
!args.openControllerDebug &&
!args.openJimaku &&
@@ -655,6 +691,8 @@ export function shouldRunSettingsOnlyStartup(args: CliArgs): boolean {
!args.anilistSetup &&
!args.anilistRetryQueue &&
!args.dictionary &&
!args.dictionaryCandidates &&
!args.dictionarySelect &&
!args.stats &&
!args.jellyfin &&
!args.jellyfinLogin &&
@@ -679,6 +717,7 @@ export function commandNeedsOverlayRuntime(args: CliArgs): boolean {
return (
args.toggle ||
args.toggleVisibleOverlay ||
args.togglePrimarySubtitleBar ||
args.show ||
args.hide ||
args.showVisibleOverlay ||
@@ -696,6 +735,7 @@ export function commandNeedsOverlayRuntime(args: CliArgs): boolean {
args.markAudioCard ||
args.openRuntimeOptions ||
args.openSessionHelp ||
args.openCharacterDictionary ||
args.openControllerSelect ||
args.openControllerDebug ||
args.openJimaku ||
+5
View File
@@ -19,6 +19,7 @@ ${B}Session${R}
${B}Overlay${R}
--toggle-visible-overlay Toggle subtitle overlay
--toggle-primary-subtitle-bar Toggle primary subtitle bar
--show-visible-overlay Show subtitle overlay
--hide-visible-overlay Hide subtitle overlay
--settings Open Yomitan settings window
@@ -38,6 +39,7 @@ ${B}Mining${R}
--toggle-subtitle-sidebar Toggle subtitle sidebar panel
--open-runtime-options Open runtime options palette
--open-session-help Open session help modal
--open-character-dictionary Open character dictionary anime selection modal
--open-controller-select Open controller select modal
--open-controller-debug Open controller debug modal
@@ -47,6 +49,9 @@ ${B}AniList${R}
--anilist-logout Clear stored AniList token
--anilist-retry-queue Retry next queued update
--dictionary Generate character dictionary ZIP for current anime
--dictionary-candidates Show character dictionary AniList candidates
--dictionary-select Save manual character dictionary AniList selection
--dictionary-anilist-id ${D}ID${R} AniList media ID for --dictionary-select
--dictionary-target ${D}PATH${R} Override dictionary source path (file or directory)
${B}Jellyfin${R}