fix(stats): harden duplicate-line cleanup and tracking

- Reject malformed requests and sub-day cleanup windows
- Reset deduplication across media and subtitle-track changes
- Handle karaoke bursts ending with a long hold frame
This commit is contained in:
2026-08-11 22:20:50 -07:00
parent fa4c734e30
commit 046a87a826
15 changed files with 410 additions and 55 deletions
+22
View File
@@ -399,6 +399,28 @@ test('hasExplicitCommand and shouldStartApp preserve command intent', () => {
assert.equal(statsLifetimeRebuild.statsCleanupLifetime, true);
assert.equal(statsLifetimeRebuild.statsCleanupVocab, false);
assert.throws(
() =>
parseArgs([
'--stats',
'--stats-cleanup',
'--stats-cleanup-duplicate-lines',
'--stats-cleanup-lookback-days',
'0.5',
]),
/at least one day/,
);
assert.equal(
parseArgs([
'--stats',
'--stats-cleanup',
'--stats-cleanup-duplicate-lines',
'--stats-cleanup-lookback-days',
'1.5',
]).statsCleanupLookbackDays,
1,
);
const jellyfinLibraries = parseArgs(['--jellyfin-libraries']);
assert.equal(jellyfinLibraries.jellyfinLibraries, true);
assert.equal(hasExplicitCommand(jellyfinLibraries), true);
+10 -4
View File
@@ -112,6 +112,14 @@ export interface CliArgs {
export type CliCommandSource = 'initial' | 'second-instance';
function parseStatsCleanupLookbackDays(value: string | undefined): number {
const days = Number(value);
if (!Number.isFinite(days) || days < 1) {
throw new Error('Stats --lookback-days must be at least one day.');
}
return Math.floor(days);
}
export function parseArgs(argv: string[]): CliArgs {
const args: CliArgs = {
background: false,
@@ -376,11 +384,9 @@ export function parseArgs(argv: string[]): CliArgs {
else if (arg === '--stats-cleanup-duplicate-lines') args.statsCleanupDuplicateLines = true;
else if (arg === '--stats-cleanup-dry-run') args.statsCleanupDryRun = true;
else if (arg.startsWith('--stats-cleanup-lookback-days=')) {
const value = Number(arg.split('=', 2)[1]);
if (Number.isFinite(value) && value > 0) args.statsCleanupLookbackDays = Math.floor(value);
args.statsCleanupLookbackDays = parseStatsCleanupLookbackDays(arg.split('=', 2)[1]);
} else if (arg === '--stats-cleanup-lookback-days') {
const value = Number(readValue(argv[i + 1]));
if (Number.isFinite(value) && value > 0) args.statsCleanupLookbackDays = Math.floor(value);
args.statsCleanupLookbackDays = parseStatsCleanupLookbackDays(readValue(argv[i + 1]));
} else if (arg.startsWith('--stats-response-path=')) {
const value = arg.split('=', 2)[1];
if (value) args.statsResponsePath = value;