feat(diagnostics): persist full stderr detail behind a "Show details" toggle

describeDownloadError condenses a postprocessing failure to one line for
the queue/notification, discarding the rest of yt-dlp's stderr. The
persisted error log now also keeps the fuller non-noise transcript
(stderrDetail) as an optional `detail` field, and the Diagnostics card
gets a collapsible "Show details" expander per row so a failure like
"Postprocessing: Conversion failed!" can be inspected -- and copied
into a bug report -- without re-running the download from a terminal.
This commit is contained in:
2026-07-05 14:56:09 -04:00
parent 6cb9c5ca47
commit 27cae28e12
9 changed files with 155 additions and 17 deletions
+36 -1
View File
@@ -1,5 +1,5 @@
import { describe, it, expect } from 'vitest'
import { cleanError, describeDownloadError } from '../src/main/log'
import { cleanError, describeDownloadError, stderrDetail } from '../src/main/log'
describe('cleanError', () => {
it('returns the last ERROR line, stripped of its prefix', () => {
@@ -76,3 +76,38 @@ describe('describeDownloadError', () => {
expect(describeDownloadError('')).toBe('')
})
})
describe('stderrDetail', () => {
it('keeps the full non-noise transcript for the Diagnostics "Show details" expander', () => {
const stderr = [
'[info] qkUTB65OfAc: Downloading 1 format(s): 137+251',
'[SponsorBlock] Found 1 segments in the SponsorBlock database',
'[ModifyChapters] Re-encoding "video.mp4" with appropriate keyframes',
'ERROR: Postprocessing: Conversion failed!'
].join('\n')
const detail = stderrDetail(stderr)
expect(detail).toContain('[SponsorBlock] Found 1 segments')
expect(detail).toContain('[ModifyChapters] Re-encoding')
expect(detail).toContain('ERROR: Postprocessing: Conversion failed!')
})
it('strips [download] progress ticks and "Deleting original file" bookkeeping', () => {
const stderr = [
'[download] 42.0% of 23.21MiB at 15.11MiB/s ETA 00:00',
'Deleting original file video.f251.webm (pass -k to keep)',
'[ModifyChapters] Re-encoding "video.mp4" with appropriate keyframes',
'ERROR: Postprocessing: Conversion failed!'
].join('\n')
const detail = stderrDetail(stderr)
expect(detail).not.toMatch(/\[download\]/)
expect(detail).not.toContain('Deleting original file')
})
it('returns undefined when there is nothing beyond a single headline', () => {
expect(stderrDetail('ERROR: Postprocessing: Conversion failed!')).toBeUndefined()
})
it('returns undefined for blank stderr', () => {
expect(stderrDetail('')).toBeUndefined()
})
})