feat: added librespotConcurrency, which determines the threadpool of librespot api processes
This commit is contained in:
@@ -179,6 +179,77 @@ function UtilityConcurrencyForm() {
|
||||
);
|
||||
}
|
||||
|
||||
function LibrespotConcurrencyForm() {
|
||||
const queryClient = useQueryClient();
|
||||
const { data: configData, isLoading } = useQuery({
|
||||
queryKey: ["config"],
|
||||
queryFn: () => authApiClient.getConfig<any>(),
|
||||
});
|
||||
|
||||
const { register, handleSubmit, reset, formState: { isDirty } } = useForm<{ librespotConcurrency: number }>();
|
||||
|
||||
useEffect(() => {
|
||||
if (configData) {
|
||||
reset({ librespotConcurrency: Number(configData.librespotConcurrency ?? 2) });
|
||||
}
|
||||
}, [configData, reset]);
|
||||
|
||||
const mutation = useMutation({
|
||||
mutationFn: (payload: { librespotConcurrency: number }) => authApiClient.updateConfig(payload),
|
||||
onSuccess: () => {
|
||||
toast.success("Librespot concurrency saved!");
|
||||
queryClient.invalidateQueries({ queryKey: ["config"] });
|
||||
},
|
||||
onError: (e) => {
|
||||
toast.error(`Failed to save: ${(e as any).message}`);
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = (values: { librespotConcurrency: number }) => {
|
||||
const raw = Number(values.librespotConcurrency || 2);
|
||||
const safe = Math.max(1, Math.min(16, raw));
|
||||
mutation.mutate({ librespotConcurrency: safe });
|
||||
};
|
||||
|
||||
if (isLoading) return <p className="text-content-muted dark:text-content-muted-dark">Loading server settings...</p>;
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
|
||||
<div className="flex items-center justify-end mb-2">
|
||||
<div className="flex items-center gap-3">
|
||||
<button
|
||||
type="submit"
|
||||
disabled={mutation.isPending || !isDirty}
|
||||
className="px-4 py-2 bg-button-primary hover:bg-button-primary-hover text-button-primary-text rounded-md disabled:opacity-50"
|
||||
title="Save Librespot Concurrency"
|
||||
>
|
||||
{mutation.isPending ? (
|
||||
<img src="/spinner.svg" alt="Saving" className="w-5 h-5 animate-spin logo" />
|
||||
) : (
|
||||
<img src="/save.svg" alt="Save" className="w-5 h-5 logo" />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
<label htmlFor="librespotConcurrency" className="text-content-primary dark:text-content-primary-dark">Librespot Concurrency</label>
|
||||
<input
|
||||
id="librespotConcurrency"
|
||||
type="number"
|
||||
min={1}
|
||||
max={16}
|
||||
step={1}
|
||||
{...register("librespotConcurrency", { valueAsNumber: true })}
|
||||
className="block w-full p-2 border bg-input-background dark:bg-input-background-dark border-input-border dark:border-input-border-dark rounded-md focus:outline-none focus:ring-2 focus:ring-input-focus"
|
||||
placeholder="2"
|
||||
/>
|
||||
<p className="text-xs text-content-secondary dark:text-content-secondary-dark">Controls worker threads used by the Librespot client. 1–16 is recommended.</p>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
// --- Components ---
|
||||
function WebhookForm() {
|
||||
const queryClient = useQueryClient();
|
||||
@@ -299,6 +370,12 @@ export function ServerTab() {
|
||||
<UtilityConcurrencyForm />
|
||||
</div>
|
||||
<hr className="border-border dark:border-border-dark" />
|
||||
<div>
|
||||
<h3 className="text-xl font-semibold text-content-primary dark:text-content-primary-dark">Librespot</h3>
|
||||
<p className="text-sm text-content-muted dark:text-content-muted-dark mt-1">Adjust Librespot client worker threads.</p>
|
||||
<LibrespotConcurrencyForm />
|
||||
</div>
|
||||
<hr className="border-border dark:border-border-dark" />
|
||||
<div>
|
||||
<h3 className="text-xl font-semibold text-content-primary dark:text-content-primary-dark">Webhooks</h3>
|
||||
<p className="text-sm text-content-muted dark:text-content-muted-dark mt-1">
|
||||
|
||||
@@ -33,6 +33,7 @@ export type FlatAppSettings = {
|
||||
deezerQuality: "MP3_128" | "MP3_320" | "FLAC";
|
||||
maxConcurrentDownloads: number;
|
||||
utilityConcurrency: number;
|
||||
librespotConcurrency: number;
|
||||
realTime: boolean;
|
||||
fallback: boolean;
|
||||
convertTo: "MP3" | "AAC" | "OGG" | "OPUS" | "FLAC" | "WAV" | "ALAC" | "";
|
||||
@@ -74,6 +75,7 @@ const defaultSettings: FlatAppSettings = {
|
||||
deezerQuality: "MP3_128",
|
||||
maxConcurrentDownloads: 3,
|
||||
utilityConcurrency: 1,
|
||||
librespotConcurrency: 2,
|
||||
realTime: false,
|
||||
fallback: false,
|
||||
convertTo: "",
|
||||
@@ -138,6 +140,7 @@ const fetchSettings = async (): Promise<FlatAppSettings> => {
|
||||
recursiveQuality: Boolean((camelData as any).recursiveQuality ?? false),
|
||||
realTimeMultiplier: Number((camelData as any).realTimeMultiplier ?? 0),
|
||||
utilityConcurrency: Number((camelData as any).utilityConcurrency ?? 1),
|
||||
librespotConcurrency: Number((camelData as any).librespotConcurrency ?? 2),
|
||||
// Ensure watch subkeys default if missing
|
||||
watch: {
|
||||
...(camelData.watch as any),
|
||||
|
||||
@@ -9,6 +9,7 @@ export interface AppSettings {
|
||||
deezerQuality: "MP3_128" | "MP3_320" | "FLAC";
|
||||
maxConcurrentDownloads: number;
|
||||
utilityConcurrency: number;
|
||||
librespotConcurrency: number;
|
||||
realTime: boolean;
|
||||
fallback: boolean;
|
||||
convertTo: "MP3" | "AAC" | "OGG" | "OPUS" | "FLAC" | "WAV" | "ALAC" | "";
|
||||
|
||||
Reference in New Issue
Block a user