Spaces:
Build error
Build error
'use client'; | |
import { useStatus } from '@/context/status'; | |
import { PageWrapper } from '../shared/page-wrapper'; | |
import { useState, useEffect } from 'react'; | |
import * as constants from '../../../../core/src/utils/constants'; | |
import { useUserData } from '@/context/userData'; | |
import { Switch } from '../ui/switch'; | |
import { Select } from '../ui/select'; | |
import { Combobox } from '../ui/combobox'; | |
import { SettingsCard } from '../shared/settings-card'; | |
import { TextInput } from '../ui/text-input'; | |
import { toast } from 'sonner'; | |
import { Button } from '../ui/button'; | |
import MarkdownLite from '../shared/markdown-lite'; | |
import { PageControls } from '../shared/page-controls'; | |
import { PasswordInput } from '../ui/password-input'; | |
type ProxyServiceId = keyof typeof constants.PROXY_SERVICE_DETAILS; | |
type ProxyConfig = { | |
enabled: boolean; | |
id: ProxyServiceId; | |
url: string; | |
credentials: string; | |
publicIp?: string; | |
proxiedAddons?: string[]; | |
proxiedServices?: string[]; | |
}; | |
export function ProxyMenu() { | |
return ( | |
<> | |
<PageWrapper className="space-y-4 p-4 sm:p-8"> | |
<Content /> | |
</PageWrapper> | |
</> | |
); | |
} | |
function Content() { | |
const { status } = useStatus(); | |
const { userData, setUserData } = useUserData(); | |
const details = constants.PROXY_SERVICE_DETAILS; | |
// Effect to initialize values from userData/defaults/forced | |
// Generate options for proxy service select | |
const proxyOptions = Object.entries(details).map(([id, detail]) => ({ | |
label: detail.name, | |
value: id, | |
})); | |
// Generate options for services multi-select | |
const serviceOptions = [ | |
...Object.values(constants.SERVICE_DETAILS).map((service) => ({ | |
label: service.name, | |
value: service.id, | |
textValue: service.name, | |
})), | |
{ | |
label: 'None', | |
value: 'none', | |
textValue: 'None', | |
}, | |
]; | |
const addonOptions = userData.presets.map((preset) => { | |
return { | |
label: preset.options.name || preset.type, | |
value: preset.instanceId, | |
textValue: preset.options.name, | |
}; | |
}); | |
// lues are forced | |
const isForced = status?.settings.forced.proxy; | |
const isProxyForced = isForced?.enabled !== null; | |
const isUrlForced = isForced?.url !== null; | |
const isIdForced = isForced?.id !== null; | |
const isPublicIpForced = isForced?.publicIp !== null; | |
const isCredentialsForced = isForced?.credentials !== null; | |
const isServicesForced = isForced?.proxiedServices !== null; | |
const isProxiedAddonsDisabled = isForced?.disableProxiedAddons; | |
const selectedProxyDetails = userData.proxy?.id | |
? details[userData.proxy.id] | |
: undefined; | |
return ( | |
<> | |
<div className="flex items-center w-full"> | |
<div> | |
<h2>Proxy</h2> | |
<p className="text-[--muted]"> | |
Configure a proxy for your streams to bypass IP restrictions or | |
improve compatibility | |
</p> | |
</div> | |
<div className="hidden lg:block lg:ml-auto"> | |
<PageControls /> | |
</div> | |
</div> | |
<div className="space-y-2"> | |
<SettingsCard> | |
<Switch | |
side="right" | |
label="Enable" | |
value={userData.proxy?.enabled ?? false} | |
onValueChange={(v) => { | |
setUserData((prev) => ({ | |
...prev, | |
proxy: { ...prev.proxy, enabled: v }, | |
})); | |
}} | |
disabled={isProxyForced} | |
/> | |
</SettingsCard> | |
<SettingsCard> | |
<div className="space-y-2"> | |
<Select | |
label="Proxy Service" | |
value={userData.proxy?.id} | |
onValueChange={(v) => { | |
setUserData((prev) => ({ | |
...prev, | |
proxy: { ...prev.proxy, id: v as ProxyServiceId }, | |
})); | |
}} | |
options={proxyOptions} | |
disabled={isIdForced || !userData.proxy?.enabled} | |
/> | |
{selectedProxyDetails && ( | |
<p className="text-[--muted] text-sm"> | |
<MarkdownLite>{selectedProxyDetails.description}</MarkdownLite> | |
</p> | |
)} | |
</div> | |
<div className="space-y-2"> | |
<PasswordInput | |
label="URL" | |
value={userData.proxy?.url ?? ''} | |
onValueChange={(v) => { | |
setUserData((prev) => ({ | |
...prev, | |
proxy: { ...prev.proxy, url: v }, | |
})); | |
}} | |
placeholder="Enter proxy URL" | |
disabled={isUrlForced || !userData.proxy?.enabled} | |
/> | |
<p className="text-[--muted] text-sm"> | |
The URL of your hosted proxy service. | |
</p> | |
</div> | |
<div className="space-y-2"> | |
<PasswordInput | |
label="Credentials" | |
value={userData.proxy?.credentials ?? ''} | |
onValueChange={(v) => { | |
setUserData((prev) => ({ | |
...prev, | |
proxy: { ...prev.proxy, credentials: v }, | |
})); | |
}} | |
placeholder="Enter proxy credentials" | |
disabled={isCredentialsForced || !userData.proxy?.enabled} | |
/> | |
{selectedProxyDetails && ( | |
<p className="text-[--muted] text-sm"> | |
<MarkdownLite> | |
{selectedProxyDetails.credentialDescription} | |
</MarkdownLite> | |
</p> | |
)} | |
</div> | |
<div className="space-y-2"> | |
<TextInput | |
label="Public IP" | |
value={userData.proxy?.publicIp ?? ''} | |
onValueChange={(v) => { | |
setUserData((prev) => ({ | |
...prev, | |
proxy: { ...prev.proxy, publicIp: v || undefined }, | |
})); | |
}} | |
placeholder="Enter public IP" | |
disabled={isPublicIpForced || !userData.proxy?.enabled} | |
/> | |
<p className="text-[--muted] text-sm"> | |
Configure this only when running {selectedProxyDetails?.name}{' '} | |
locally with a proxy service. Leave empty if{' '} | |
{selectedProxyDetails?.name} is configured locally without a proxy | |
server or if it's hosted on a remote server. | |
</p> | |
</div> | |
</SettingsCard> | |
<SettingsCard | |
title="Proxy Controls" | |
description="Optionally, specify services and addons that should be proxied. These options are applied conjunctively." | |
> | |
<div className="space-y-2"> | |
<Combobox | |
label="Proxied Services" | |
value={userData.proxy?.proxiedServices ?? []} | |
onValueChange={(v) => { | |
setUserData((prev) => ({ | |
...prev, | |
proxy: { ...prev.proxy, proxiedServices: v }, | |
})); | |
}} | |
options={serviceOptions} | |
placeholder="Select services to proxy" | |
multiple={true} | |
disabled={isServicesForced || !userData.proxy?.enabled} | |
emptyMessage="No services available" | |
/> | |
<p className="text-[--muted] text-sm"> | |
Only streams (that are detected to be) from these services will be | |
proxied. Select None to enable proxying of streams that are not | |
detected to be from a service. | |
</p> | |
</div> | |
<div className="space-y-2"> | |
<Combobox | |
label="Proxied Addons" | |
value={userData.proxy?.proxiedAddons ?? []} | |
onValueChange={(v) => { | |
setUserData((prev) => ({ | |
...prev, | |
proxy: { ...prev.proxy, proxiedAddons: v }, | |
})); | |
}} | |
options={addonOptions} | |
placeholder="Select addons to proxy" | |
multiple={true} | |
disabled={isProxiedAddonsDisabled || !userData.proxy?.enabled} | |
emptyMessage="No addons available" | |
/> | |
<p className="text-[--muted] text-sm"> | |
Only streams from these addons will be proxied | |
</p> | |
</div> | |
</SettingsCard> | |
</div> | |
</> | |
); | |
} | |