- new storeDb.ts: DB+FS layer (folders w/ parent_id, videos w/ global id)
- depth cap: sub-folder cannot have children (enforced in createFolder)
- video id: editable anytime (changeVideoId), uniqueness via PK
- routes:
- public /folder/:topName[/:subName], /video/:topName[/:subName]/:videoId
- admin /op/folder/:topName[/:subName], id-based /op/folders/:id/*
and /op/videos/:id/* (rename/changeId/delete/save + idAvailable check)
- views: breadcrumb + subFolder grid; 플레이리스트 추가 button shows at 2단계
- client JS: id-based mutation endpoints, share URL data attribute,
in-site player pushes share URL to address bar
- store.ts slimmed to Account + readAccounts (FS layer moved to storeDb)
- pickIntId accepts numeric JSON bodies
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
24 lines
732 B
TypeScript
24 lines
732 B
TypeScript
import { promises as fs } from 'node:fs'
|
|
import { accountJsonPath } from './paths.js'
|
|
|
|
export interface Account {
|
|
id: string
|
|
password: string
|
|
}
|
|
|
|
/** account.json 에서 로그인 계정 목록을 읽는다. (나머지 파일 기반 저장소는 storeDb.ts 로 이전됨.) */
|
|
export async function readAccounts(): Promise<Account[]> {
|
|
try {
|
|
const raw = await fs.readFile(accountJsonPath, 'utf8')
|
|
const parsed = JSON.parse(raw)
|
|
if (!Array.isArray(parsed)) return []
|
|
return parsed.filter(
|
|
(entry): entry is Account =>
|
|
typeof entry?.id === 'string' && typeof entry?.password === 'string'
|
|
)
|
|
} catch (err) {
|
|
if ((err as NodeJS.ErrnoException).code === 'ENOENT') return []
|
|
throw err
|
|
}
|
|
}
|