9134e7d216
CC12: renderer views/ (5 screens + Onboarding + settings cards) + lib/ (theme/thumb/datetime/id/qualityOptions/useClipboardLink/queueStats); main core/ (buildArgs/validation/indexerCore/ytdlpPolicy). git mv preserved history; all src+test imports updated. Build emits view chunks from views/, 344 tests + typecheck green, live probe rendered all screens. CC7: wc/onProgress is the leading arg everywhere — downloadAppUpdate(wc,url), indexSource(onProgress,url,signal), indexSourceCancelable(onProgress,url). CC10: closed by-design — jsonStore backs all records; settings stay in electron-store for DPAPI secret encryption (a deliberate two-store split). Also closes the UI24/W4 context-menu cross-reference. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
40 lines
1.7 KiB
TypeScript
40 lines
1.7 KiB
TypeScript
import { HISTORY_MAX_ENTRIES, type HistoryEntry } from '@shared/ipc'
|
||
import { isValidHistoryEntry } from './core/validation'
|
||
import { createJsonStore } from './jsonStore'
|
||
|
||
// Plain JSON in userData (portable build redirects userData next to the exe).
|
||
// Kept simple per the build plan; can migrate to better-sqlite3 later. Atomic
|
||
// writes, corruption backup, and caching come from the shared jsonStore (R1–R3).
|
||
// The row cap (HISTORY_MAX_ENTRIES) is shared with the renderer's optimistic list.
|
||
//
|
||
// Per-entry validation (isValidHistoryEntry) so a hand-edited or corrupted
|
||
// history.json can't feed the UI (or openPath) entries with the wrong shape —
|
||
// invalid rows are dropped rather than trusted. (audit S5)
|
||
const store = createJsonStore('history.json', isValidHistoryEntry, HISTORY_MAX_ENTRIES)
|
||
|
||
export function listHistory(): HistoryEntry[] {
|
||
return store.read()
|
||
}
|
||
|
||
export function addHistory(entry: HistoryEntry): HistoryEntry[] {
|
||
// De-dupe by id AND url (M35): a History re-download re-queues via addFromUrl,
|
||
// which mints a NEW id, so id-only de-dup would let the same video accumulate a
|
||
// fresh row on every re-download. Dropping any prior entry with the same url
|
||
// keeps one row per video, refreshed to the top.
|
||
const prior = listHistory().filter((e) => e.id !== entry.id && e.url !== entry.url)
|
||
return store.write([entry, ...prior])
|
||
}
|
||
|
||
export function removeHistory(id: string): HistoryEntry[] {
|
||
return store.write(listHistory().filter((e) => e.id !== id))
|
||
}
|
||
|
||
export function removeManyHistory(ids: string[]): HistoryEntry[] {
|
||
const remove = new Set(ids)
|
||
return store.write(listHistory().filter((e) => !remove.has(e.id)))
|
||
}
|
||
|
||
export function clearHistory(): HistoryEntry[] {
|
||
return store.write([])
|
||
}
|