Major Features: - Multi-source download system (Soulseek/Lidarr with fallback) - Configurable enrichment speed control (1-5x) - Mobile touch drag support for seek sliders - iOS PWA media controls (Control Center, Lock Screen) - Artist name alias resolution via Last.fm - Circuit breaker pattern for audio analysis Critical Fixes: - Audio analyzer stability (non-ASCII, BrokenProcessPool, OOM) - Discovery system race conditions and import failures - Radio decade categorization using originalYear - LastFM API response normalization - Mood bucket infinite loop prevention Security: - Bull Board admin authentication - Lidarr webhook signature verification - JWT token expiration and refresh - Encryption key validation on startup Closes #2, #6, #9, #13, #21, #26, #31, #34, #35, #37, #40, #43
128 lines
4.7 KiB
TypeScript
128 lines
4.7 KiB
TypeScript
"use client";
|
|
|
|
import { SettingsSection, SettingsRow, SettingsSelect } from "../ui";
|
|
import { SystemSettings } from "../../types";
|
|
|
|
interface DownloadPreferencesSectionProps {
|
|
settings: SystemSettings;
|
|
onUpdate: (updates: Partial<SystemSettings>) => void;
|
|
}
|
|
|
|
export function DownloadPreferencesSection({
|
|
settings,
|
|
onUpdate,
|
|
}: DownloadPreferencesSectionProps) {
|
|
// Service configuration detection
|
|
const isLidarrConfigured =
|
|
settings.lidarrEnabled === true &&
|
|
settings.lidarrUrl.trim() !== "" &&
|
|
settings.lidarrApiKey.trim() !== "";
|
|
|
|
const isSoulseekConfigured =
|
|
settings.soulseekUsername.trim() !== "" &&
|
|
settings.soulseekPassword.trim() !== "";
|
|
|
|
const areBothServicesConfigured = isLidarrConfigured && isSoulseekConfigured;
|
|
const isDisabled = !areBothServicesConfigured;
|
|
|
|
// Dynamic fallback options based on primary source
|
|
const getFallbackOptions = () => {
|
|
if (settings.downloadSource === "soulseek") {
|
|
return [
|
|
{ value: "none", label: "Skip track" },
|
|
{ value: "lidarr", label: "Download full album via Lidarr" },
|
|
];
|
|
} else {
|
|
return [
|
|
{ value: "none", label: "Skip album" },
|
|
{ value: "soulseek", label: "Try Soulseek for individual tracks" },
|
|
];
|
|
}
|
|
};
|
|
|
|
return (
|
|
<SettingsSection
|
|
id="download-preferences"
|
|
title="Download Preferences"
|
|
description="Configure how music is downloaded for playlists and discovery"
|
|
>
|
|
<SettingsRow
|
|
label="Primary Download Source"
|
|
description={
|
|
isDisabled
|
|
? "Requires both Soulseek and Lidarr to be configured"
|
|
: "Choose how to download music for imported playlists"
|
|
}
|
|
>
|
|
<SettingsSelect
|
|
value={settings.downloadSource || "soulseek"}
|
|
onChange={(v) =>
|
|
onUpdate({
|
|
downloadSource: v as "soulseek" | "lidarr",
|
|
primaryFailureFallback: "none"
|
|
})
|
|
}
|
|
options={[
|
|
{ value: "soulseek", label: "Soulseek (Per-track)" },
|
|
{ value: "lidarr", label: "Lidarr (Full albums)" },
|
|
]}
|
|
disabled={isDisabled}
|
|
/>
|
|
</SettingsRow>
|
|
|
|
<SettingsRow
|
|
label={
|
|
settings.downloadSource === "soulseek"
|
|
? "When Soulseek Fails"
|
|
: "When Lidarr Fails"
|
|
}
|
|
description={
|
|
isDisabled
|
|
? "Requires both Soulseek and Lidarr to be configured"
|
|
: settings.downloadSource === "soulseek"
|
|
? "What to do if a track can't be found on Soulseek"
|
|
: "What to do if an album can't be found on Lidarr"
|
|
}
|
|
>
|
|
<SettingsSelect
|
|
value={settings.primaryFailureFallback || "none"}
|
|
onChange={(v) =>
|
|
onUpdate({
|
|
primaryFailureFallback: v as "none" | "lidarr" | "soulseek",
|
|
})
|
|
}
|
|
options={getFallbackOptions()}
|
|
disabled={isDisabled}
|
|
/>
|
|
</SettingsRow>
|
|
|
|
<SettingsRow
|
|
label="Soulseek Concurrent Downloads"
|
|
description="Number of simultaneous downloads when using Soulseek (1-10)"
|
|
>
|
|
<SettingsSelect
|
|
value={settings.soulseekConcurrentDownloads?.toString() || "4"}
|
|
onChange={(v) =>
|
|
onUpdate({
|
|
soulseekConcurrentDownloads: parseInt(v),
|
|
})
|
|
}
|
|
options={[
|
|
{ value: "1", label: "1" },
|
|
{ value: "2", label: "2" },
|
|
{ value: "3", label: "3" },
|
|
{ value: "4", label: "4 (Default)" },
|
|
{ value: "5", label: "5" },
|
|
{ value: "6", label: "6" },
|
|
{ value: "7", label: "7" },
|
|
{ value: "8", label: "8" },
|
|
{ value: "9", label: "9" },
|
|
{ value: "10", label: "10" },
|
|
]}
|
|
disabled={!isSoulseekConfigured}
|
|
/>
|
|
</SettingsRow>
|
|
</SettingsSection>
|
|
);
|
|
}
|