327 lines
No EOL
13 KiB
TypeScript
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; |