mirror of
https://github.com/nimbold/Firelink.git
synced 2026-08-06 17:38:06 +00:00
fix(downloads): harden capture and media flows
Scope extension request context to each Add modal row, refresh stale metadata handoffs, and align yt-dlp format and retry behavior with Firelink's transfer contract.
This commit is contained in:
@@ -71,6 +71,59 @@ describe('add download metadata workflow', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('keeps extension-provided filenames scoped to their individual URLs', () => {
|
||||
const rows = reconcileDownloadRows(
|
||||
'https://first.example/download\nhttps://second.example/download',
|
||||
[],
|
||||
undefined,
|
||||
new Set(),
|
||||
() => crypto.randomUUID(),
|
||||
{
|
||||
'https://first.example/download': 'first.zip',
|
||||
'https://second.example/download': 'second.zip'
|
||||
}
|
||||
);
|
||||
|
||||
expect(rows.map(item => item.file)).toEqual(['first.zip', 'second.zip']);
|
||||
});
|
||||
|
||||
it('refreshes an existing row when a newer extension handoff changes its request context', () => {
|
||||
const existing = row({
|
||||
isMedia: true,
|
||||
status: 'ready',
|
||||
generation: 4,
|
||||
requestContextVersion: 1,
|
||||
formats: [{
|
||||
name: '1080p MP4',
|
||||
selector: '137+140',
|
||||
ext: 'mp4',
|
||||
formatLabel: 'MP4',
|
||||
detail: '10 MB',
|
||||
type: 'Video',
|
||||
bytes: 10
|
||||
}],
|
||||
selectedFormat: 0
|
||||
});
|
||||
|
||||
const refreshed = reconcileDownloadRows(
|
||||
existing.sourceUrl,
|
||||
[existing],
|
||||
undefined,
|
||||
new Set(),
|
||||
() => 'unused',
|
||||
{},
|
||||
{ [existing.sourceUrl]: 2 }
|
||||
);
|
||||
|
||||
expect(refreshed[0]).toMatchObject({
|
||||
status: 'loading',
|
||||
generation: 5,
|
||||
requestContextVersion: 2,
|
||||
formats: undefined,
|
||||
selectedFormat: undefined
|
||||
});
|
||||
});
|
||||
|
||||
it('upgrades an existing normal row when the user explicitly fetches it as media', () => {
|
||||
const existing = row({
|
||||
sourceUrl: 'https://adult.example/watch/123',
|
||||
|
||||
@@ -26,6 +26,7 @@ export interface AddDownloadDraftRow {
|
||||
sizeBytes?: number;
|
||||
status: MetadataStatus;
|
||||
generation: number;
|
||||
requestContextVersion?: number;
|
||||
isMedia: boolean;
|
||||
resumable?: boolean;
|
||||
formats?: AddMediaFormat[];
|
||||
@@ -72,7 +73,9 @@ export const reconcileDownloadRows = (
|
||||
currentRows: AddDownloadDraftRow[],
|
||||
pendingFilename?: string,
|
||||
forceMediaUrls: ReadonlySet<string> = new Set(),
|
||||
createId: () => string = () => crypto.randomUUID()
|
||||
createId: () => string = () => crypto.randomUUID(),
|
||||
requestFilenames: Readonly<Record<string, string>> = {},
|
||||
requestContextVersions: Readonly<Record<string, number>> = {}
|
||||
): AddDownloadDraftRow[] => {
|
||||
const inputs = parseInputLines(rawText);
|
||||
const existing = new Map(currentRows.map(row => [row.sourceUrl, row]));
|
||||
@@ -80,23 +83,28 @@ export const reconcileDownloadRows = (
|
||||
return inputs.map(input => {
|
||||
const preserved = existing.get(input.sourceUrl);
|
||||
if (preserved) {
|
||||
if (input.valid && forceMediaUrls.has(input.sourceUrl) && !preserved.isMedia) {
|
||||
const forcedMedia = input.valid && forceMediaUrls.has(input.sourceUrl);
|
||||
const requestContextVersion = requestContextVersions[input.sourceUrl];
|
||||
const contextChanged = requestContextVersion !== undefined
|
||||
&& requestContextVersion !== preserved.requestContextVersion;
|
||||
if ((forcedMedia && !preserved.isMedia) || contextChanged) {
|
||||
return {
|
||||
...preserved,
|
||||
status: 'loading',
|
||||
generation: preserved.generation + 1,
|
||||
isMedia: true,
|
||||
formats: undefined,
|
||||
selectedFormat: undefined
|
||||
requestContextVersion,
|
||||
isMedia: preserved.isMedia || forcedMedia,
|
||||
formats: preserved.isMedia || forcedMedia ? undefined : preserved.formats,
|
||||
selectedFormat: preserved.isMedia || forcedMedia ? undefined : preserved.selectedFormat
|
||||
};
|
||||
}
|
||||
return preserved;
|
||||
}
|
||||
|
||||
const requestedFilename = requestFilenames[input.sourceUrl]
|
||||
|| (inputs.length === 1 ? pendingFilename : undefined);
|
||||
const fallback = canonicalizeDownloadFileName(
|
||||
inputs.length === 1 && pendingFilename
|
||||
? pendingFilename
|
||||
: fileNameFromUrl(input.sourceUrl)
|
||||
requestedFilename || fileNameFromUrl(input.sourceUrl)
|
||||
);
|
||||
|
||||
return {
|
||||
@@ -106,6 +114,7 @@ export const reconcileDownloadRows = (
|
||||
file: fallback,
|
||||
status: input.valid ? 'loading' : 'invalid',
|
||||
generation: input.valid ? 1 : 0,
|
||||
requestContextVersion: requestContextVersions[input.sourceUrl],
|
||||
isMedia: input.valid && (forceMediaUrls.has(input.sourceUrl) || isMediaUrl(input.sourceUrl))
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user