multi-downloader-nx/gui/react/src/components/AddToQueue/DownloadSelector/DownloadSelector.tsx
2024-04-06 09:10:48 -07:00

327 lines
No EOL
13 KiB
TypeScript

import React, { ChangeEvent } from 'react';
import { Box, Button, Divider, FormControl, InputBase, InputLabel, Link, MenuItem, Select, TextField, Tooltip, Typography } from '@mui/material';
import useStore from '../../../hooks/useStore';
import MultiSelect from '../../reusable/MultiSelect';
import { messageChannelContext } from '../../../provider/MessageChannel';
import LoadingButton from '@mui/lab/LoadingButton';
import { useSnackbar } from 'notistack';
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
type DownloadSelectorProps = {
onFinish?: () => unknown
}
const DownloadSelector: React.FC<DownloadSelectorProps> = ({ onFinish }) => {
const messageHandler = React.useContext(messageChannelContext);
const [store, dispatch] = useStore();
const [availableDubs, setAvailableDubs] = React.useState<string[]>([]);
const [availableSubs, setAvailableSubs ] = React.useState<string[]>([]);
const [ loading, setLoading ] = React.useState(false);
const { enqueueSnackbar } = useSnackbar();
const ITEM_HEIGHT = 48;
const ITEM_PADDING_TOP = 8;
React.useEffect(() => {
(async () => {
/* If we don't wait the response is undefined? */
await new Promise((resolve) => setTimeout(() => resolve(undefined), 100));
const dubLang = messageHandler?.handleDefault('dubLang');
const subLang = messageHandler?.handleDefault('dlsubs');
const q = messageHandler?.handleDefault('q');
const fileName = messageHandler?.handleDefault('fileName');
const dlVideoOnce = messageHandler?.handleDefault('dlVideoOnce');
const result = await Promise.all([dubLang, subLang, q, fileName, dlVideoOnce]);
dispatch({
type: 'downloadOptions',
payload: {
...store.downloadOptions,
dubLang: result[0],
dlsubs: result[1],
q: result[2],
fileName: result[3],
dlVideoOnce: result[4],
}
});
setAvailableDubs(await messageHandler?.availableDubCodes() ?? []);
setAvailableSubs(await messageHandler?.availableSubCodes() ?? []);
})();
}, []);
const addToQueue = async () => {
setLoading(true);
const res = await messageHandler?.resolveItems(store.downloadOptions);
if (!res)
return enqueueSnackbar('The request failed. Please check if the ID is correct.', {
variant: 'error'
});
setLoading(false);
if (onFinish)
onFinish();
};
const listEpisodes = async () => {
if (!store.downloadOptions.id) {
return enqueueSnackbar('Please enter a ID', {
variant: 'error'
});
}
setLoading(true);
const res = await messageHandler?.listEpisodes(store.downloadOptions.id);
if (!res || !res.isOk) {
setLoading(false);
return enqueueSnackbar('The request failed. Please check if the ID is correct.', {
variant: 'error'
});
} else {
dispatch({
type: 'episodeListing',
payload: res.value
});
}
setLoading(false);
};
return <Box sx={{ display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center' }}>
<Box sx={{display: 'flex',
flexDirection: 'column',
alignItems: 'center',
margin: '5px',
}}>
<Box sx={{
width: '50rem',
height: '21rem',
margin: '10px',
display: 'flex',
justifyContent: 'space-between',
//backgroundColor: '#ffffff30',
}}>
<Box sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: '0.7rem',
//backgroundColor: '#ff000030'
}}>
<Typography sx={{fontSize: '1.4rem'}}>
General Options
</Typography>
<TextField value={store.downloadOptions.id} required onChange={e => {
dispatch({
type: 'downloadOptions',
payload: { ...store.downloadOptions, id: e.target.value }
});
}} label='Show ID'/>
<TextField type='number' value={store.downloadOptions.q} required onChange={e => {
const parsed = parseInt(e.target.value);
if (isNaN(parsed) || parsed < 0 || parsed > 10)
return;
dispatch({
type: 'downloadOptions',
payload: { ...store.downloadOptions, q: parsed }
});
}} label='Quality Level (0 for max)'/>
<Box sx={{ display: 'flex', gap: '5px' }}>
<Button sx={{ textTransform: 'none'}} onClick={() => dispatch({ type: 'downloadOptions', payload: { ...store.downloadOptions, noaudio: !store.downloadOptions.noaudio } })} variant={store.downloadOptions.noaudio ? 'contained' : 'outlined'}>Skip Audio</Button>
<Button sx={{ textTransform: 'none'}} onClick={() => dispatch({ type: 'downloadOptions', payload: { ...store.downloadOptions, novids: !store.downloadOptions.novids } })} variant={store.downloadOptions.novids ? 'contained' : 'outlined'}>Skip Video</Button>
</Box>
<Button sx={{ textTransform: 'none'}} onClick={() => dispatch({ type: 'downloadOptions', payload: { ...store.downloadOptions, dlVideoOnce: !store.downloadOptions.dlVideoOnce } })} variant={store.downloadOptions.dlVideoOnce ? 'contained' : 'outlined'}>Skip Unnecessary</Button>
<Tooltip title={store.service == 'hidive' ? '' :
<Typography>
Simulcast is only supported on Hidive
</Typography>}
arrow placement='top'
>
<Box>
<Button sx={{ textTransform: 'none'}} disabled={store.service != 'hidive'} onClick={() => dispatch({ type: 'downloadOptions', payload: { ...store.downloadOptions, simul: !store.downloadOptions.simul } })} variant={store.downloadOptions.simul ? 'contained' : 'outlined'}>Download Simulcast ver.</Button>
</Box>
</Tooltip>
</Box>
<Box sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: '0.7rem',
//backgroundColor: '#00000020'
}}>
<Typography sx={{fontSize: '1.4rem'}}>
Episode Options
</Typography>
<Box sx={{
display: 'flex',
flexDirection: 'column',
gap: '1px'
}}>
<Box sx={{
borderColor: '#595959',
borderStyle: 'solid',
borderWidth: '1px',
borderRadius: '5px',
//backgroundColor: '#ff4567',
width: '15rem',
height: '3.5rem',
display: 'flex',
'&:hover' : {
borderColor: '#ffffff',
},
}}>
<InputBase sx={{
ml: 2,
flex: 1,
}}
disabled={store.downloadOptions.all} value={store.downloadOptions.e} required onChange={e => {
dispatch({
type: 'downloadOptions',
payload: { ...store.downloadOptions, e: e.target.value }
});
}} placeholder='Episode Select'/>
<Divider orientation='vertical'/>
<LoadingButton loading={loading} disableElevation disableFocusRipple disableRipple disableTouchRipple onClick={listEpisodes} variant='text' sx={{ textTransform: 'none'}}><Typography>List<br/>Episodes</Typography></LoadingButton>
</Box>
</Box>
<Button sx={{ textTransform: 'none'}} onClick={() => dispatch({ type: 'downloadOptions', payload: { ...store.downloadOptions, all: !store.downloadOptions.all } })} variant={store.downloadOptions.all ? 'contained' : 'outlined'}>Download All</Button>
<Button sx={{ textTransform: 'none'}} onClick={() => dispatch({ type: 'downloadOptions', payload: { ...store.downloadOptions, but: !store.downloadOptions.but } })} variant={store.downloadOptions.but ? 'contained' : 'outlined'}>Download All but</Button>
</Box>
<Box sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: '0.7rem',
//backgroundColor: '#00ff0020'
}}>
<Typography sx={{fontSize: '1.4rem'}}>
Language Options
</Typography>
<MultiSelect
title='Dub Languages'
values={availableDubs}
selected={store.downloadOptions.dubLang}
onChange={(e) => {
dispatch({
type: 'downloadOptions',
payload: { ...store.downloadOptions, dubLang: e }
});
}}
allOption
/>
<MultiSelect
title='Sub Languages'
values={availableSubs}
selected={store.downloadOptions.dlsubs}
onChange={(e) => {
dispatch({
type: 'downloadOptions',
payload: { ...store.downloadOptions, dlsubs: e }
});
}}
/>
<Tooltip title={store.service == 'crunchy' ? '' :
<Typography>
Hardsubs are only supported on Crunchyroll
</Typography>
}
arrow placement='top'>
<Box sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: '100%',
gap: '1rem'
}}>
<Box sx={{
borderRadius: '5px',
//backgroundColor: '#ff4567',
width: '15rem',
height: '3.5rem',
display: 'flex',
}}>
<FormControl fullWidth>
<InputLabel id='hsLabel'>Hardsub Language</InputLabel>
<Select
MenuProps={{
PaperProps: {
style: {
maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP,
width: 250
}
}
}}
labelId='hsLabel'
label='Hardsub Language'
disabled={store.service != 'crunchy'}
value={store.downloadOptions.hslang}
onChange={(e) => {
dispatch({
type: 'downloadOptions',
payload: { ...store.downloadOptions, hslang: (e.target.value as string) === '' ? undefined : e.target.value as string }
});
}}
>
<MenuItem value=''>No Hardsub</MenuItem>
{availableSubs.map((lang) => {
if(lang === 'all' || lang === 'none')
return undefined;
return <MenuItem value={lang}>{lang}</MenuItem>;
})}
</Select>
</FormControl>
</Box>
<Tooltip title={
<Typography>
Downloads the hardsub version of the selected subtitle.<br/>Subtitles are displayed <b>PERMANENTLY!</b><br/>You can choose only <b>1</b> subtitle per video!
</Typography>
} arrow placement='top'>
<InfoOutlinedIcon sx={{
transition: '100ms',
ml: '0.35rem',
mr: '0.65rem',
'&:hover' : {
color: '#ffffff30',
}
}} />
</Tooltip>
</Box>
</Tooltip>
</Box>
</Box>
<Box sx={{width: '95%', height: '0.3rem', backgroundColor: '#ffffff50', borderRadius: '10px', marginBottom: '20px'}}/>
<Box sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: '100%',
gap: '15px'
}}>
<TextField value={store.downloadOptions.fileName} onChange={e => {
dispatch({
type: 'downloadOptions',
payload: { ...store.downloadOptions, fileName: e.target.value }
});
}} sx={{ width: '87%' }} label='Filename Overwrite' />
<Tooltip title={
<Typography>
Click here to see the documentation
</Typography>
} arrow placement='top'>
<Link href='https://github.com/anidl/multi-downloader-nx/blob/master/docs/DOCUMENTATION.md#filename-template' rel="noopener noreferrer" target="_blank">
<InfoOutlinedIcon sx={{
transition: '100ms',
'&:hover' : {
color: '#ffffff30',
}
}} />
</Link>
</Tooltip>
</Box>
</Box>
<Box sx={{width: '95%', height: '0.3rem', backgroundColor: '#ffffff50', borderRadius: '10px', marginTop: '10px'}}/>
<LoadingButton sx={{ margin: '15px', textTransform: 'none' }} loading={loading} onClick={addToQueue} variant='contained'>Add to Queue</LoadingButton>
</Box>;
};
export default DownloadSelector;