feat: move default download directories to desktop
This commit is contained in:
@@ -301,6 +301,11 @@ This makes it easy to share one URL plus token during support, so current packag
|
|||||||
|
|
||||||
Detailed release history is published on [GitHub Releases](https://github.com/Sucukdeluxe/multi-debrid-downloader/releases).
|
Detailed release history is published on [GitHub Releases](https://github.com/Sucukdeluxe/multi-debrid-downloader/releases).
|
||||||
|
|
||||||
|
### 2.0.5
|
||||||
|
|
||||||
|
- Move the default download, extraction, and video collection directories to the desktop under `Multi-Debrid-Downloader`.
|
||||||
|
- Migrate untouched legacy default directories from `Downloads\RealDebrid` to the new desktop location.
|
||||||
|
|
||||||
### 2.0.4
|
### 2.0.4
|
||||||
|
|
||||||
- Rename the online backup action from "create" to "export" for clearer wording.
|
- Rename the online backup action from "create" to "export" for clearer wording.
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "real-debrid-downloader",
|
"name": "real-debrid-downloader",
|
||||||
"version": "2.0.4",
|
"version": "2.0.5",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "real-debrid-downloader",
|
"name": "real-debrid-downloader",
|
||||||
"version": "2.0.4",
|
"version": "2.0.5",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"adm-zip": "0.6.0",
|
"adm-zip": "0.6.0",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "real-debrid-downloader",
|
"name": "real-debrid-downloader",
|
||||||
"version": "2.0.4",
|
"version": "2.0.5",
|
||||||
"description": "Desktop downloader",
|
"description": "Desktop downloader",
|
||||||
"main": "build/main/main/main.js",
|
"main": "build/main/main/main.js",
|
||||||
"author": "Sucukdeluxe",
|
"author": "Sucukdeluxe",
|
||||||
|
|||||||
@@ -37,11 +37,11 @@ export const MAX_LINK_ARTIFACT_BYTES = 256 * 1024;
|
|||||||
export const SPEED_WINDOW_SECONDS = 1;
|
export const SPEED_WINDOW_SECONDS = 1;
|
||||||
export const CLIPBOARD_POLL_INTERVAL_MS = 2000;
|
export const CLIPBOARD_POLL_INTERVAL_MS = 2000;
|
||||||
|
|
||||||
export const DEFAULT_UPDATE_REPO = "Sucukdeluxe/multi-debrid-downloader";
|
export const DEFAULT_UPDATE_REPO = "Sucukdeluxe/multi-debrid-downloader";
|
||||||
export const ONLINE_BACKUP_API_URL = "https://downloader.24-music.de/backup-api";
|
export const ONLINE_BACKUP_API_URL = "https://downloader.24-music.de/backup-api";
|
||||||
|
|
||||||
export function defaultSettings(): AppSettings {
|
export function defaultSettings(): AppSettings {
|
||||||
const baseDir = path.join(os.homedir(), "Downloads", "RealDebrid");
|
const baseDir = path.join(os.homedir(), "Desktop", "Multi-Debrid-Downloader");
|
||||||
return {
|
return {
|
||||||
token: "",
|
token: "",
|
||||||
realDebridUseWebLogin: false,
|
realDebridUseWebLogin: false,
|
||||||
@@ -110,7 +110,7 @@ export function defaultSettings(): AppSettings {
|
|||||||
hideExtractedItems: true,
|
hideExtractedItems: true,
|
||||||
confirmDeleteSelection: true,
|
confirmDeleteSelection: true,
|
||||||
backupIncludeDownloads: false,
|
backupIncludeDownloads: false,
|
||||||
backupIncludeRemoteDiagnostics: false,
|
backupIncludeRemoteDiagnostics: false,
|
||||||
notifyUrl: "",
|
notifyUrl: "",
|
||||||
notifyMention: "",
|
notifyMention: "",
|
||||||
notifyOnPackageCompleted: false,
|
notifyOnPackageCompleted: false,
|
||||||
|
|||||||
+47
-15
@@ -1,5 +1,6 @@
|
|||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import fsp from "node:fs/promises";
|
import fsp from "node:fs/promises";
|
||||||
|
import os from "node:os";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { getDebridLinkApiKeyIds } from "../shared/debrid-link-keys";
|
import { getDebridLinkApiKeyIds } from "../shared/debrid-link-keys";
|
||||||
import { getMegaDebridAccountIds } from "../shared/mega-debrid-accounts";
|
import { getMegaDebridAccountIds } from "../shared/mega-debrid-accounts";
|
||||||
@@ -104,6 +105,36 @@ function normalizeAbsoluteDir(value: unknown, fallback: string): string {
|
|||||||
return path.resolve(text);
|
return path.resolve(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function samePath(left: unknown, right: string): boolean {
|
||||||
|
const leftText = asText(left);
|
||||||
|
if (!leftText) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const leftResolved = path.resolve(leftText);
|
||||||
|
const rightResolved = path.resolve(right);
|
||||||
|
return process.platform === "win32"
|
||||||
|
? leftResolved.toLowerCase() === rightResolved.toLowerCase()
|
||||||
|
: leftResolved === rightResolved;
|
||||||
|
}
|
||||||
|
|
||||||
|
function migrateLegacyDefaultDirectories(settings: AppSettings, defaults: AppSettings): AppSettings {
|
||||||
|
const legacyBaseDir = path.join(os.homedir(), "Downloads", "RealDebrid");
|
||||||
|
const legacyExtractDir = path.join(legacyBaseDir, "_entpackt");
|
||||||
|
const legacyMkvLibraryDir = path.join(legacyBaseDir, "_mkv");
|
||||||
|
const isUntouchedLegacyConfiguration = samePath(settings.outputDir, legacyBaseDir)
|
||||||
|
&& samePath(settings.extractDir, legacyExtractDir)
|
||||||
|
&& samePath(settings.mkvLibraryDir, legacyMkvLibraryDir);
|
||||||
|
if (!isUntouchedLegacyConfiguration) {
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...settings,
|
||||||
|
outputDir: defaults.outputDir,
|
||||||
|
extractDir: defaults.extractDir,
|
||||||
|
mkvLibraryDir: defaults.mkvLibraryDir
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const DEFAULT_COLUMN_ORDER = ["name", "size", "progress", "hoster", "account", "prio", "status", "speed"];
|
const DEFAULT_COLUMN_ORDER = ["name", "size", "progress", "hoster", "account", "prio", "status", "speed"];
|
||||||
const ALL_VALID_COLUMNS = new Set([...DEFAULT_COLUMN_ORDER, "added"]);
|
const ALL_VALID_COLUMNS = new Set([...DEFAULT_COLUMN_ORDER, "added"]);
|
||||||
|
|
||||||
@@ -328,22 +359,23 @@ function normalizeProviderOrder(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEPRECATED_UPDATE_REPO_NAMES = new Set([
|
const DEPRECATED_UPDATE_REPO_NAMES = new Set([
|
||||||
"real-debrid-downloader",
|
"real-debrid-downloader",
|
||||||
"multi-debrid-downloader"
|
"multi-debrid-downloader"
|
||||||
]);
|
]);
|
||||||
|
|
||||||
function migrateUpdateRepo(raw: string, fallback: string): string {
|
function migrateUpdateRepo(raw: string, fallback: string): string {
|
||||||
const trimmed = raw.trim();
|
const trimmed = raw.trim();
|
||||||
const repoName = trimmed.split("/").filter(Boolean).pop()?.replace(/\.git$/i, "").toLowerCase() || "";
|
const repoName = trimmed.split("/").filter(Boolean).pop()?.replace(/\.git$/i, "").toLowerCase() || "";
|
||||||
if (!trimmed || (DEPRECATED_UPDATE_REPO_NAMES.has(repoName) && trimmed.toLowerCase() !== fallback.toLowerCase())) {
|
if (!trimmed || (DEPRECATED_UPDATE_REPO_NAMES.has(repoName) && trimmed.toLowerCase() !== fallback.toLowerCase())) {
|
||||||
return fallback;
|
return fallback;
|
||||||
}
|
}
|
||||||
return trimmed;
|
return trimmed;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function normalizeSettings(settings: AppSettings): AppSettings {
|
export function normalizeSettings(settings: AppSettings): AppSettings {
|
||||||
const defaults = defaultSettings();
|
const defaults = defaultSettings();
|
||||||
|
const directorySettings = migrateLegacyDefaultDirectories(settings, defaults);
|
||||||
const currentUsageDay = getProviderUsageDayKey();
|
const currentUsageDay = getProviderUsageDayKey();
|
||||||
const megaLogin = asText(settings.megaLogin);
|
const megaLogin = asText(settings.megaLogin);
|
||||||
const megaPassword = asText(settings.megaPassword);
|
const megaPassword = asText(settings.megaPassword);
|
||||||
@@ -419,15 +451,15 @@ export function normalizeSettings(settings: AppSettings): AppSettings {
|
|||||||
providerSecondary: normalizeFallbackProvider(settings.providerSecondary, megaDebridPreferApi, megaDebridApiEnabled, megaDebridWebEnabled),
|
providerSecondary: normalizeFallbackProvider(settings.providerSecondary, megaDebridPreferApi, megaDebridApiEnabled, megaDebridWebEnabled),
|
||||||
providerTertiary: normalizeFallbackProvider(settings.providerTertiary, megaDebridPreferApi, megaDebridApiEnabled, megaDebridWebEnabled),
|
providerTertiary: normalizeFallbackProvider(settings.providerTertiary, megaDebridPreferApi, megaDebridApiEnabled, megaDebridWebEnabled),
|
||||||
autoProviderFallback: Boolean(settings.autoProviderFallback),
|
autoProviderFallback: Boolean(settings.autoProviderFallback),
|
||||||
outputDir: normalizeAbsoluteDir(settings.outputDir, defaults.outputDir),
|
outputDir: normalizeAbsoluteDir(directorySettings.outputDir, defaults.outputDir),
|
||||||
packageName: asText(settings.packageName),
|
packageName: asText(settings.packageName),
|
||||||
autoExtract: Boolean(settings.autoExtract),
|
autoExtract: Boolean(settings.autoExtract),
|
||||||
autoRename4sf4sj: Boolean(settings.autoRename4sf4sj),
|
autoRename4sf4sj: Boolean(settings.autoRename4sf4sj),
|
||||||
keepGermanAudioOnly: Boolean(settings.keepGermanAudioOnly),
|
keepGermanAudioOnly: Boolean(settings.keepGermanAudioOnly),
|
||||||
germanAudioMode: settings.germanAudioMode === "first" ? "first" : "tag",
|
germanAudioMode: settings.germanAudioMode === "first" ? "first" : "tag",
|
||||||
extractDir: normalizeAbsoluteDir(settings.extractDir, defaults.extractDir),
|
extractDir: normalizeAbsoluteDir(directorySettings.extractDir, defaults.extractDir),
|
||||||
collectMkvToLibrary: Boolean(settings.collectMkvToLibrary),
|
collectMkvToLibrary: Boolean(settings.collectMkvToLibrary),
|
||||||
mkvLibraryDir: normalizeAbsoluteDir(settings.mkvLibraryDir, defaults.mkvLibraryDir),
|
mkvLibraryDir: normalizeAbsoluteDir(directorySettings.mkvLibraryDir, defaults.mkvLibraryDir),
|
||||||
createExtractSubfolder: Boolean(settings.createExtractSubfolder),
|
createExtractSubfolder: Boolean(settings.createExtractSubfolder),
|
||||||
hybridExtract: Boolean(settings.hybridExtract),
|
hybridExtract: Boolean(settings.hybridExtract),
|
||||||
cleanupMode: settings.cleanupMode,
|
cleanupMode: settings.cleanupMode,
|
||||||
@@ -463,7 +495,7 @@ export function normalizeSettings(settings: AppSettings): AppSettings {
|
|||||||
hideExtractedItems: settings.hideExtractedItems !== undefined ? Boolean(settings.hideExtractedItems) : defaults.hideExtractedItems,
|
hideExtractedItems: settings.hideExtractedItems !== undefined ? Boolean(settings.hideExtractedItems) : defaults.hideExtractedItems,
|
||||||
confirmDeleteSelection: settings.confirmDeleteSelection !== undefined ? Boolean(settings.confirmDeleteSelection) : defaults.confirmDeleteSelection,
|
confirmDeleteSelection: settings.confirmDeleteSelection !== undefined ? Boolean(settings.confirmDeleteSelection) : defaults.confirmDeleteSelection,
|
||||||
backupIncludeDownloads: settings.backupIncludeDownloads !== undefined ? Boolean(settings.backupIncludeDownloads) : defaults.backupIncludeDownloads,
|
backupIncludeDownloads: settings.backupIncludeDownloads !== undefined ? Boolean(settings.backupIncludeDownloads) : defaults.backupIncludeDownloads,
|
||||||
backupIncludeRemoteDiagnostics: settings.backupIncludeRemoteDiagnostics !== undefined ? Boolean(settings.backupIncludeRemoteDiagnostics) : defaults.backupIncludeRemoteDiagnostics,
|
backupIncludeRemoteDiagnostics: settings.backupIncludeRemoteDiagnostics !== undefined ? Boolean(settings.backupIncludeRemoteDiagnostics) : defaults.backupIncludeRemoteDiagnostics,
|
||||||
notifyUrl: asText(settings.notifyUrl) || defaults.notifyUrl,
|
notifyUrl: asText(settings.notifyUrl) || defaults.notifyUrl,
|
||||||
notifyMention: asText(settings.notifyMention) || defaults.notifyMention,
|
notifyMention: asText(settings.notifyMention) || defaults.notifyMention,
|
||||||
notifyOnPackageCompleted: settings.notifyOnPackageCompleted !== undefined ? Boolean(settings.notifyOnPackageCompleted) : defaults.notifyOnPackageCompleted,
|
notifyOnPackageCompleted: settings.notifyOnPackageCompleted !== undefined ? Boolean(settings.notifyOnPackageCompleted) : defaults.notifyOnPackageCompleted,
|
||||||
|
|||||||
+55
-16
@@ -17,6 +17,45 @@ afterEach(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("settings storage", () => {
|
describe("settings storage", () => {
|
||||||
|
it("defaults download directories to the desktop project folder", () => {
|
||||||
|
const baseDir = path.join(os.homedir(), "Desktop", "Multi-Debrid-Downloader");
|
||||||
|
const defaults = defaultSettings();
|
||||||
|
|
||||||
|
expect(defaults.outputDir).toBe(baseDir);
|
||||||
|
expect(defaults.extractDir).toBe(path.join(baseDir, "_entpackt"));
|
||||||
|
expect(defaults.mkvLibraryDir).toBe(path.join(baseDir, "_mkv"));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("migrates an untouched legacy directory configuration", () => {
|
||||||
|
const legacyBaseDir = path.join(os.homedir(), "Downloads", "RealDebrid");
|
||||||
|
const normalized = normalizeSettings({
|
||||||
|
...defaultSettings(),
|
||||||
|
outputDir: legacyBaseDir,
|
||||||
|
extractDir: path.join(legacyBaseDir, "_entpackt"),
|
||||||
|
mkvLibraryDir: path.join(legacyBaseDir, "_mkv")
|
||||||
|
});
|
||||||
|
const defaults = defaultSettings();
|
||||||
|
|
||||||
|
expect(normalized.outputDir).toBe(defaults.outputDir);
|
||||||
|
expect(normalized.extractDir).toBe(defaults.extractDir);
|
||||||
|
expect(normalized.mkvLibraryDir).toBe(defaults.mkvLibraryDir);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps custom directory choices during legacy migration", () => {
|
||||||
|
const legacyBaseDir = path.join(os.homedir(), "Downloads", "RealDebrid");
|
||||||
|
const customOutputDir = path.join(os.homedir(), "Videos", "Custom-Downloads");
|
||||||
|
const normalized = normalizeSettings({
|
||||||
|
...defaultSettings(),
|
||||||
|
outputDir: customOutputDir,
|
||||||
|
extractDir: path.join(legacyBaseDir, "_entpackt"),
|
||||||
|
mkvLibraryDir: path.join(legacyBaseDir, "_mkv")
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(normalized.outputDir).toBe(customOutputDir);
|
||||||
|
expect(normalized.extractDir).toBe(path.join(legacyBaseDir, "_entpackt"));
|
||||||
|
expect(normalized.mkvLibraryDir).toBe(path.join(legacyBaseDir, "_mkv"));
|
||||||
|
});
|
||||||
|
|
||||||
it("does not persist provider credentials when rememberToken is disabled", () => {
|
it("does not persist provider credentials when rememberToken is disabled", () => {
|
||||||
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "rd-store-"));
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "rd-store-"));
|
||||||
tempDirs.push(dir);
|
tempDirs.push(dir);
|
||||||
@@ -71,7 +110,7 @@ describe("settings storage", () => {
|
|||||||
expect(loaded.allDebridToken).toBe("all-token");
|
expect(loaded.allDebridToken).toBe("all-token");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("normalizes invalid enum and numeric values", () => {
|
it("normalizes invalid enum and numeric values", () => {
|
||||||
const normalized = normalizeSettings({
|
const normalized = normalizeSettings({
|
||||||
...defaultSettings(),
|
...defaultSettings(),
|
||||||
providerPrimary: "invalid-provider" as unknown as AppSettings["providerPrimary"],
|
providerPrimary: "invalid-provider" as unknown as AppSettings["providerPrimary"],
|
||||||
@@ -105,21 +144,21 @@ describe("settings storage", () => {
|
|||||||
expect(normalized.outputDir).toBe(defaultSettings().outputDir);
|
expect(normalized.outputDir).toBe(defaultSettings().outputDir);
|
||||||
expect(normalized.extractDir).toBe(defaultSettings().extractDir);
|
expect(normalized.extractDir).toBe(defaultSettings().extractDir);
|
||||||
expect(normalized.mkvLibraryDir).toBe(defaultSettings().mkvLibraryDir);
|
expect(normalized.mkvLibraryDir).toBe(defaultSettings().mkvLibraryDir);
|
||||||
expect(normalized.updateRepo).toBe(defaultSettings().updateRepo);
|
expect(normalized.updateRepo).toBe(defaultSettings().updateRepo);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("migrates the previous private update repository to the public release repository", () => {
|
it("migrates the previous private update repository to the public release repository", () => {
|
||||||
for (const updateRepo of [
|
for (const updateRepo of [
|
||||||
"legacy-owner/real-debrid-downloader",
|
"legacy-owner/real-debrid-downloader",
|
||||||
"legacy-owner/multi-debrid-downloader",
|
"legacy-owner/multi-debrid-downloader",
|
||||||
"legacy-owner/real-debrid-downloader.git"
|
"legacy-owner/real-debrid-downloader.git"
|
||||||
]) {
|
]) {
|
||||||
const normalized = normalizeSettings({ ...defaultSettings(), updateRepo });
|
const normalized = normalizeSettings({ ...defaultSettings(), updateRepo });
|
||||||
expect(normalized.updateRepo).toBe(defaultSettings().updateRepo);
|
expect(normalized.updateRepo).toBe(defaultSettings().updateRepo);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it("normalizes malformed persisted config on load", () => {
|
it("normalizes malformed persisted config on load", () => {
|
||||||
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "rd-store-"));
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "rd-store-"));
|
||||||
tempDirs.push(dir);
|
tempDirs.push(dir);
|
||||||
const paths = createStoragePaths(dir);
|
const paths = createStoragePaths(dir);
|
||||||
|
|||||||
Reference in New Issue
Block a user