Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Settings page use controlled components #4

Merged
merged 2 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions web2/src/helpers/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,7 @@ export const fromStringResolution = (
const [h, w] = res.split('x', 1);
return { widthPx: parseInt(w), heightPx: parseInt(h) };
};

export const hasOnlyDigits = (value: string) => {
return /^-?\d+$/.test(value);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should prob add the global flag to the regex: /^-?\d+$/g

};
227 changes: 164 additions & 63 deletions web2/src/pages/settings/FfmpegSettingsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import React, { useEffect } from 'react';
import {
Button,
Checkbox,
Expand All @@ -6,21 +7,29 @@ import {
FormControlLabel,
InputLabel,
MenuItem,
Paper,
Stack,
Select,
TextField,
Typography,
SelectChangeEvent,
Alert,
} from '@mui/material';
import { useFfmpegSettings } from '../../hooks/settingsHooks.ts';
import { hasOnlyDigits } from '../../helpers/util.ts';

const supportedVideoBuffer = [
{ value: 0, string: '0 Seconds' },
{ value: 1000, string: '1 Second' },
{ value: 2000, string: '2 Seconds' },
{ value: 3000, string: '3 Seconds' },
{ value: 4000, string: '4 Seconds' },
{ value: 5000, string: '5 Seconds' },
{ value: 10000, string: '10 Seconds' },
];

export default function FfmpegSettingsPage() {
const { data, isPending, error } = useFfmpegSettings();

if (isPending || error) {
return <div></div>;
}

const defaultFFMPEGSettings = {
ffmpegExecutablePath: '/usr/bin/ffmpeg',
numThreads: 4,
Expand All @@ -29,68 +38,160 @@ export default function FfmpegSettingsPage() {
enableTranscoding: false,
};

const [ffmpegExecutablePath, setFfmpegExecutablePath] =
React.useState<string>(defaultFFMPEGSettings.ffmpegExecutablePath);

const [numThreads, setNumThreads] = React.useState<string>(
defaultFFMPEGSettings.numThreads.toString(),
);

const [enableLogging, setEnableLogging] = React.useState<boolean>(
defaultFFMPEGSettings.enableLogging,
);

const [videoBufferSize, setVideoBufferSize] = React.useState<string>(
defaultFFMPEGSettings.videoBufferSize.toString(),
);

const [enableTranscoding, setEnableTranscoding] = React.useState<boolean>(
defaultFFMPEGSettings.enableTranscoding,
);

const [showFormError, setShowFormError] = React.useState<boolean>(false);

useEffect(() => {
setFfmpegExecutablePath(
data?.ffmpegExecutablePath || defaultFFMPEGSettings.ffmpegExecutablePath,
);

setNumThreads(
data?.numThreads.toString() ||
defaultFFMPEGSettings.numThreads.toString(),
);

setEnableLogging(
data?.enableLogging || defaultFFMPEGSettings.enableLogging,
);

setVideoBufferSize(
data?.videoBufferSize.toString() ||
defaultFFMPEGSettings.videoBufferSize.toString(),
);

setEnableTranscoding(
data?.enableTranscoding || defaultFFMPEGSettings.enableTranscoding,
);
}, [data]);

const handleFfmpegExecutablePath = (
event: React.ChangeEvent<HTMLInputElement>,
) => {
setFfmpegExecutablePath(event.target.value);
};

const handleNumThreads = (event: React.ChangeEvent<HTMLInputElement>) => {
setNumThreads(event.target.value);
};

const handleEnableLogging = () => {
setEnableLogging(!enableLogging);
};

const handleVideoBufferSize = (event: SelectChangeEvent<string>) => {
setVideoBufferSize(event.target.value);
};

const handleEnableTranscoding = () => {
setEnableTranscoding(!enableTranscoding);
};

const handleValidateFields = (event: React.FocusEvent<HTMLInputElement>) => {
setShowFormError(!hasOnlyDigits(event.target.value));
};

if (isPending || error) {
return <div></div>;
}

return (
<>
<Paper>
<FormControl fullWidth>
<TextField
id="executable-path"
label="Executable Path"
defaultValue={data.ffmpegExecutablePath}
helperText={
'FFMPEG version 4.2+ required. Check by opening the version tab'
}
/>
</FormControl>
<Typography variant="h6" sx={{ my: 2 }}>
Miscellaneous Options
</Typography>
<Stack spacing={2} direction={{ sm: 'column', md: 'row' }}>
<TextField label="Threads" defaultValue={data.numThreads} />
<FormControlLabel
control={<Checkbox />}
label="Log FFMPEG to console"
/>
</Stack>
<FormControl sx={{ mt: 2 }}>
<InputLabel id="video-buffer-size-label">Video Buffer</InputLabel>
<Select
labelId="video-buffer-size-label"
id="video-buffer-size"
value={data.videoBufferSize}
label="Video Buffer"
>
<MenuItem value={0}>0 Seconds</MenuItem>
<MenuItem value={1000}>1 Second</MenuItem>
<MenuItem value={2000}>2 Seconds</MenuItem>
<MenuItem value={3000}>3 Seconds</MenuItem>
<MenuItem value={4000}>4 Seconds</MenuItem>
<MenuItem value={5000}>5 Seconds</MenuItem>
<MenuItem value={10000}>10 Seconds</MenuItem>
</Select>
<FormHelperText>
Note: If you experience playback issues upon stream start, try
increasing this.
</FormHelperText>
</FormControl>
<Typography variant="h6" sx={{ my: 2 }}>
Transcoding Features
</Typography>
<FormControl>
<FormControlLabel
control={<Checkbox />}
label="Enable FFMPEG Transcoding"
/>
<FormHelperText>
Transcoding is required for some features like channel overlay and
measures to prevent issues when switching episodes. The trade-off is
quality loss and additional computing resource requirements.
</FormHelperText>
</FormControl>
</Paper>
<FormControl fullWidth>
<TextField
id="executable-path"
label="Executable Path"
value={ffmpegExecutablePath}
onChange={handleFfmpegExecutablePath}
helperText={
'FFMPEG version 4.2+ required. Check by opening the version tab'
}
/>
</FormControl>
<Typography variant="h6" sx={{ my: 2 }}>
Miscellaneous Options
</Typography>
{showFormError && (
<Alert severity="error" sx={{ my: 2 }}>
Invalid input. Please make sure number of threads is a number
</Alert>
)}
<Stack spacing={2} direction={{ sm: 'column', md: 'row' }}>
<TextField
label="Threads"
value={numThreads}
onChange={handleNumThreads}
onBlur={handleValidateFields}
/>
<FormControlLabel
control={
<Checkbox checked={enableLogging} onChange={handleEnableLogging} />
}
label="Log FFMPEG to console"
/>
</Stack>
<FormControl sx={{ mt: 2 }}>
<InputLabel id="video-buffer-size-label">Video Buffer</InputLabel>
<Select
labelId="video-buffer-size-label"
id="video-buffer-size"
value={videoBufferSize}
onChange={handleVideoBufferSize}
label="Video Buffer"
>
{supportedVideoBuffer.map((buffer) => (
<MenuItem key={buffer.value} value={buffer.value}>
{buffer.string}
</MenuItem>
))}
</Select>
<FormHelperText>
Note: If you experience playback issues upon stream start, try
increasing this.
</FormHelperText>
</FormControl>
<Typography variant="h6" sx={{ my: 2 }}>
Transcoding Features
</Typography>
<FormControl>
<FormControlLabel
control={
<Checkbox
checked={enableTranscoding}
onChange={handleEnableTranscoding}
/>
}
label="Enable FFMPEG Transcoding"
/>
<FormHelperText>
Transcoding is required for some features like channel overlay and
measures to prevent issues when switching episodes. The trade-off is
quality loss and additional computing resource requirements.
</FormHelperText>
</FormControl>
<Stack spacing={2} direction="row" justifyContent="right" sx={{ mt: 2 }}>
<Button variant="outlined">Reset Options</Button>
<Button variant="contained">Save</Button>
<Button variant="contained" disabled={showFormError}>
Save
</Button>
</Stack>
</>
);
Expand Down
3 changes: 1 addition & 2 deletions web2/src/pages/settings/GeneralSettingsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { Button, Paper, Stack } from '@mui/material';
import { Button, Stack } from '@mui/material';

export default function GeneralSettingsPage() {
return (
<>
<Paper></Paper>
<Stack spacing={2} direction="row" justifyContent="right" sx={{ mt: 2 }}>
<Button variant="outlined">Reset Options</Button>
<Button variant="contained">Save</Button>
Expand Down
33 changes: 14 additions & 19 deletions web2/src/pages/settings/HdhrSettingsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import {
Box,
Button,
Checkbox,
FormControl,
FormLabel,
FormControlLabel,
FormHelperText,
Paper,
Stack,
TextField,
} from '@mui/material';
Expand All @@ -28,22 +25,20 @@ export default function HdhrSettingsPage() {

return (
<>
<Paper>
<FormControl>
<Checkbox />
<FormLabel>Enable SSDP server</FormLabel>
<FormHelperText>* Restart required</FormHelperText>
</FormControl>
<TextField
fullWidth
id="output-path"
label="Tuner Count"
defaultValue={'2'}
InputProps={{ readOnly: true }}
variant="filled"
sx={{ mt: 2, mb: 2 }}
/>
</Paper>
<FormControl>
<Checkbox />
<FormLabel>Enable SSDP server</FormLabel>
<FormHelperText>* Restart required</FormHelperText>
</FormControl>
<TextField
fullWidth
id="output-path"
label="Tuner Count"
defaultValue={'2'}
InputProps={{ readOnly: true }}
variant="filled"
sx={{ mt: 2, mb: 2 }}
/>
<Stack spacing={2} direction="row" justifyContent="right" sx={{ mt: 2 }}>
<Button variant="outlined">Reset Options</Button>
<Button variant="contained">Save</Button>
Expand Down
Loading