import React, { useState } from "react"; import { Button, Form } from "react-bootstrap"; import { FormattedMessage, useIntl } from "react-intl"; import { useDisableDLNA, useDLNAStatus, useEnableDLNA, useAddTempDLNAIP, useRemoveTempDLNAIP, } from "src/core/StashService"; import { useToast } from "src/hooks"; import { DurationInput, Icon, LoadingIndicator, Modal } from "../Shared"; import { SettingSection } from "./SettingSection"; import { BooleanSetting, StringListSetting, StringSetting } from "./Inputs"; import { SettingStateContext } from "./context"; import { faClock, faTimes, faUserClock, } from "@fortawesome/free-solid-svg-icons"; export const SettingsServicesPanel: React.FC = () => { const intl = useIntl(); const Toast = useToast(); const { dlna, loading: configLoading, error, saveDLNA } = React.useContext( SettingStateContext ); // undefined to hide dialog, true for enable, false for disable const [enableDisable, setEnableDisable] = useState( undefined ); const [enableUntilRestart, setEnableUntilRestart] = useState(false); const [enableDuration, setEnableDuration] = useState( undefined ); const [ipEntry, setIPEntry] = useState(""); const [tempIP, setTempIP] = useState(); const { data: statusData, loading, refetch: statusRefetch } = useDLNAStatus(); const [enableDLNA] = useEnableDLNA(); const [disableDLNA] = useDisableDLNA(); const [addTempDLANIP] = useAddTempDLNAIP(); const [removeTempDLNAIP] = useRemoveTempDLNAIP(); if (error) return

{error.message}

; if (loading || configLoading) return ; async function onTempEnable() { const input = { variables: { input: { duration: enableUntilRestart ? undefined : enableDuration, }, }, }; try { if (enableDisable) { await enableDLNA(input); Toast.success({ content: intl.formatMessage({ id: "config.dlna.enabled_dlna_temporarily", }), }); } else { await disableDLNA(input); Toast.success({ content: intl.formatMessage({ id: "config.dlna.disabled_dlna_temporarily", }), }); } } catch (e) { Toast.error(e); } finally { setEnableDisable(undefined); statusRefetch(); } } async function onAllowTempIP() { if (!tempIP) { return; } const input = { variables: { input: { duration: enableUntilRestart ? undefined : enableDuration, address: tempIP, }, }, }; try { await addTempDLANIP(input); Toast.success({ content: intl.formatMessage({ id: "config.dlna.allowed_ip_temporarily", }), }); } catch (e) { Toast.error(e); } finally { setTempIP(undefined); statusRefetch(); } } async function onDisallowTempIP(address: string) { const input = { variables: { input: { address, }, }, }; try { await removeTempDLNAIP(input); Toast.success({ content: intl.formatMessage({ id: "config.dlna.disallowed_ip" }), }); } catch (e) { Toast.error(e); } finally { statusRefetch(); } } function renderDeadline(until?: string) { if (until) { const deadline = new Date(until); return `until ${intl.formatDate(deadline)}`; } return ""; } function renderStatus() { if (!statusData) { return ""; } const { dlnaStatus } = statusData; const runningText = intl.formatMessage({ id: dlnaStatus.running ? "actions.running" : "actions.not_running", }); return `${runningText} ${renderDeadline(dlnaStatus.until)}`; } function renderEnableButton() { // if enabled by default, then show the disable temporarily // if disabled by default, then show enable temporarily if (dlna.enabled) { return ( ); } return ( ); } function canCancel() { if (!statusData || !dlna) { return false; } const { dlnaStatus } = statusData; const { enabled } = dlna; return dlnaStatus.until || dlnaStatus.running !== enabled; } async function cancelTempBehaviour() { if (!canCancel()) { return; } const running = statusData?.dlnaStatus.running; const input = { variables: { input: {}, }, }; try { if (!running) { await enableDLNA(input); } else { await disableDLNA(input); } Toast.success({ content: intl.formatMessage({ id: "config.dlna.successfully_cancelled_temporary_behaviour", }), }); } catch (e) { Toast.error(e); } finally { setEnableDisable(undefined); statusRefetch(); } } function renderTempCancelButton() { if (!canCancel()) { return; } return ( ); } function renderTempEnableDialog() { const text: string = enableDisable ? "enable" : "disable"; const capitalised = `${text[0].toUpperCase()}${text.slice(1)}`; return ( setEnableDisable(undefined), variant: "secondary", }} >

{capitalised} temporarily

setEnableUntilRestart(!enableUntilRestart)} /> setEnableDuration(v ?? 0)} disabled={enableUntilRestart} /> Duration to {text} for - in minutes.
); } function renderTempWhitelistDialog() { return ( setTempIP(undefined), variant: "secondary", }} >

{`Allow ${tempIP} temporarily`}

setEnableUntilRestart(!enableUntilRestart)} /> setEnableDuration(v ?? 0)} disabled={enableUntilRestart} /> Duration to allow for - in minutes.
); } function renderAllowedIPs() { if (!statusData || statusData.dlnaStatus.allowedIPAddresses.length === 0) { return; } const { allowedIPAddresses } = statusData.dlnaStatus; return (
{intl.formatMessage({ id: "config.dlna.allowed_ip_addresses" })}
    {allowedIPAddresses.map((a) => (
  • {a.ipAddress}
    {renderDeadline(a.until)}
  • ))}
); } function renderRecentIPs() { if (!statusData) { return; } const { recentIPAddresses } = statusData.dlnaStatus; return (
    {recentIPAddresses.map((a) => (
  • {a}
  • ))}
  • ) => setIPEntry(e.currentTarget.value) } />
); } const DLNASettingsForm: React.FC = () => { return ( <> stash } )} value={dlna.serverName ?? undefined} onChange={(v) => saveDLNA({ serverName: v })} /> saveDLNA({ enabled: v })} /> saveDLNA({ interfaces: v })} /> * } )} defaultNewValue="*" value={dlna.whitelistedIPs ?? undefined} onChange={(v) => saveDLNA({ whitelistedIPs: v })} /> ); }; return (
{renderTempEnableDialog()} {renderTempWhitelistDialog()}

DLNA

{intl.formatMessage({ id: "status" }, { statusText: renderStatus() })}
{renderEnableButton()} {renderTempCancelButton()} {renderAllowedIPs()}
{intl.formatMessage({ id: "config.dlna.recent_ip_addresses" })}
{renderRecentIPs()}
); };