mirror of
https://github.com/Viren070/AIOStreams.git
synced 2025-12-01 23:14:04 +01:00
fix: update handling of default/forced values
This commit is contained in:
@@ -41,9 +41,9 @@ const Formatter = z.object({
|
||||
|
||||
const StreamProxyConfig = z.object({
|
||||
enabled: z.boolean().optional(),
|
||||
id: z.enum(constants.PROXY_SERVICES),
|
||||
url: z.string().url(),
|
||||
credentials: z.string().min(1),
|
||||
id: z.enum(constants.PROXY_SERVICES).optional(),
|
||||
url: z.string().optional(),
|
||||
credentials: z.string().min(1).optional(),
|
||||
publicIp: z.string().ip().optional(),
|
||||
proxiedAddons: z.array(z.string().min(1)).optional(),
|
||||
proxiedServices: z.array(z.string().min(1)).optional(),
|
||||
|
||||
@@ -13,14 +13,24 @@ export interface ProxyStream {
|
||||
};
|
||||
}
|
||||
|
||||
type ValidatedStreamProxyConfig = StreamProxyConfig & {
|
||||
id: 'mediaflow' | 'stremthru';
|
||||
url: string;
|
||||
credentials: string;
|
||||
};
|
||||
|
||||
export abstract class BaseProxy {
|
||||
protected readonly config: StreamProxyConfig;
|
||||
protected readonly config: ValidatedStreamProxyConfig;
|
||||
private readonly PRIVATE_CIDR =
|
||||
/^(10\.|127\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.)/;
|
||||
|
||||
constructor(config: StreamProxyConfig) {
|
||||
if (!config.id || !config.credentials || !config.url) {
|
||||
throw new Error('Proxy configuration is missing');
|
||||
}
|
||||
|
||||
this.config = {
|
||||
enabled: config.enabled,
|
||||
enabled: config.enabled ?? false,
|
||||
id: config.id,
|
||||
url: config.url,
|
||||
credentials: config.credentials,
|
||||
|
||||
@@ -13,7 +13,7 @@ import { createProxy } from '../proxy';
|
||||
import { constants } from '.';
|
||||
import { isEncrypted, decryptString, encryptString } from './crypto';
|
||||
import { Env } from './env';
|
||||
import { createLogger } from './logger';
|
||||
import { createLogger, maskSensitiveInfo } from './logger';
|
||||
import { ZodError } from 'zod';
|
||||
import { ConditionParser } from '../parser/conditions';
|
||||
import { RPDB } from './rpdb';
|
||||
@@ -273,11 +273,15 @@ export async function validateConfig(
|
||||
}
|
||||
|
||||
if (config.proxy) {
|
||||
config.proxy = await validateProxy(
|
||||
config.proxy,
|
||||
skipErrorsFromAddonsOrProxies,
|
||||
decryptValues
|
||||
);
|
||||
const decryptedProxy = ensureDecrypted(config).proxy;
|
||||
if (decryptedProxy) {
|
||||
config.proxy = await validateProxy(
|
||||
config.proxy,
|
||||
decryptedProxy,
|
||||
skipErrorsFromAddonsOrProxies,
|
||||
decryptValues
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (config.rpdbApiKey) {
|
||||
@@ -351,7 +355,7 @@ async function validateRegexes(config: UserData) {
|
||||
);
|
||||
}
|
||||
|
||||
function ensureDecrypted(config: UserData) {
|
||||
function ensureDecrypted(config: UserData): UserData {
|
||||
const decryptedConfig = { ...config };
|
||||
|
||||
// Helper function to decrypt a value if needed
|
||||
@@ -369,7 +373,7 @@ function ensureDecrypted(config: UserData) {
|
||||
if (!service.credentials) continue;
|
||||
for (const [credential, value] of Object.entries(service.credentials)) {
|
||||
service.credentials[credential] = tryDecrypt(
|
||||
value,
|
||||
decodeURIComponent(value),
|
||||
`credential ${credential}`
|
||||
);
|
||||
}
|
||||
@@ -378,8 +382,14 @@ function ensureDecrypted(config: UserData) {
|
||||
// Decrypt proxy config
|
||||
if (decryptedConfig.proxy) {
|
||||
const proxy = decryptedConfig.proxy;
|
||||
proxy.credentials = tryDecrypt(proxy.credentials, 'proxy credentials');
|
||||
proxy.url = tryDecrypt(proxy.url, 'proxy URL');
|
||||
proxy.credentials = tryDecrypt(
|
||||
proxy.credentials ? decodeURIComponent(proxy.credentials) : undefined,
|
||||
'proxy credentials'
|
||||
);
|
||||
proxy.url = tryDecrypt(
|
||||
proxy.url ? decodeURIComponent(proxy.url) : undefined,
|
||||
'proxy URL'
|
||||
);
|
||||
}
|
||||
|
||||
return decryptedConfig;
|
||||
@@ -519,6 +529,7 @@ function validateOption(
|
||||
if (option.forced) {
|
||||
value = option.forced;
|
||||
}
|
||||
value = decodeURIComponent(value);
|
||||
if (isEncrypted(value) && decryptValues) {
|
||||
const { success, data, error } = decryptString(value);
|
||||
if (!success) {
|
||||
@@ -547,6 +558,7 @@ function validateOption(
|
||||
|
||||
async function validateProxy(
|
||||
proxy: StreamProxyConfig,
|
||||
decryptedProxy: StreamProxyConfig,
|
||||
skipProxyErrors: boolean = false,
|
||||
decryptCredentials: boolean = false
|
||||
): Promise<StreamProxyConfig> {
|
||||
@@ -572,18 +584,10 @@ async function validateProxy(
|
||||
throw new Error('Proxy credentials are required');
|
||||
}
|
||||
|
||||
const ProxyService = createProxy(proxy);
|
||||
|
||||
try {
|
||||
proxy.publicIp || (await ProxyService.getPublicIp());
|
||||
} catch (error) {
|
||||
if (!skipProxyErrors) {
|
||||
throw new Error(
|
||||
`Failed to get the public IP of the proxy service ${proxy.id}: ${error}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
proxy.credentials = decodeURIComponent(proxy.credentials);
|
||||
proxy.url = proxy.url.startsWith('aioEncrypt')
|
||||
? decodeURIComponent(proxy.url)
|
||||
: proxy.url;
|
||||
if (isEncrypted(proxy.credentials) && decryptCredentials) {
|
||||
const { success, data, error } = decryptString(proxy.credentials);
|
||||
if (!success) {
|
||||
@@ -602,6 +606,22 @@ async function validateProxy(
|
||||
}
|
||||
proxy.url = data;
|
||||
}
|
||||
|
||||
// use decrypted proxy config for validation.
|
||||
const ProxyService = createProxy(decryptedProxy);
|
||||
|
||||
try {
|
||||
proxy.publicIp || (await ProxyService.getPublicIp());
|
||||
} catch (error) {
|
||||
if (!skipProxyErrors) {
|
||||
logger.error(
|
||||
`Failed to get the public IP of the proxy service ${proxy.id} (${maskSensitiveInfo(proxy.url)}): ${error}`
|
||||
);
|
||||
throw new Error(
|
||||
`Failed to get the public IP of the proxy service ${proxy.id}: ${error}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return proxy;
|
||||
}
|
||||
|
||||
@@ -35,68 +35,12 @@ export function ProxyMenu() {
|
||||
);
|
||||
}
|
||||
|
||||
// provides a page to configure a proxy
|
||||
// use constants.PROXY_DETAILS to get the list of proxies
|
||||
// and use status.settings.defaults.proxy to load default values if current userData doesn't have a value
|
||||
// use status.settings.forced.proxy to always load the forced values
|
||||
|
||||
// should look like this.
|
||||
// a switch to enable/disable the proxy. should be enabled on left and then switch on right, with descriptin of setting below.
|
||||
// when disabled, hide the rest of the settings
|
||||
// a select menu to choose a proxy, mapped to the proxy.id option (Get name/label from details)
|
||||
// shows the description below the select.
|
||||
// then a password input to provide the credential
|
||||
// then a multi select menu to choose services that proxy is used for
|
||||
// then a multi select menu to choose addons that proxy is used for
|
||||
// addon labels should use the addon name, and value should be the ID, calculated using same method as getPresetUniqueKey in addons.tsx
|
||||
|
||||
function Content() {
|
||||
const { status } = useStatus();
|
||||
const { userData, setUserData } = useUserData();
|
||||
const details = constants.PROXY_SERVICE_DETAILS;
|
||||
|
||||
// Initialize proxy configuration from userData, defaults, or forced values
|
||||
const [proxyEnabled, setProxyEnabled] = useState(false);
|
||||
const [selectedProxyId, setSelectedProxyId] =
|
||||
useState<ProxyServiceId>('mediaflow');
|
||||
const [proxyUrl, setProxyUrl] = useState('');
|
||||
const [proxyCredentials, setProxyCredentials] = useState('');
|
||||
const [proxiedServices, setProxiedServices] = useState<string[] | undefined>(
|
||||
undefined
|
||||
);
|
||||
const [proxiedAddons, setProxiedAddons] = useState<string[] | undefined>(
|
||||
undefined
|
||||
);
|
||||
const [hasChanges, setHasChanges] = useState(false);
|
||||
|
||||
// Effect to initialize values from userData/defaults/forced
|
||||
useEffect(() => {
|
||||
if (!status) return;
|
||||
|
||||
const forced = status.settings.forced.proxy;
|
||||
const defaults = status.settings.defaults.proxy;
|
||||
const current = userData.proxy;
|
||||
|
||||
// Apply forced values first, then current values, then defaults
|
||||
setProxyEnabled(
|
||||
forced.enabled ?? current?.enabled ?? defaults.enabled ?? false
|
||||
);
|
||||
setSelectedProxyId(
|
||||
(forced.id ?? current?.id ?? defaults.id ?? '') as ProxyServiceId
|
||||
);
|
||||
setProxyCredentials(
|
||||
forced.credentials ?? current?.credentials ?? defaults.credentials ?? ''
|
||||
);
|
||||
setProxyUrl(forced.url ?? current?.url ?? defaults.url ?? '');
|
||||
setProxiedServices(
|
||||
forced.proxiedServices ??
|
||||
current?.proxiedServices ??
|
||||
defaults.proxiedServices ??
|
||||
[]
|
||||
);
|
||||
setProxiedAddons(current?.proxiedAddons);
|
||||
setHasChanges(false);
|
||||
}, [status]);
|
||||
|
||||
// Generate options for proxy service select
|
||||
const proxyOptions = Object.entries(details).map(([id, detail]) => ({
|
||||
@@ -126,61 +70,7 @@ function Content() {
|
||||
};
|
||||
});
|
||||
|
||||
// Handle changes
|
||||
const handleProxyChange = (enabled: boolean) => {
|
||||
setProxyEnabled(enabled);
|
||||
if (!enabled && !selectedProxyId && userData.proxy === undefined) {
|
||||
setHasChanges(false);
|
||||
} else {
|
||||
setHasChanges(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleUrlChange = (value: string) => {
|
||||
setProxyUrl(value);
|
||||
setHasChanges(true);
|
||||
};
|
||||
|
||||
const handleProxyServiceChange = (value: string) => {
|
||||
setSelectedProxyId(value as ProxyServiceId);
|
||||
setHasChanges(true);
|
||||
};
|
||||
|
||||
const handleCredentialsChange = (value: string) => {
|
||||
setProxyCredentials(value);
|
||||
setHasChanges(true);
|
||||
};
|
||||
|
||||
const handleProxiedServicesChange = (values: string[]) => {
|
||||
setProxiedServices(values);
|
||||
setHasChanges(true);
|
||||
};
|
||||
|
||||
const handleProxiedAddonsChange = (values: string[]) => {
|
||||
setProxiedAddons(values);
|
||||
setHasChanges(true);
|
||||
};
|
||||
|
||||
const handleSubmit = () => {
|
||||
const proxyConfig: ProxyConfig = {
|
||||
enabled: proxyEnabled,
|
||||
id: selectedProxyId,
|
||||
url: proxyUrl,
|
||||
credentials: proxyCredentials,
|
||||
proxiedServices: proxiedServices,
|
||||
proxiedAddons: proxiedAddons,
|
||||
};
|
||||
|
||||
setUserData((prev) => ({
|
||||
...prev,
|
||||
proxy: proxyConfig,
|
||||
}));
|
||||
|
||||
setHasChanges(false);
|
||||
toast.success('Proxy settings saved');
|
||||
};
|
||||
|
||||
// Check if values are forced
|
||||
// lues are forced
|
||||
const isForced = status?.settings.forced.proxy;
|
||||
const isProxyForced = isForced?.enabled !== null;
|
||||
const isUrlForced = isForced?.url !== null;
|
||||
@@ -189,8 +79,8 @@ function Content() {
|
||||
const isServicesForced = isForced?.proxiedServices !== null;
|
||||
const isProxiedAddonsDisabled = isForced?.disableProxiedAddons;
|
||||
|
||||
const selectedProxyDetails = selectedProxyId
|
||||
? details[selectedProxyId]
|
||||
const selectedProxyDetails = userData.proxy?.id
|
||||
? details[userData.proxy.id]
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
@@ -213,8 +103,13 @@ function Content() {
|
||||
<Switch
|
||||
side="right"
|
||||
label="Enable"
|
||||
value={proxyEnabled}
|
||||
onValueChange={handleProxyChange}
|
||||
value={userData.proxy?.enabled ?? false}
|
||||
onValueChange={(v) => {
|
||||
setUserData((prev) => ({
|
||||
...prev,
|
||||
proxy: { ...prev.proxy, enabled: v },
|
||||
}));
|
||||
}}
|
||||
disabled={isProxyForced}
|
||||
/>
|
||||
</SettingsCard>
|
||||
@@ -223,10 +118,15 @@ function Content() {
|
||||
<div className="space-y-2">
|
||||
<Select
|
||||
label="Proxy Service"
|
||||
value={selectedProxyId}
|
||||
onValueChange={handleProxyServiceChange}
|
||||
value={userData.proxy?.id ?? 'mediaflow'}
|
||||
onValueChange={(v) => {
|
||||
setUserData((prev) => ({
|
||||
...prev,
|
||||
proxy: { ...prev.proxy, id: v as ProxyServiceId },
|
||||
}));
|
||||
}}
|
||||
options={proxyOptions}
|
||||
disabled={isIdForced || !proxyEnabled}
|
||||
disabled={isIdForced || !userData.proxy?.enabled}
|
||||
/>
|
||||
{selectedProxyDetails && (
|
||||
<p className="text-[--muted] text-sm">
|
||||
@@ -238,11 +138,16 @@ function Content() {
|
||||
<div className="space-y-2">
|
||||
<TextInput
|
||||
label="URL"
|
||||
value={proxyUrl}
|
||||
value={userData.proxy?.url ?? ''}
|
||||
type="password"
|
||||
onValueChange={handleUrlChange}
|
||||
onValueChange={(v) => {
|
||||
setUserData((prev) => ({
|
||||
...prev,
|
||||
proxy: { ...prev.proxy, url: v },
|
||||
}));
|
||||
}}
|
||||
placeholder="Enter proxy URL"
|
||||
disabled={isUrlForced || !proxyEnabled}
|
||||
disabled={isUrlForced || !userData.proxy?.enabled}
|
||||
/>
|
||||
<p className="text-[--muted] text-sm">
|
||||
The URL of your hosted proxy service.
|
||||
@@ -253,10 +158,15 @@ function Content() {
|
||||
<TextInput
|
||||
label="Credentials"
|
||||
type="password"
|
||||
value={proxyCredentials}
|
||||
onValueChange={handleCredentialsChange}
|
||||
value={userData.proxy?.credentials ?? ''}
|
||||
onValueChange={(v) => {
|
||||
setUserData((prev) => ({
|
||||
...prev,
|
||||
proxy: { ...prev.proxy, credentials: v },
|
||||
}));
|
||||
}}
|
||||
placeholder="Enter proxy credentials"
|
||||
disabled={isCredentialsForced || !proxyEnabled}
|
||||
disabled={isCredentialsForced || !userData.proxy?.enabled}
|
||||
/>
|
||||
{selectedProxyDetails && (
|
||||
<p className="text-[--muted] text-sm">
|
||||
@@ -275,12 +185,17 @@ function Content() {
|
||||
<div className="space-y-2">
|
||||
<Combobox
|
||||
label="Proxied Services"
|
||||
value={proxiedServices}
|
||||
onValueChange={handleProxiedServicesChange}
|
||||
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 || !proxyEnabled}
|
||||
disabled={isServicesForced || !userData.proxy?.enabled}
|
||||
emptyMessage="No services available"
|
||||
/>
|
||||
<p className="text-[--muted] text-sm">
|
||||
@@ -293,12 +208,17 @@ function Content() {
|
||||
<div className="space-y-2">
|
||||
<Combobox
|
||||
label="Proxied Addons"
|
||||
value={proxiedAddons}
|
||||
onValueChange={handleProxiedAddonsChange}
|
||||
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 || !proxyEnabled}
|
||||
disabled={isProxiedAddonsDisabled || !userData.proxy?.enabled}
|
||||
emptyMessage="No addons available"
|
||||
/>
|
||||
<p className="text-[--muted] text-sm">
|
||||
@@ -307,17 +227,6 @@ function Content() {
|
||||
</div>
|
||||
</SettingsCard>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-start mt-4">
|
||||
<Button
|
||||
intent="white"
|
||||
rounded
|
||||
onClick={handleSubmit}
|
||||
disabled={!hasChanges}
|
||||
>
|
||||
Save Changes
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -127,36 +127,7 @@ function Content() {
|
||||
const currentServices = userData.services ?? [];
|
||||
|
||||
// Remove any services not in SERVICE_DETAILS and apply forced/default credentials
|
||||
let filtered = currentServices
|
||||
.filter((s) => allServiceIds.includes(s.id))
|
||||
.map((service) => {
|
||||
const svcMeta = status.settings.services[service.id]!;
|
||||
const updatedCredentials = { ...service.credentials };
|
||||
let hasChanges = false;
|
||||
|
||||
svcMeta.credentials.forEach((cred) => {
|
||||
// Always apply forced credentials, regardless of existing value
|
||||
if (cred.forced) {
|
||||
if (updatedCredentials[cred.id] !== cred.forced) {
|
||||
updatedCredentials[cred.id] = cred.forced;
|
||||
hasChanges = true;
|
||||
}
|
||||
}
|
||||
// Only apply defaults for missing credentials
|
||||
else if (!service.credentials?.[cred.id] && cred.default) {
|
||||
updatedCredentials[cred.id] = cred.default;
|
||||
hasChanges = true;
|
||||
}
|
||||
});
|
||||
|
||||
// Only create a new object if there were changes
|
||||
return hasChanges
|
||||
? {
|
||||
...service,
|
||||
credentials: updatedCredentials,
|
||||
}
|
||||
: service;
|
||||
});
|
||||
let filtered = currentServices.filter((s) => allServiceIds.includes(s.id));
|
||||
|
||||
// Add any missing services from SERVICE_DETAILS
|
||||
const missing = allServiceIds.filter(
|
||||
@@ -169,18 +140,6 @@ function Content() {
|
||||
const credentials: Record<string, any> = {};
|
||||
let enabled = false;
|
||||
|
||||
// Apply forced/default credentials for new services
|
||||
svcMeta.credentials.forEach((cred) => {
|
||||
if (cred.forced) {
|
||||
credentials[cred.id] = cred.forced;
|
||||
// enable the service if it has forced credentials
|
||||
enabled = true;
|
||||
} else if (cred.default) {
|
||||
credentials[cred.id] = cred.default;
|
||||
enabled = true;
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
id,
|
||||
enabled,
|
||||
@@ -437,7 +396,6 @@ function SortableServiceItem({
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
function ServiceModal({
|
||||
open,
|
||||
onOpenChange,
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
import React from 'react';
|
||||
import { UserData } from '@aiostreams/core';
|
||||
import { QUALITIES, RESOLUTIONS } from '../../../core/src/utils/constants';
|
||||
import {
|
||||
QUALITIES,
|
||||
RESOLUTIONS,
|
||||
SERVICE_DETAILS,
|
||||
} from '../../../core/src/utils/constants';
|
||||
import { useStatus } from './status';
|
||||
|
||||
const DefaultUserData: UserData = {
|
||||
services: Object.values(SERVICE_DETAILS).map((service) => ({
|
||||
id: service.id,
|
||||
enabled: false,
|
||||
credentials: {},
|
||||
})),
|
||||
presets: [],
|
||||
formatter: {
|
||||
id: 'gdrive',
|
||||
@@ -56,6 +66,7 @@ const UserDataContext = React.createContext<UserDataContextType | undefined>(
|
||||
);
|
||||
|
||||
export function UserDataProvider({ children }: { children: React.ReactNode }) {
|
||||
const { status } = useStatus();
|
||||
const [userData, setUserData] = React.useState<UserData>(DefaultUserData);
|
||||
const [uuid, setUuid] = React.useState<string | null>(null);
|
||||
const [password, setPassword] = React.useState<string | null>(null);
|
||||
@@ -63,6 +74,93 @@ export function UserDataProvider({ children }: { children: React.ReactNode }) {
|
||||
string | null
|
||||
>(null);
|
||||
|
||||
// Effect to apply forced and default values from status
|
||||
React.useEffect(() => {
|
||||
if (!status) return;
|
||||
|
||||
const forced = status.settings.forced;
|
||||
const defaults = status.settings.defaults;
|
||||
const services = status.settings.services;
|
||||
|
||||
setUserData((prev) => {
|
||||
const newData = { ...prev };
|
||||
|
||||
// // Apply forced values first
|
||||
// if (forced.proxy) {
|
||||
// newData.proxy = {
|
||||
// ...newData.proxy,
|
||||
// enabled: forced.proxy.enabled ?? newData.proxy?.enabled ?? false,
|
||||
// id: (forced.proxy.id ?? newData.proxy?.id) as
|
||||
// | 'mediaflow'
|
||||
// | 'stremthru'
|
||||
// | undefined,
|
||||
// url: forced.proxy.url ?? newData.proxy?.url,
|
||||
// credentials: forced.proxy.credentials ?? newData.proxy?.credentials,
|
||||
// proxiedServices:
|
||||
// forced.proxy.proxiedServices ??
|
||||
// newData.proxy?.proxiedServices ??
|
||||
// [],
|
||||
// };
|
||||
// }
|
||||
|
||||
// // Apply default values if not already set
|
||||
// if (defaults.proxy) {
|
||||
// newData.proxy = {
|
||||
// ...newData.proxy,
|
||||
// enabled: defaults.proxy.enabled ?? false,
|
||||
// id: (newData.proxy?.id ?? defaults.proxy.id ?? undefined) as
|
||||
// | 'mediaflow'
|
||||
// | 'stremthru'
|
||||
// | undefined,
|
||||
// url: newData.proxy?.url ?? defaults.proxy.url ?? undefined,
|
||||
// credentials:
|
||||
// newData.proxy?.credentials ??
|
||||
// defaults.proxy.credentials ??
|
||||
// undefined,
|
||||
// proxiedServices:
|
||||
// newData.proxy?.proxiedServices ??
|
||||
// defaults.proxy.proxiedServices ??
|
||||
// [],
|
||||
// };
|
||||
// }
|
||||
newData.proxy = {
|
||||
...newData.proxy,
|
||||
enabled: forced.proxy.enabled ?? defaults.proxy?.enabled ?? undefined,
|
||||
id: (forced.proxy.id ?? defaults.proxy?.id) as
|
||||
| 'mediaflow'
|
||||
| 'stremthru'
|
||||
| undefined,
|
||||
url: forced.proxy.url ?? defaults.proxy?.url ?? undefined,
|
||||
credentials:
|
||||
forced.proxy.credentials ?? defaults.proxy?.credentials ?? undefined,
|
||||
proxiedServices:
|
||||
forced.proxy.proxiedServices ?? defaults.proxy?.proxiedServices ?? [],
|
||||
};
|
||||
|
||||
newData.services = (newData.services ?? []).map((service) => {
|
||||
const serviceMeta = services[service.id];
|
||||
if (!serviceMeta) return service;
|
||||
serviceMeta.credentials.forEach((credential) => {
|
||||
if (credential.forced) {
|
||||
service.credentials[credential.id] = credential.forced;
|
||||
} else if (credential.default) {
|
||||
service.credentials[credential.id] = credential.default;
|
||||
}
|
||||
});
|
||||
// enable if every credential is set
|
||||
service.enabled = serviceMeta.credentials.every(
|
||||
(credential) =>
|
||||
credential.forced ||
|
||||
credential.default ||
|
||||
service.credentials[credential.id] !== undefined
|
||||
);
|
||||
return service;
|
||||
});
|
||||
|
||||
return newData;
|
||||
});
|
||||
}, [status]);
|
||||
|
||||
const safeSetUserData = (
|
||||
data: ((prev: UserData) => UserData | null) | null
|
||||
) => {
|
||||
|
||||
Reference in New Issue
Block a user