feat(stats): add launcher stats command and build integration

- Launcher stats subcommand with cleanup mode
- Stats frontend build integrated into Makefile
- CI workflow updated for stats package
- Config example updated with stats section
- mpv plugin menu entry for stats toggle
This commit is contained in:
2026-03-14 22:14:46 -07:00
parent 26fb5b4162
commit 950263bd66
20 changed files with 456 additions and 60 deletions

View File

@@ -122,6 +122,9 @@ export function createDefaultArgs(launcherConfig: LauncherYoutubeSubgenConfig):
jellyfinPlay: false,
jellyfinDiscovery: false,
dictionary: false,
stats: false,
statsCleanup: false,
statsCleanupVocab: false,
doctor: false,
configPath: false,
configShow: false,
@@ -188,6 +191,9 @@ export function applyRootOptionsToArgs(
export function applyInvocationsToArgs(parsed: Args, invocations: CliInvocations): void {
if (invocations.dictionaryTriggered) parsed.dictionary = true;
if (invocations.statsTriggered) parsed.stats = true;
if (invocations.statsCleanup) parsed.statsCleanup = true;
if (invocations.statsCleanupVocab) parsed.statsCleanupVocab = true;
if (invocations.dictionaryTarget) {
parsed.dictionaryTarget = parseDictionaryTarget(invocations.dictionaryTarget);
}
@@ -256,6 +262,9 @@ export function applyInvocationsToArgs(parsed: Args, invocations: CliInvocations
if (invocations.dictionaryLogLevel) {
parsed.logLevel = parseLogLevel(invocations.dictionaryLogLevel);
}
if (invocations.statsLogLevel) {
parsed.logLevel = parseLogLevel(invocations.statsLogLevel);
}
if (invocations.doctorLogLevel) parsed.logLevel = parseLogLevel(invocations.doctorLogLevel);
if (invocations.texthookerLogLevel)

View File

@@ -40,6 +40,10 @@ export interface CliInvocations {
dictionaryTriggered: boolean;
dictionaryTarget: string | null;
dictionaryLogLevel: string | null;
statsTriggered: boolean;
statsCleanup: boolean;
statsCleanupVocab: boolean;
statsLogLevel: string | null;
doctorTriggered: boolean;
doctorLogLevel: string | null;
texthookerTriggered: boolean;
@@ -87,6 +91,7 @@ function getTopLevelCommand(argv: string[]): { name: string; index: number } | n
'mpv',
'dictionary',
'dict',
'stats',
'texthooker',
'app',
'bin',
@@ -137,6 +142,10 @@ export function parseCliPrograms(
let dictionaryTriggered = false;
let dictionaryTarget: string | null = null;
let dictionaryLogLevel: string | null = null;
let statsTriggered = false;
let statsCleanup = false;
let statsCleanupVocab = false;
let statsLogLevel: string | null = null;
let doctorLogLevel: string | null = null;
let texthookerLogLevel: string | null = null;
let doctorTriggered = false;
@@ -241,6 +250,21 @@ export function parseCliPrograms(
dictionaryLogLevel = typeof options.logLevel === 'string' ? options.logLevel : null;
});
commandProgram
.command('stats')
.description('Launch the local immersion stats dashboard')
.argument('[action]', 'cleanup')
.option('-v, --vocab', 'Clean vocabulary rows in the stats database')
.option('--log-level <level>', 'Log level')
.action((action: string | undefined, options: Record<string, unknown>) => {
statsTriggered = true;
if ((action || '').toLowerCase() === 'cleanup') {
statsCleanup = true;
statsCleanupVocab = options.vocab === true;
}
statsLogLevel = typeof options.logLevel === 'string' ? options.logLevel : null;
});
commandProgram
.command('doctor')
.description('Run dependency and environment checks')
@@ -319,6 +343,10 @@ export function parseCliPrograms(
dictionaryTriggered,
dictionaryTarget,
dictionaryLogLevel,
statsTriggered,
statsCleanup,
statsCleanupVocab,
statsLogLevel,
doctorTriggered,
doctorLogLevel,
texthookerTriggered,