diff --git a/src/App.tsx b/src/App.tsx
index 647829a..12bd593 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -44,13 +44,17 @@ const getScheduledQueueIds = () => {
type AudioContextConstructor = typeof AudioContext;
-const playCompletionChime = () => {
+const playCompletionChime = async () => {
const AudioCtor =
window.AudioContext ||
(window as Window & { webkitAudioContext?: AudioContextConstructor }).webkitAudioContext;
if (!AudioCtor) return;
const context = new AudioCtor();
+ if (context.state === 'suspended') {
+ await context.resume();
+ }
+
const oscillator = context.createOscillator();
const gain = context.createGain();
oscillator.type = 'sine';
@@ -551,11 +555,9 @@ function App() {
if (event.payload.status !== 'completed' && event.payload.status !== 'failed') return;
const settings = useSettingsStore.getState();
if (event.payload.status === 'completed' && settings.playCompletionSound) {
- try {
- playCompletionChime();
- } catch (error) {
+ playCompletionChime().catch(error => {
console.error('Completion sound failed:', error);
- }
+ });
}
if (!settings.showNotifications) return;
diff --git a/src/components/AddDownloadsModal.tsx b/src/components/AddDownloadsModal.tsx
index 917a2d5..544a648 100644
--- a/src/components/AddDownloadsModal.tsx
+++ b/src/components/AddDownloadsModal.tsx
@@ -37,6 +37,16 @@ const formatBytes = (bytes: number) => {
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
};
+const isCrossHostRedirect = (sourceUrl: string, downloadUrl: string) => {
+ try {
+ const sourceHost = new URL(sourceUrl).hostname;
+ const downloadHost = new URL(downloadUrl).hostname;
+ return downloadHost !== sourceHost && !downloadHost.endsWith(`.${sourceHost}`);
+ } catch {
+ return false;
+ }
+};
+
export const AddDownloadsModal = () => {
const { addToast } = useToast();
const {
@@ -85,6 +95,7 @@ export const AddDownloadsModal = () => {
const [checksumValue, setChecksumValue] = useState('');
const [headers, setHeaders] = useState('');
const [cookies, setCookies] = useState('');
+ const cookiesFromExtensionRef = useRef(false);
const [mirrors, setMirrors] = useState('');
useEffect(() => {
@@ -111,6 +122,7 @@ export const AddDownloadsModal = () => {
pendingAddHeaders
].filter(Boolean).join('\n'));
setCookies(pendingAddCookies);
+ cookiesFromExtensionRef.current = Boolean(pendingAddCookies?.trim());
setMirrors('');
setIsQueueMenuOpen(false);
setIsSubmitting(false);
@@ -251,6 +263,11 @@ export const AddDownloadsModal = () => {
headers: headers?.trim() || null,
cookies: cookies?.trim() || null
});
+ const nextDownloadUrl = meta.url || row.sourceUrl;
+ if (cookiesFromExtensionRef.current && isCrossHostRedirect(row.sourceUrl, nextDownloadUrl)) {
+ setCookies('');
+ cookiesFromExtensionRef.current = false;
+ }
setParsedItems(current => updateRowIfCurrent(
current,
row.id,
@@ -258,7 +275,7 @@ export const AddDownloadsModal = () => {
row.generation,
currentRow => ({
...currentRow,
- downloadUrl: meta.url || currentRow.downloadUrl,
+ downloadUrl: nextDownloadUrl || currentRow.downloadUrl,
file: canonicalizeDownloadFileName(
current.length === 1 && pendingAddFilename
? pendingAddFilename
@@ -1008,7 +1025,17 @@ export const AddDownloadsModal = () => {
- setCookies(e.target.value)} placeholder="name=value; other=value" className="add-download-control w-full px-3 py-1.5 text-xs font-mono" aria-label="Cookies" />
+ {
+ cookiesFromExtensionRef.current = false;
+ setCookies(e.target.value);
+ }}
+ placeholder="name=value; other=value"
+ className="add-download-control w-full px-3 py-1.5 text-xs font-mono"
+ aria-label="Cookies"
+ />
diff --git a/src/components/SettingsView.tsx b/src/components/SettingsView.tsx
index 5c946ed..3f3d5d3 100644
--- a/src/components/SettingsView.tsx
+++ b/src/components/SettingsView.tsx
@@ -639,8 +639,8 @@ runEngineChecks(false);