feat(audit): Batch 10 — CC conventions (shared line-buffer, cleanError)
The contained consistency consolidations; the sweeping ones are deferred with their standard documented (they're the audit's own post-1.0 refactors, and several would be reckless to do unattended). Landed: - src/main/lib/lineBuffer.ts (createLineBuffer): one newline line-splitter for streamed child-process output, replacing the duplicated buffer loop in download.ts and terminal.ts (CC3/CC4/SIMP5). Pure + unit-tested (test/lineBuffer.test.ts, 7 cases: partial lines, CRLF, empty lines, flush, multi-line chunks). download.ts keeps byte-identical marker parsing and no close-flush (yt-dlp template lines are always newline-terminated). - ytdlp.ts: getYtdlpVersion/updateYtdlp now run stderr through cleanError, the same `cleanError(r.stderr) || r.error?.message || ''` idiom already used by download/probe/indexer (CC6) — a failed check shows the trailing error line. - CL6 resolved: the one real redundancy was L15; clearDir/openFile/showInFolder are deliberate view-model wrappers (CC13), left as-is. Deferred with documented standard + rationale (CODE-AUDIT.md): CC1 (breaking persisted-key rename → migration), CC5+CL4 (security-critical updater net.request, not live-verifiable here), CC7 (cosmetic arg-order), CC9 (zod dep), CC10 (electron-store↔jsonStore split is deliberate for DPAPI), CC11 (config.ts move), CC12 (file-tree reorg), CC13→L93, CC14→L142. Verified: typecheck (node+web) + 275 tests + eslint + production build green; touched files prettier-clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+21
-21
@@ -15,6 +15,7 @@ import {
|
||||
} from './binaries'
|
||||
import { getSettings } from './settings'
|
||||
import { execFileAsync } from './lib/exec'
|
||||
import { createLineBuffer } from './lib/lineBuffer'
|
||||
import { getDownloadArchivePath, getDefaultMediaDir } from './paths'
|
||||
import { ensureManagedYtdlp } from './ytdlp'
|
||||
import { materializeCookies, hasStoredCookies } from './cookies'
|
||||
@@ -372,7 +373,6 @@ function wireChildProcess(params: {
|
||||
const { wc, opts, rec, cleanup, getTitle } = params
|
||||
const child = rec.child
|
||||
|
||||
let stdoutBuf = ''
|
||||
let stderrTail = ''
|
||||
let filePath: string | undefined
|
||||
// Latched once the first download stream reports 'finished'; flags later
|
||||
@@ -415,28 +415,28 @@ function wireChildProcess(params: {
|
||||
}
|
||||
bumpWatchdog()
|
||||
|
||||
// Split stdout into lines (shared helper, CC3/CC4) and parse our --print markers.
|
||||
// No flush on close: yt-dlp's progress/path template lines are always
|
||||
// newline-terminated, so a trailing partial is never a real marker.
|
||||
const stdoutLines = createLineBuffer((line) => {
|
||||
if (line.startsWith(PROGRESS_MARKER)) {
|
||||
const p = parseProgress(line.slice(PROGRESS_MARKER.length))
|
||||
if (p) {
|
||||
// SR7: yt-dlp reports a 'finished' status when each download stream
|
||||
// completes. A video+audio download has two streams, so the bar would
|
||||
// otherwise fill 0→100% twice. Latch on the first 'finished' and flag
|
||||
// every later tick as "finishing" so the renderer shows an indeterminate
|
||||
// merge state instead of a visible restart.
|
||||
if (p.status === 'finished') finishing = true
|
||||
send(wc, { type: 'progress', id: opts.id, progress: { ...p, finishing } })
|
||||
}
|
||||
} else if (line.startsWith(FILEPATH_MARKER)) {
|
||||
filePath = line.slice(FILEPATH_MARKER.length).trim()
|
||||
}
|
||||
})
|
||||
child.stdout?.on('data', (chunk: Buffer) => {
|
||||
bumpWatchdog()
|
||||
stdoutBuf += chunk.toString()
|
||||
let nl: number
|
||||
while ((nl = stdoutBuf.indexOf('\n')) >= 0) {
|
||||
const line = stdoutBuf.slice(0, nl).replace(/\r$/, '')
|
||||
stdoutBuf = stdoutBuf.slice(nl + 1)
|
||||
if (line.startsWith(PROGRESS_MARKER)) {
|
||||
const p = parseProgress(line.slice(PROGRESS_MARKER.length))
|
||||
if (p) {
|
||||
// SR7: yt-dlp reports a 'finished' status when each download stream
|
||||
// completes. A video+audio download has two streams, so the bar would
|
||||
// otherwise fill 0→100% twice. Latch on the first 'finished' and flag
|
||||
// every later tick as "finishing" so the renderer shows an indeterminate
|
||||
// merge state instead of a visible restart.
|
||||
if (p.status === 'finished') finishing = true
|
||||
send(wc, { type: 'progress', id: opts.id, progress: { ...p, finishing } })
|
||||
}
|
||||
} else if (line.startsWith(FILEPATH_MARKER)) {
|
||||
filePath = line.slice(FILEPATH_MARKER.length).trim()
|
||||
}
|
||||
}
|
||||
stdoutLines.push(chunk.toString())
|
||||
})
|
||||
|
||||
child.stderr?.on('data', (chunk: Buffer) => {
|
||||
|
||||
Reference in New Issue
Block a user