Content probe: don't download the first segment again for whole files
Test and deploy / test (push) Successful in 1m34s
Test and deploy / deploy (push) Successful in 1m40s

Par2 sets, NZBs and SFVs were sniffed from their first segment and then
read whole, downloading that segment a second time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Daan MeijerandClaude Opus 5.5 committed 2026-10-06 23:37:26 +02:00
1 parent 23bbdcc5ee
commit bef68075be
2 files changed
+23 -25

No files matched your search

+21 -24
View File
@@ -93,32 +93,29 @@ export function decodeBody(body: Buffer): DecodedSegment {
} }
} }
/** All of a (small) file whose first segment is already decoded; null when it is too big. */ /**
export async function readWhole(first: Buffer, segments: TaskSegment[], fetch: BodyFetcher): Promise<Buffer | null> { * All of a (small) file whose first segment is already decoded; null when it is too big.
* The first segment isn't downloaded again (it was, for every par2 set, NZB and SFV).
*/
export async function readWhole(first: DecodedSegment, segments: TaskSegment[], fetch: BodyFetcher): Promise<Buffer | null> {
const bytes = segments.reduce((sum, p) => sum + (p.size ?? 0), 0) const bytes = segments.reduce((sum, p) => sum + (p.size ?? 0), 0)
if (segments.length > WHOLE_MAX_PARTS || bytes > WHOLE_MAX_BYTES) return null if (segments.length > WHOLE_MAX_PARTS || bytes > WHOLE_MAX_BYTES) return null
if (segments.length === 1) return first if (segments.length === 1) return first.data
let assembled: YencFile | undefined const assembled = YencFile.fromSegment(first)
for (const part of segments) { assembled.add(first)
const segment = decodeSegment(await fetch(part.id), { lenientSize: true }) for (const part of segments.slice(1)) assembled.add(decodeSegment(await fetch(part.id), { lenientSize: true }))
assembled ??= YencFile.fromSegment(segment) return assembled.getBuffer()
assembled.add(segment)
}
return assembled!.getBuffer()
} }
/** A par2 file whose first segment is already decoded, with its other parts if any; null when it is not par2. */ /** A par2 file whose first segment is already decoded, with its other parts if any; null when it is not par2. */
export async function readPar2(first: Buffer, segments: TaskSegment[], fetch: BodyFetcher): Promise<Par2Set | null> { export async function readPar2(first: DecodedSegment, segments: TaskSegment[], fetch: BodyFetcher): Promise<Par2Set | null> {
if (!isPar2(first)) return null if (!isPar2(first.data)) return null
if (segments.length > PAR2_MAX_PARTS) return null if (segments.length > PAR2_MAX_PARTS) return null
if (segments.length === 1) return parsePar2(first) if (segments.length === 1) return parsePar2(first.data)
let assembled: YencFile | undefined const assembled = YencFile.fromSegment(first)
for (const part of segments) { assembled.add(first)
const segment = decodeSegment(await fetch(part.id)) for (const part of segments.slice(1)) assembled.add(decodeSegment(await fetch(part.id)))
assembled ??= YencFile.fromSegment(segment) return parsePar2(assembled.getBuffer())
assembled.add(segment)
}
return parsePar2(assembled!.getBuffer())
} }
export function isNzbEntry(entry: Pick<RarEntry, 'name' | 'encrypted' | 'directory'>): boolean { export function isNzbEntry(entry: Pick<RarEntry, 'name' | 'encrypted' | 'directory'>): boolean {
@@ -151,14 +148,14 @@ export async function probeInspection(
return probe return probe
} }
if (/\.sfv$/i.test(task.name)) { if (/\.sfv$/i.test(task.name)) {
probe.text = (await readWhole(segment.data, task.segments, fetch))?.toString('latin1') ?? null probe.text = (await readWhole(segment, task.segments, fetch))?.toString('latin1') ?? null
return probe return probe
} }
if (contentType === 'nzb') { if (contentType === 'nzb') {
probe.text = (await readWhole(segment.data, task.segments, fetch))?.toString('utf8') ?? null probe.text = (await readWhole(segment, task.segments, fetch))?.toString('utf8') ?? null
return probe return probe
} }
probe.par2 = await readPar2(segment.data, task.segments, fetch) probe.par2 = await readPar2(segment, task.segments, fetch)
if (probe.par2) return probe if (probe.par2) return probe
if (contentType === '7z') { if (contentType === '7z') {
probe.archive = task.sevenZip ? await listSevenZip(segment.data, task.sevenZip.volumes, task.sevenZip.last, fetch, warn) : null probe.archive = task.sevenZip ? await listSevenZip(segment.data, task.sevenZip.volumes, task.sevenZip.last, fetch, warn) : null
@@ -168,7 +165,7 @@ export async function probeInspection(
probe.archive = info probe.archive = info
if (info && hasNzbEntries(info)) { if (info && hasNzbEntries(info)) {
probe.archiveNzbs = [] probe.archiveNzbs = []
const archive = await readWhole(segment.data, task.segments, fetch) const archive = await readWhole(segment, task.segments, fetch)
const archived = archive && parseRarHeaders(archive) const archived = archive && parseRarHeaders(archive)
const entries = archived ? archived.entries.filter(isNzbEntry) : [] const entries = archived ? archived.entries.filter(isNzbEntry) : []
probe.archiveNzbEntries = entries.length probe.archiveNzbEntries = entries.length
+2 -1
View File
@@ -59,7 +59,8 @@ test.group('content probe', () => {
const probe = await probeInspection(task, fetch) const probe = await probeInspection(task, fetch)
assert.equal(probe.contentType, 'nzb') assert.equal(probe.contentType, 'nzb')
assert.equal(probe.text, xml) assert.equal(probe.text, xml)
assert.lengthOf(fetched, task.segments.length + 1) // the first segment twice: once to sniff, once in the whole // Every segment once: the first, decoded to sniff, is reused for the whole.
assert.deepEqual(fetched, task.segments.map((s) => s.id))
}) })
test('a 7z archive with encrypted headers is known from its tail, without bsdtar', async ({ assert }) => { test('a 7z archive with encrypted headers is known from its tail, without bsdtar', async ({ assert }) => {