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)
if (segments.length > WHOLE_MAX_PARTS || bytes > WHOLE_MAX_BYTES) return null
if (segments.length === 1) return first
let assembled: YencFile | undefined
for (const part of segments) {
const segment = decodeSegment(await fetch(part.id), { lenientSize: true })
assembled ??= YencFile.fromSegment(segment)
assembled.add(segment)
}
return assembled!.getBuffer()
if (segments.length === 1) return first.data
const assembled = YencFile.fromSegment(first)
assembled.add(first)
for (const part of segments.slice(1)) assembled.add(decodeSegment(await fetch(part.id), { lenientSize: true }))
return assembled.getBuffer()
}
/** 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> {
if (!isPar2(first)) return null
export async function readPar2(first: DecodedSegment, segments: TaskSegment[], fetch: BodyFetcher): Promise<Par2Set | null> {
if (!isPar2(first.data)) return null
if (segments.length > PAR2_MAX_PARTS) return null
if (segments.length === 1) return parsePar2(first)
let assembled: YencFile | undefined
for (const part of segments) {
const segment = decodeSegment(await fetch(part.id))
assembled ??= YencFile.fromSegment(segment)
assembled.add(segment)
}
return parsePar2(assembled!.getBuffer())
if (segments.length === 1) return parsePar2(first.data)
const assembled = YencFile.fromSegment(first)
assembled.add(first)
for (const part of segments.slice(1)) assembled.add(decodeSegment(await fetch(part.id)))
return parsePar2(assembled.getBuffer())
}
export function isNzbEntry(entry: Pick<RarEntry, 'name' | 'encrypted' | 'directory'>): boolean {
@@ -151,14 +148,14 @@ export async function probeInspection(
return probe
}
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
}
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
}
probe.par2 = await readPar2(segment.data, task.segments, fetch)
probe.par2 = await readPar2(segment, task.segments, fetch)
if (probe.par2) return probe
if (contentType === '7z') {
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
if (info && hasNzbEntries(info)) {
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 entries = archived ? archived.entries.filter(isNzbEntry) : []
probe.archiveNzbEntries = entries.length
+2 -1
View File
@@ -59,7 +59,8 @@ test.group('content probe', () => {
const probe = await probeInspection(task, fetch)
assert.equal(probe.contentType, 'nzb')
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 }) => {