diff --git a/package.json b/package.json index 3e2ae2a..7df4e5a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "real-debrid-downloader", - "version": "1.6.36", + "version": "1.6.37", "description": "Desktop downloader", "main": "build/main/main/main.js", "author": "Sucukdeluxe", diff --git a/src/main/debrid.ts b/src/main/debrid.ts index c9dd0ee..12ba2b0 100644 --- a/src/main/debrid.ts +++ b/src/main/debrid.ts @@ -1212,6 +1212,27 @@ export class DebridService { public async unrestrictLink(link: string, signal?: AbortSignal, settingsSnapshot?: AppSettings): Promise { const settings = settingsSnapshot ? cloneSettings(settingsSnapshot) : cloneSettings(this.settings); + + // DDownload is a direct file hoster, not a debrid service. + // If the link is a ddownload.com/ddl.to URL and the account is configured, + // use DDownload directly before trying any debrid providers. + if (DDOWNLOAD_URL_RE.test(link) && this.isProviderConfiguredFor(settings, "ddownload")) { + try { + const result = await this.unrestrictViaProvider(settings, "ddownload", link, signal); + return { + ...result, + provider: "ddownload", + providerLabel: PROVIDER_LABELS["ddownload"] + }; + } catch (error) { + const errorText = compactErrorText(error); + if (signal?.aborted || (/aborted/i.test(errorText) && !/timeout/i.test(errorText))) { + throw error; + } + // Fall through to normal provider chain (debrid services may also support ddownload links) + } + } + const order = toProviderOrder( settings.providerPrimary, settings.providerSecondary, diff --git a/src/main/storage.ts b/src/main/storage.ts index 9f7fbf5..cc6838a 100644 --- a/src/main/storage.ts +++ b/src/main/storage.ts @@ -5,8 +5,8 @@ import { AppSettings, BandwidthScheduleEntry, DebridProvider, DownloadItem, Down import { defaultSettings } from "./constants"; import { logger } from "./logger"; -const VALID_PRIMARY_PROVIDERS = new Set(["realdebrid", "megadebrid", "bestdebrid", "alldebrid", "ddownload"]); -const VALID_FALLBACK_PROVIDERS = new Set(["none", "realdebrid", "megadebrid", "bestdebrid", "alldebrid", "ddownload"]); +const VALID_PRIMARY_PROVIDERS = new Set(["realdebrid", "megadebrid", "bestdebrid", "alldebrid"]); +const VALID_FALLBACK_PROVIDERS = new Set(["none", "realdebrid", "megadebrid", "bestdebrid", "alldebrid"]); const VALID_CLEANUP_MODES = new Set(["none", "trash", "delete"]); const VALID_CONFLICT_MODES = new Set(["overwrite", "skip", "rename", "ask"]); const VALID_FINISHED_POLICIES = new Set(["never", "immediate", "on_start", "package_done"]); diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index 1182b83..63d7755 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -928,11 +928,17 @@ export function App(): ReactElement { if (settingsDraft.allDebridToken.trim()) { list.push("alldebrid"); } - if ((settingsDraft.ddownloadLogin || "").trim() && (settingsDraft.ddownloadPassword || "").trim()) { - list.push("ddownload"); - } return list; - }, [settingsDraft.token, settingsDraft.megaLogin, settingsDraft.megaPassword, settingsDraft.bestToken, settingsDraft.allDebridToken, settingsDraft.ddownloadLogin, settingsDraft.ddownloadPassword]); + }, [settingsDraft.token, settingsDraft.megaLogin, settingsDraft.megaPassword, settingsDraft.bestToken, settingsDraft.allDebridToken]); + + // DDownload is a direct file hoster (not a debrid service) and is used automatically + // for ddownload.com/ddl.to URLs. It counts as a configured account but does not + // appear in the primary/secondary/tertiary provider dropdowns. + const hasDdownloadAccount = useMemo(() => + Boolean((settingsDraft.ddownloadLogin || "").trim() && (settingsDraft.ddownloadPassword || "").trim()), + [settingsDraft.ddownloadLogin, settingsDraft.ddownloadPassword]); + + const totalConfiguredAccounts = configuredProviders.length + (hasDdownloadAccount ? 1 : 0); const primaryProviderValue: DebridProvider = useMemo(() => { if (configuredProviders.includes(settingsDraft.providerPrimary)) { @@ -1112,7 +1118,7 @@ export function App(): ReactElement { const onStartDownloads = async (): Promise => { await performQuickAction(async () => { - if (configuredProviders.length === 0) { + if (totalConfiguredAccounts === 0) { setTab("settings"); showToast("Bitte zuerst mindestens einen Hoster-Account eintragen", 3000); return; @@ -2956,7 +2962,7 @@ export function App(): ReactElement { Links: {Object.keys(snapshot.session.items).length} Session: {humanSize(snapshot.stats.totalDownloaded)} Gesamt: {humanSize(snapshot.stats.totalDownloadedAllTime)} - Hoster: {configuredProviders.length} + Hoster: {totalConfiguredAccounts} {snapshot.speedText} {snapshot.etaText}