mirror of
https://github.com/nimbold/Firelink.git
synced 2026-07-26 12:08:27 +00:00
fix(media): quote forwarded cookie headers
Keep yt-dlp config values intact and require explicit media metadata before downloads can start.
This commit is contained in:
+22
-6
@@ -1110,8 +1110,13 @@ fn append_ytdlp_config_option(config: &mut String, option: &str, value: &str) {
|
||||
let safe_value = sanitize_ytdlp_config_value(value);
|
||||
if !safe_value.is_empty() {
|
||||
config.push_str(option);
|
||||
config.push('\n');
|
||||
config.push_str(&safe_value);
|
||||
config.push(' ');
|
||||
// yt-dlp parses one configuration line at a time. Quoting keeps
|
||||
// whitespace and cookie delimiters inside this option's single value,
|
||||
// rather than turning them into additional input URLs.
|
||||
config.push('\'');
|
||||
config.push_str(&safe_value.replace('\'', "'\\''"));
|
||||
config.push('\'');
|
||||
config.push('\n');
|
||||
}
|
||||
}
|
||||
@@ -4676,7 +4681,8 @@ fn set_extension_frontend_ready(state: tauri::State<'_, AppState>, ready: bool)
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{
|
||||
aggregate_media_fraction, append_ytdlp_http_headers, build_media_format_options,
|
||||
aggregate_media_fraction, append_ytdlp_config_option, append_ytdlp_http_headers,
|
||||
build_media_format_options,
|
||||
collect_download_uris, drain_media_output_lines, filename_from_content_disposition,
|
||||
filename_from_url_disposition_query, filename_from_url_path, is_excluded_yt_dlp_format,
|
||||
is_browser_cookie_extraction_error, json_lower, media_metadata_cache_key,
|
||||
@@ -4731,12 +4737,22 @@ mod tests {
|
||||
append_ytdlp_http_headers(
|
||||
&mut config,
|
||||
Some("Referer: https://example.com/video"),
|
||||
Some("session=abc\r\n--proxy=http://bad.invalid"),
|
||||
Some("session=abc; preference=high\r\n--proxy=http://bad.invalid"),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert!(config.contains("--add-header\nReferer: https://example.com/video\n"));
|
||||
assert!(config.contains("--add-header\nCookie: session=abc--proxy=http://bad.invalid\n"));
|
||||
assert_eq!(
|
||||
config,
|
||||
"--add-header 'Referer: https://example.com/video'\n--add-header 'Cookie: session=abc; preference=high--proxy=http://bad.invalid'\n"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ytdlp_config_options_quote_embedded_single_quotes() {
|
||||
let mut config = String::new();
|
||||
append_ytdlp_config_option(&mut config, "--username", "sam's account");
|
||||
|
||||
assert_eq!(config, "--username 'sam'\\''s account'\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -791,6 +791,10 @@ export const AddDownloadsModal = () => {
|
||||
: 'Unknown';
|
||||
const canSubmit = canSubmitMetadataRows(parsedItems);
|
||||
const failedMetadataCount = parsedItems.filter(item => item.status === 'metadata-error').length;
|
||||
const failedMediaMetadataCount = parsedItems.filter(
|
||||
item => item.status === 'metadata-error' && item.isMedia
|
||||
).length;
|
||||
const fallbackMetadataCount = failedMetadataCount - failedMediaMetadataCount;
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -844,7 +848,7 @@ export const AddDownloadsModal = () => {
|
||||
/>
|
||||
<div className="flex justify-between items-center px-1">
|
||||
<span className="text-[11px] text-text-muted font-medium">
|
||||
{parsedItems.filter(item => item.status === 'ready').length} ready, {failedMetadataCount} fallback
|
||||
{parsedItems.filter(item => item.status === 'ready').length} ready, {fallbackMetadataCount} fallback, {failedMediaMetadataCount} media retry
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
@@ -910,7 +914,7 @@ export const AddDownloadsModal = () => {
|
||||
</div>
|
||||
) : (
|
||||
item.status === 'metadata-error'
|
||||
? 'Fallback'
|
||||
? item.isMedia ? 'Metadata failed' : 'Fallback'
|
||||
: item.status === 'invalid'
|
||||
? 'Invalid'
|
||||
: 'Ready'
|
||||
@@ -987,7 +991,7 @@ export const AddDownloadsModal = () => {
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col items-center justify-center py-4 relative z-10">
|
||||
<span className="text-xs text-red-400 font-medium">Metadata unavailable. Default media format will be used.</span>
|
||||
<span className="text-xs text-red-400 font-medium">Metadata unavailable. Refresh metadata before adding this media.</span>
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
|
||||
@@ -187,11 +187,15 @@ describe('add download metadata workflow', () => {
|
||||
expect(updated[0]).toBe(current);
|
||||
});
|
||||
|
||||
it('allows ready and failed rows but blocks loading and invalid rows', () => {
|
||||
it('allows normal-download fallback but blocks unresolved explicit media', () => {
|
||||
expect(canSubmitMetadataRows([
|
||||
row(),
|
||||
row({ id: 'fallback', status: 'metadata-error' })
|
||||
])).toBe(true);
|
||||
expect(canSubmitMetadataRows([
|
||||
row(),
|
||||
row({ id: 'media-fallback', status: 'metadata-error', isMedia: true })
|
||||
])).toBe(false);
|
||||
expect(canSubmitMetadataRows([row({ status: 'loading' })])).toBe(false);
|
||||
expect(canSubmitMetadataRows([row({ status: 'invalid' })])).toBe(false);
|
||||
});
|
||||
@@ -246,6 +250,9 @@ describe('add download metadata workflow', () => {
|
||||
expect(metadataSummaryMessage([
|
||||
row({ status: 'metadata-error' })
|
||||
])).toContain('can still be added');
|
||||
expect(metadataSummaryMessage([
|
||||
row({ status: 'metadata-error', isMedia: true })
|
||||
])).toContain('Refresh metadata before adding');
|
||||
expect(metadataSummaryMessage([
|
||||
row({ status: 'invalid' })
|
||||
])).toContain('Correct or remove 1 invalid URL');
|
||||
|
||||
@@ -146,7 +146,10 @@ export const refreshFailedMetadataRows = (
|
||||
|
||||
export const canSubmitMetadataRows = (rows: AddDownloadDraftRow[]): boolean =>
|
||||
rows.length > 0
|
||||
&& rows.every(row => row.status === 'ready' || row.status === 'metadata-error');
|
||||
&& rows.every(row =>
|
||||
row.status === 'ready'
|
||||
|| (!row.isMedia && row.status === 'metadata-error')
|
||||
);
|
||||
|
||||
export const mediaFormatSelectorForRow = (
|
||||
row: AddDownloadDraftRow
|
||||
@@ -203,7 +206,11 @@ export const metadataSummaryMessage = (rows: AddDownloadDraftRow[]): string => {
|
||||
}
|
||||
|
||||
const failed = rows.filter(row => row.status === 'metadata-error').length;
|
||||
const failedMedia = rows.filter(row => row.status === 'metadata-error' && row.isMedia).length;
|
||||
const ready = rows.filter(row => row.status === 'ready').length;
|
||||
if (failedMedia > 0) {
|
||||
return `Media metadata is unavailable for ${failedMedia} item${failedMedia === 1 ? '' : 's'}. Refresh metadata before adding.`;
|
||||
}
|
||||
if (failed === rows.length) {
|
||||
return 'Metadata is unavailable. Downloads can still be added using fallback details.';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user