mirror of
https://github.com/Ernous/TorrServerJellyfin.git
synced 2025-12-19 21:46:11 +05:00
Merge branch 'settings-dialog'
This commit is contained in:
@@ -23,6 +23,7 @@
|
|||||||
"react-measure": "^2.5.2",
|
"react-measure": "^2.5.2",
|
||||||
"react-query": "^3.17.0",
|
"react-query": "^3.17.0",
|
||||||
"react-scripts": "4.0.3",
|
"react-scripts": "4.0.3",
|
||||||
|
"react-swipeable-views": "^0.14.0",
|
||||||
"styled-components": "^5.3.0",
|
"styled-components": "^5.3.0",
|
||||||
"uuid": "^8.3.2"
|
"uuid": "^8.3.2"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -12,9 +12,10 @@ import usePreviousState from 'utils/usePreviousState'
|
|||||||
import { useQuery } from 'react-query'
|
import { useQuery } from 'react-query'
|
||||||
import { getTorrents } from 'utils/Utils'
|
import { getTorrents } from 'utils/Utils'
|
||||||
import parseTorrent from 'parse-torrent'
|
import parseTorrent from 'parse-torrent'
|
||||||
|
import { ButtonWrapper, Header } from 'style/DialogStyles'
|
||||||
|
|
||||||
import { checkImageURL, getMoviePosters, chechTorrentSource, parseTorrentTitle } from './helpers'
|
import { checkImageURL, getMoviePosters, chechTorrentSource, parseTorrentTitle } from './helpers'
|
||||||
import { ButtonWrapper, Content, Header } from './style'
|
import { Content } from './style'
|
||||||
import RightSideComponent from './RightSideComponent'
|
import RightSideComponent from './RightSideComponent'
|
||||||
import LeftSideComponent from './LeftSideComponent'
|
import LeftSideComponent from './LeftSideComponent'
|
||||||
|
|
||||||
@@ -219,14 +220,7 @@ export default function AddDialog({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog open onClose={handleClose} fullScreen={fullScreen} fullWidth maxWidth='md'>
|
||||||
open
|
|
||||||
onClose={handleClose}
|
|
||||||
aria-labelledby='form-dialog-title'
|
|
||||||
fullScreen={fullScreen}
|
|
||||||
fullWidth
|
|
||||||
maxWidth='md'
|
|
||||||
>
|
|
||||||
<Header>{t(isEditMode ? 'EditTorrent' : 'AddNewTorrent')}</Header>
|
<Header>{t(isEditMode ? 'EditTorrent' : 'AddNewTorrent')}</Header>
|
||||||
|
|
||||||
<Content isEditMode={isEditMode}>
|
<Content isEditMode={isEditMode}>
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export const checkImageURL = async url => {
|
|||||||
if (!url || !url.match(/.(jpg|jpeg|png|gif)$/i)) return false
|
if (!url || !url.match(/.(jpg|jpeg|png|gif)$/i)) return false
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await fetch(url)
|
await fetch(url, { mode: 'no-cors' })
|
||||||
return true
|
return true
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export default function AddDialogButton({ isOffline, isLoading }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<ListItem disabled={isOffline || isLoading} button key='Add' onClick={handleClickOpen}>
|
<ListItem disabled={isOffline || isLoading} button onClick={handleClickOpen}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<LibraryAddIcon />
|
<LibraryAddIcon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
|
|||||||
@@ -1,19 +1,6 @@
|
|||||||
import { Button } from '@material-ui/core'
|
import { Button } from '@material-ui/core'
|
||||||
import styled, { css } from 'styled-components'
|
import styled, { css } from 'styled-components'
|
||||||
|
|
||||||
export const Header = styled.div`
|
|
||||||
${({ theme: { primary } }) => css`
|
|
||||||
background: ${primary};
|
|
||||||
color: rgba(0, 0, 0, 0.87);
|
|
||||||
font-size: 20px;
|
|
||||||
color: #fff;
|
|
||||||
font-weight: 600;
|
|
||||||
box-shadow: 0px 2px 4px -1px rgb(0 0 0 / 20%), 0px 4px 5px 0px rgb(0 0 0 / 14%), 0px 1px 10px 0px rgb(0 0 0 / 12%);
|
|
||||||
padding: 15px 24px;
|
|
||||||
position: relative;
|
|
||||||
`}
|
|
||||||
`
|
|
||||||
|
|
||||||
export const Content = styled.div`
|
export const Content = styled.div`
|
||||||
${({
|
${({
|
||||||
isEditMode,
|
isEditMode,
|
||||||
@@ -349,13 +336,3 @@ export const PosterLanguageSwitch = styled.div`
|
|||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
`
|
`
|
||||||
|
|
||||||
export const ButtonWrapper = styled.div`
|
|
||||||
padding: 20px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
|
|
||||||
> :not(:last-child) {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ const Sidebar = ({ isDrawerOpen, setIsDonationDialogOpen, isOffline, isLoading }
|
|||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
<List>
|
<List>
|
||||||
<SettingsDialog />
|
<SettingsDialog isOffline={isOffline} isLoading={isLoading} />
|
||||||
|
|
||||||
<AboutDialog />
|
<AboutDialog />
|
||||||
|
|
||||||
|
|||||||
@@ -1,297 +0,0 @@
|
|||||||
import axios from 'axios'
|
|
||||||
import ListItem from '@material-ui/core/ListItem'
|
|
||||||
import ListItemIcon from '@material-ui/core/ListItemIcon'
|
|
||||||
import ListItemText from '@material-ui/core/ListItemText'
|
|
||||||
import { useEffect, useState } from 'react'
|
|
||||||
import SettingsIcon from '@material-ui/icons/Settings'
|
|
||||||
import Dialog from '@material-ui/core/Dialog'
|
|
||||||
import DialogTitle from '@material-ui/core/DialogTitle'
|
|
||||||
import DialogContent from '@material-ui/core/DialogContent'
|
|
||||||
import TextField from '@material-ui/core/TextField'
|
|
||||||
import DialogActions from '@material-ui/core/DialogActions'
|
|
||||||
import Button from '@material-ui/core/Button'
|
|
||||||
import { FormControlLabel, InputLabel, Select, Switch } from '@material-ui/core'
|
|
||||||
import { settingsHost, setTorrServerHost, getTorrServerHost } from 'utils/Hosts'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import { ThemeProvider } from '@material-ui/core/styles'
|
|
||||||
|
|
||||||
import { lightTheme } from '../style/materialUISetup'
|
|
||||||
|
|
||||||
export default function SettingsDialog() {
|
|
||||||
const { t } = useTranslation()
|
|
||||||
const [open, setOpen] = useState(false)
|
|
||||||
const [settings, setSets] = useState({})
|
|
||||||
const [show, setShow] = useState(false)
|
|
||||||
const [tsHost, setTSHost] = useState(getTorrServerHost())
|
|
||||||
|
|
||||||
const handleClickOpen = () => setOpen(true)
|
|
||||||
const handleClose = () => setOpen(false)
|
|
||||||
const handleSave = () => {
|
|
||||||
setOpen(false)
|
|
||||||
const sets = JSON.parse(JSON.stringify(settings))
|
|
||||||
sets.CacheSize *= 1024 * 1024
|
|
||||||
axios.post(settingsHost(), { action: 'set', sets })
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
axios
|
|
||||||
.post(settingsHost(), { action: 'get' })
|
|
||||||
.then(({ data }) => {
|
|
||||||
setSets({ ...data, CacheSize: data.CacheSize / (1024 * 1024) })
|
|
||||||
setShow(true)
|
|
||||||
})
|
|
||||||
.catch(() => setShow(false))
|
|
||||||
}, [tsHost])
|
|
||||||
|
|
||||||
const onInputHost = ({ target: { value } }) => {
|
|
||||||
const host = value.replace(/\/$/gi, '')
|
|
||||||
setTorrServerHost(host)
|
|
||||||
setTSHost(host)
|
|
||||||
}
|
|
||||||
|
|
||||||
const inputForm = ({ target: { type, value, checked, id } }) => {
|
|
||||||
const sets = JSON.parse(JSON.stringify(settings))
|
|
||||||
if (type === 'number' || type === 'select-one') {
|
|
||||||
sets[id] = Number(value)
|
|
||||||
} else if (type === 'checkbox') {
|
|
||||||
if (
|
|
||||||
id === 'DisableTCP' ||
|
|
||||||
id === 'DisableUTP' ||
|
|
||||||
id === 'DisableUPNP' ||
|
|
||||||
id === 'DisableDHT' ||
|
|
||||||
id === 'DisablePEX' ||
|
|
||||||
id === 'DisableUpload'
|
|
||||||
)
|
|
||||||
sets[id] = Boolean(!checked)
|
|
||||||
else sets[id] = Boolean(checked)
|
|
||||||
} else if (type === 'url') {
|
|
||||||
sets[id] = value
|
|
||||||
}
|
|
||||||
setSets(sets)
|
|
||||||
}
|
|
||||||
|
|
||||||
const {
|
|
||||||
CacheSize,
|
|
||||||
PreloadBuffer,
|
|
||||||
ReaderReadAHead,
|
|
||||||
RetrackersMode,
|
|
||||||
TorrentDisconnectTimeout,
|
|
||||||
EnableIPv6,
|
|
||||||
ForceEncrypt,
|
|
||||||
DisableTCP,
|
|
||||||
DisableUTP,
|
|
||||||
DisableUPNP,
|
|
||||||
DisableDHT,
|
|
||||||
DisablePEX,
|
|
||||||
DisableUpload,
|
|
||||||
DownloadRateLimit,
|
|
||||||
UploadRateLimit,
|
|
||||||
ConnectionsLimit,
|
|
||||||
DhtConnectionLimit,
|
|
||||||
PeersListenPort,
|
|
||||||
UseDisk,
|
|
||||||
TorrentsSavePath,
|
|
||||||
RemoveCacheOnDrop,
|
|
||||||
} = settings
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<ListItem button key={t('Settings')} onClick={handleClickOpen}>
|
|
||||||
<ListItemIcon>
|
|
||||||
<SettingsIcon />
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemText primary={t('Settings')} />
|
|
||||||
</ListItem>
|
|
||||||
|
|
||||||
<ThemeProvider theme={lightTheme}>
|
|
||||||
<Dialog open={open} onClose={handleClose} aria-labelledby='form-dialog-title' fullWidth>
|
|
||||||
<DialogTitle id='form-dialog-title'>{t('Settings')}</DialogTitle>
|
|
||||||
<DialogContent>
|
|
||||||
<TextField
|
|
||||||
onChange={onInputHost}
|
|
||||||
margin='dense'
|
|
||||||
id='TorrServerHost'
|
|
||||||
label={t('Host')}
|
|
||||||
value={tsHost}
|
|
||||||
type='url'
|
|
||||||
fullWidth
|
|
||||||
/>
|
|
||||||
{show && (
|
|
||||||
<>
|
|
||||||
<TextField
|
|
||||||
onChange={inputForm}
|
|
||||||
margin='dense'
|
|
||||||
id='CacheSize'
|
|
||||||
label={t('CacheSize')}
|
|
||||||
value={CacheSize}
|
|
||||||
type='number'
|
|
||||||
fullWidth
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<TextField
|
|
||||||
onChange={inputForm}
|
|
||||||
margin='dense'
|
|
||||||
id='ReaderReadAHead'
|
|
||||||
label={t('ReaderReadAHead')}
|
|
||||||
value={ReaderReadAHead}
|
|
||||||
type='number'
|
|
||||||
fullWidth
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<FormControlLabel
|
|
||||||
control={<Switch checked={PreloadBuffer} onChange={inputForm} id='PreloadBuffer' color='primary' />}
|
|
||||||
label={t('PreloadBuffer')}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<FormControlLabel
|
|
||||||
control={<Switch checked={UseDisk} onChange={inputForm} id='UseDisk' color='primary' />}
|
|
||||||
label={t('UseDisk')}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<small>{t('UseDiskDesc')}</small>
|
|
||||||
<br />
|
|
||||||
<FormControlLabel
|
|
||||||
control={
|
|
||||||
<Switch checked={RemoveCacheOnDrop} onChange={inputForm} id='RemoveCacheOnDrop' color='primary' />
|
|
||||||
}
|
|
||||||
label={t('RemoveCacheOnDrop')}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<small>{t('RemoveCacheOnDropDesc')}</small>
|
|
||||||
<br />
|
|
||||||
<TextField
|
|
||||||
onChange={inputForm}
|
|
||||||
margin='dense'
|
|
||||||
id='TorrentsSavePath'
|
|
||||||
label={t('TorrentsSavePath')}
|
|
||||||
value={TorrentsSavePath}
|
|
||||||
type='url'
|
|
||||||
fullWidth
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<FormControlLabel
|
|
||||||
control={<Switch checked={EnableIPv6} onChange={inputForm} id='EnableIPv6' color='primary' />}
|
|
||||||
label={t('EnableIPv6')}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<FormControlLabel
|
|
||||||
control={<Switch checked={!DisableTCP} onChange={inputForm} id='DisableTCP' color='primary' />}
|
|
||||||
label={t('TCP')}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<FormControlLabel
|
|
||||||
control={<Switch checked={!DisableUTP} onChange={inputForm} id='DisableUTP' color='primary' />}
|
|
||||||
label={t('UTP')}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<FormControlLabel
|
|
||||||
control={<Switch checked={!DisablePEX} onChange={inputForm} id='DisablePEX' color='primary' />}
|
|
||||||
label={t('PEX')}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<FormControlLabel
|
|
||||||
control={<Switch checked={ForceEncrypt} onChange={inputForm} id='ForceEncrypt' color='primary' />}
|
|
||||||
label={t('ForceEncrypt')}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<TextField
|
|
||||||
onChange={inputForm}
|
|
||||||
margin='dense'
|
|
||||||
id='TorrentDisconnectTimeout'
|
|
||||||
label={t('TorrentDisconnectTimeout')}
|
|
||||||
value={TorrentDisconnectTimeout}
|
|
||||||
type='number'
|
|
||||||
fullWidth
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<TextField
|
|
||||||
onChange={inputForm}
|
|
||||||
margin='dense'
|
|
||||||
id='ConnectionsLimit'
|
|
||||||
label={t('ConnectionsLimit')}
|
|
||||||
value={ConnectionsLimit}
|
|
||||||
type='number'
|
|
||||||
fullWidth
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<FormControlLabel
|
|
||||||
control={<Switch checked={!DisableDHT} onChange={inputForm} id='DisableDHT' color='primary' />}
|
|
||||||
label={t('DHT')}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<TextField
|
|
||||||
onChange={inputForm}
|
|
||||||
margin='dense'
|
|
||||||
id='DhtConnectionLimit'
|
|
||||||
label={t('DhtConnectionLimit')}
|
|
||||||
value={DhtConnectionLimit}
|
|
||||||
type='number'
|
|
||||||
fullWidth
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<TextField
|
|
||||||
onChange={inputForm}
|
|
||||||
margin='dense'
|
|
||||||
id='DownloadRateLimit'
|
|
||||||
label={t('DownloadRateLimit')}
|
|
||||||
value={DownloadRateLimit}
|
|
||||||
type='number'
|
|
||||||
fullWidth
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<FormControlLabel
|
|
||||||
control={<Switch checked={!DisableUpload} onChange={inputForm} id='DisableUpload' color='primary' />}
|
|
||||||
label={t('Upload')}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<TextField
|
|
||||||
onChange={inputForm}
|
|
||||||
margin='dense'
|
|
||||||
id='UploadRateLimit'
|
|
||||||
label={t('UploadRateLimit')}
|
|
||||||
value={UploadRateLimit}
|
|
||||||
type='number'
|
|
||||||
fullWidth
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<TextField
|
|
||||||
onChange={inputForm}
|
|
||||||
margin='dense'
|
|
||||||
id='PeersListenPort'
|
|
||||||
label={t('PeersListenPort')}
|
|
||||||
value={PeersListenPort}
|
|
||||||
type='number'
|
|
||||||
fullWidth
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<FormControlLabel
|
|
||||||
control={<Switch checked={!DisableUPNP} onChange={inputForm} id='DisableUPNP' color='primary' />}
|
|
||||||
label={t('UPNP')}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<InputLabel htmlFor='RetrackersMode'>{t('RetrackersMode')}</InputLabel>
|
|
||||||
<Select onChange={inputForm} type='number' native id='RetrackersMode' value={RetrackersMode}>
|
|
||||||
<option value={0}>{t('DontAddRetrackers')}</option>
|
|
||||||
<option value={1}>{t('AddRetrackers')}</option>
|
|
||||||
<option value={2}>{t('RemoveRetrackers')}</option>
|
|
||||||
<option value={3}>{t('ReplaceRetrackers')}</option>
|
|
||||||
</Select>
|
|
||||||
<br />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</DialogContent>
|
|
||||||
|
|
||||||
<DialogActions>
|
|
||||||
<Button onClick={handleClose} color='primary' variant='outlined'>
|
|
||||||
{t('Cancel')}
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Button onClick={handleSave} color='primary' variant='outlined'>
|
|
||||||
{t('Save')}
|
|
||||||
</Button>
|
|
||||||
</DialogActions>
|
|
||||||
</Dialog>
|
|
||||||
</ThemeProvider>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
168
web/src/components/Settings/PrimarySettingsComponent.jsx
Normal file
168
web/src/components/Settings/PrimarySettingsComponent.jsx
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { USBIcon, RAMIcon } from 'icons'
|
||||||
|
import { FormControlLabel, Switch } from '@material-ui/core'
|
||||||
|
import TextField from '@material-ui/core/TextField'
|
||||||
|
|
||||||
|
import {
|
||||||
|
Divider,
|
||||||
|
PreloadCacheValue,
|
||||||
|
MainSettingsContent,
|
||||||
|
StorageButton,
|
||||||
|
StorageIconWrapper,
|
||||||
|
CacheStorageSelector,
|
||||||
|
SettingSectionLabel,
|
||||||
|
PreloadCachePercentage,
|
||||||
|
cacheBeforeReaderColor,
|
||||||
|
cacheAfterReaderColor,
|
||||||
|
} from './style'
|
||||||
|
import SliderInput from './SliderInput'
|
||||||
|
|
||||||
|
const CacheStorageLocationLabel = ({ style }) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SettingSectionLabel style={style}>
|
||||||
|
{t('SettingsDialog.CacheStorageLocation')}
|
||||||
|
<small>{t('SettingsDialog.UseDiskDesc')}</small>
|
||||||
|
</SettingSectionLabel>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function PrimarySettingsComponent({
|
||||||
|
settings,
|
||||||
|
inputForm,
|
||||||
|
cachePercentage,
|
||||||
|
cacheSize,
|
||||||
|
isProMode,
|
||||||
|
setCacheSize,
|
||||||
|
setCachePercentage,
|
||||||
|
updateSettings,
|
||||||
|
}) {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const { PreloadBuffer, UseDisk, TorrentsSavePath, RemoveCacheOnDrop } = settings || {}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MainSettingsContent>
|
||||||
|
<div>
|
||||||
|
<SettingSectionLabel>{t('SettingsDialog.CacheSettings')}</SettingSectionLabel>
|
||||||
|
|
||||||
|
<PreloadCachePercentage
|
||||||
|
value={100 - cachePercentage}
|
||||||
|
label={`${t('Cache')} ${cacheSize} MB`}
|
||||||
|
isPreloadEnabled={PreloadBuffer}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<PreloadCacheValue color={cacheBeforeReaderColor}>
|
||||||
|
<div>
|
||||||
|
{100 - cachePercentage}% ({Math.round((cacheSize / 100) * (100 - cachePercentage))} MB)
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>{t('SettingsDialog.CacheBeforeReaderDesc')}</div>
|
||||||
|
</PreloadCacheValue>
|
||||||
|
|
||||||
|
<PreloadCacheValue color={cacheAfterReaderColor}>
|
||||||
|
<div>
|
||||||
|
{cachePercentage}% ({Math.round((cacheSize / 100) * cachePercentage)} MB)
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>{t('SettingsDialog.CacheAfterReaderDesc')}</div>
|
||||||
|
</PreloadCacheValue>
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
|
||||||
|
<SliderInput
|
||||||
|
isProMode={isProMode}
|
||||||
|
title={t('SettingsDialog.CacheSize')}
|
||||||
|
value={cacheSize}
|
||||||
|
setValue={setCacheSize}
|
||||||
|
sliderMin={32}
|
||||||
|
sliderMax={1024}
|
||||||
|
inputMin={32}
|
||||||
|
inputMax={20000}
|
||||||
|
step={8}
|
||||||
|
onBlurCallback={value => setCacheSize(Math.round(value / 8) * 8)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SliderInput
|
||||||
|
isProMode={isProMode}
|
||||||
|
title={t('SettingsDialog.ReaderReadAHead')}
|
||||||
|
value={cachePercentage}
|
||||||
|
setValue={setCachePercentage}
|
||||||
|
sliderMin={40}
|
||||||
|
sliderMax={95}
|
||||||
|
inputMin={0}
|
||||||
|
inputMax={100}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormControlLabel
|
||||||
|
control={<Switch checked={!!PreloadBuffer} onChange={inputForm} id='PreloadBuffer' color='secondary' />}
|
||||||
|
label={t('SettingsDialog.PreloadBuffer')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{UseDisk ? (
|
||||||
|
<div>
|
||||||
|
<CacheStorageLocationLabel />
|
||||||
|
|
||||||
|
<div style={{ display: 'grid', gridAutoFlow: 'column' }}>
|
||||||
|
<StorageButton small onClick={() => updateSettings({ UseDisk: false })}>
|
||||||
|
<StorageIconWrapper small>
|
||||||
|
<RAMIcon color='#323637' />
|
||||||
|
</StorageIconWrapper>
|
||||||
|
|
||||||
|
<div>{t('SettingsDialog.RAM')}</div>
|
||||||
|
</StorageButton>
|
||||||
|
|
||||||
|
<StorageButton small selected>
|
||||||
|
<StorageIconWrapper small selected>
|
||||||
|
<USBIcon color='#dee3e5' />
|
||||||
|
</StorageIconWrapper>
|
||||||
|
|
||||||
|
<div>{t('SettingsDialog.Disk')}</div>
|
||||||
|
</StorageButton>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
|
<Switch checked={RemoveCacheOnDrop} onChange={inputForm} id='RemoveCacheOnDrop' color='secondary' />
|
||||||
|
}
|
||||||
|
label={t('SettingsDialog.RemoveCacheOnDrop')}
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<small>{t('SettingsDialog.RemoveCacheOnDropDesc')}</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<TextField
|
||||||
|
onChange={inputForm}
|
||||||
|
margin='dense'
|
||||||
|
id='TorrentsSavePath'
|
||||||
|
label={t('SettingsDialog.TorrentsSavePath')}
|
||||||
|
value={TorrentsSavePath}
|
||||||
|
type='url'
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<CacheStorageSelector>
|
||||||
|
<CacheStorageLocationLabel style={{ placeSelf: 'start', gridArea: 'label' }} />
|
||||||
|
|
||||||
|
<StorageButton selected>
|
||||||
|
<StorageIconWrapper selected>
|
||||||
|
<RAMIcon color='#dee3e5' />
|
||||||
|
</StorageIconWrapper>
|
||||||
|
|
||||||
|
<div>{t('SettingsDialog.RAM')}</div>
|
||||||
|
</StorageButton>
|
||||||
|
|
||||||
|
<StorageButton onClick={() => updateSettings({ UseDisk: true })}>
|
||||||
|
<StorageIconWrapper>
|
||||||
|
<USBIcon color='#323637' />
|
||||||
|
</StorageIconWrapper>
|
||||||
|
|
||||||
|
<div>{t('SettingsDialog.Disk')}</div>
|
||||||
|
</StorageButton>
|
||||||
|
</CacheStorageSelector>
|
||||||
|
)}
|
||||||
|
</MainSettingsContent>
|
||||||
|
)
|
||||||
|
}
|
||||||
142
web/src/components/Settings/SecondarySettingsComponent.jsx
Normal file
142
web/src/components/Settings/SecondarySettingsComponent.jsx
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import TextField from '@material-ui/core/TextField'
|
||||||
|
import { FormControlLabel, InputLabel, Select, Switch } from '@material-ui/core'
|
||||||
|
|
||||||
|
import { SecondarySettingsContent, SettingSectionLabel } from './style'
|
||||||
|
|
||||||
|
export default function SecondarySettingsComponent({ settings, inputForm }) {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
const {
|
||||||
|
RetrackersMode,
|
||||||
|
TorrentDisconnectTimeout,
|
||||||
|
EnableIPv6,
|
||||||
|
ForceEncrypt,
|
||||||
|
DisableTCP,
|
||||||
|
DisableUTP,
|
||||||
|
DisableUPNP,
|
||||||
|
DisableDHT,
|
||||||
|
DisablePEX,
|
||||||
|
DisableUpload,
|
||||||
|
DownloadRateLimit,
|
||||||
|
UploadRateLimit,
|
||||||
|
ConnectionsLimit,
|
||||||
|
DhtConnectionLimit,
|
||||||
|
PeersListenPort,
|
||||||
|
} = settings || {}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SecondarySettingsContent>
|
||||||
|
<SettingSectionLabel>{t('SettingsDialog.AdditionalSettings')}</SettingSectionLabel>
|
||||||
|
|
||||||
|
<FormControlLabel
|
||||||
|
control={<Switch checked={EnableIPv6} onChange={inputForm} id='EnableIPv6' color='secondary' />}
|
||||||
|
label='IPv6'
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
<FormControlLabel
|
||||||
|
control={<Switch checked={!DisableTCP} onChange={inputForm} id='DisableTCP' color='secondary' />}
|
||||||
|
label='TCP (Transmission Control Protocol)'
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
<FormControlLabel
|
||||||
|
control={<Switch checked={!DisableUTP} onChange={inputForm} id='DisableUTP' color='secondary' />}
|
||||||
|
label='μTP (Micro Transport Protocol)'
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
<FormControlLabel
|
||||||
|
control={<Switch checked={!DisablePEX} onChange={inputForm} id='DisablePEX' color='secondary' />}
|
||||||
|
label='PEX (Peer Exchange)'
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
<FormControlLabel
|
||||||
|
control={<Switch checked={ForceEncrypt} onChange={inputForm} id='ForceEncrypt' color='secondary' />}
|
||||||
|
label={t('SettingsDialog.ForceEncrypt')}
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
<TextField
|
||||||
|
onChange={inputForm}
|
||||||
|
margin='dense'
|
||||||
|
id='TorrentDisconnectTimeout'
|
||||||
|
label={t('SettingsDialog.TorrentDisconnectTimeout')}
|
||||||
|
value={TorrentDisconnectTimeout}
|
||||||
|
type='number'
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
<TextField
|
||||||
|
onChange={inputForm}
|
||||||
|
margin='dense'
|
||||||
|
id='ConnectionsLimit'
|
||||||
|
label={t('SettingsDialog.ConnectionsLimit')}
|
||||||
|
value={ConnectionsLimit}
|
||||||
|
type='number'
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
<FormControlLabel
|
||||||
|
control={<Switch checked={!DisableDHT} onChange={inputForm} id='DisableDHT' color='secondary' />}
|
||||||
|
label={t('SettingsDialog.DHT')}
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
<TextField
|
||||||
|
onChange={inputForm}
|
||||||
|
margin='dense'
|
||||||
|
id='DhtConnectionLimit'
|
||||||
|
label={t('SettingsDialog.DhtConnectionLimit')}
|
||||||
|
value={DhtConnectionLimit}
|
||||||
|
type='number'
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
<TextField
|
||||||
|
onChange={inputForm}
|
||||||
|
margin='dense'
|
||||||
|
id='DownloadRateLimit'
|
||||||
|
label={t('SettingsDialog.DownloadRateLimit')}
|
||||||
|
value={DownloadRateLimit}
|
||||||
|
type='number'
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
<FormControlLabel
|
||||||
|
control={<Switch checked={!DisableUpload} onChange={inputForm} id='DisableUpload' color='secondary' />}
|
||||||
|
label={t('SettingsDialog.Upload')}
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
<TextField
|
||||||
|
onChange={inputForm}
|
||||||
|
margin='dense'
|
||||||
|
id='UploadRateLimit'
|
||||||
|
label={t('SettingsDialog.UploadRateLimit')}
|
||||||
|
value={UploadRateLimit}
|
||||||
|
type='number'
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
<TextField
|
||||||
|
onChange={inputForm}
|
||||||
|
margin='dense'
|
||||||
|
id='PeersListenPort'
|
||||||
|
label={t('SettingsDialog.PeersListenPort')}
|
||||||
|
value={PeersListenPort}
|
||||||
|
type='number'
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
<FormControlLabel
|
||||||
|
control={<Switch checked={!DisableUPNP} onChange={inputForm} id='DisableUPNP' color='secondary' />}
|
||||||
|
label='UPnP (Universal Plug and Play)'
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
<InputLabel htmlFor='RetrackersMode'>{t('SettingsDialog.RetrackersMode')}</InputLabel>
|
||||||
|
<Select onChange={inputForm} type='number' native id='RetrackersMode' value={RetrackersMode}>
|
||||||
|
<option value={0}>{t('SettingsDialog.DontAddRetrackers')}</option>
|
||||||
|
<option value={1}>{t('SettingsDialog.AddRetrackers')}</option>
|
||||||
|
<option value={2}>{t('SettingsDialog.RemoveRetrackers')}</option>
|
||||||
|
<option value={3}>{t('SettingsDialog.ReplaceRetrackers')}</option>
|
||||||
|
</Select>
|
||||||
|
<br />
|
||||||
|
</SecondarySettingsContent>
|
||||||
|
)
|
||||||
|
}
|
||||||
178
web/src/components/Settings/SettingsDialog.jsx
Normal file
178
web/src/components/Settings/SettingsDialog.jsx
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
import axios from 'axios'
|
||||||
|
import Dialog from '@material-ui/core/Dialog'
|
||||||
|
import Button from '@material-ui/core/Button'
|
||||||
|
import Checkbox from '@material-ui/core/Checkbox'
|
||||||
|
import { FormControlLabel, useMediaQuery, useTheme } from '@material-ui/core'
|
||||||
|
import { settingsHost } from 'utils/Hosts'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import AppBar from '@material-ui/core/AppBar'
|
||||||
|
import Tabs from '@material-ui/core/Tabs'
|
||||||
|
import Tab from '@material-ui/core/Tab'
|
||||||
|
import SwipeableViews from 'react-swipeable-views'
|
||||||
|
import CircularProgress from '@material-ui/core/CircularProgress'
|
||||||
|
|
||||||
|
import { SettingsHeader, FooterSection, Content } from './style'
|
||||||
|
import defaultSettings from './defaultSettings'
|
||||||
|
import { a11yProps, TabPanel } from './tabComponents'
|
||||||
|
import PrimarySettingsComponent from './PrimarySettingsComponent'
|
||||||
|
import SecondarySettingsComponent from './SecondarySettingsComponent'
|
||||||
|
|
||||||
|
export default function SettingsDialog({ handleClose }) {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const fullScreen = useMediaQuery('@media (max-width:930px)')
|
||||||
|
const { direction } = useTheme()
|
||||||
|
|
||||||
|
const [settings, setSettings] = useState()
|
||||||
|
const [selectedTab, setSelectedTab] = useState(0)
|
||||||
|
const [cacheSize, setCacheSize] = useState(32)
|
||||||
|
const [cachePercentage, setCachePercentage] = useState(40)
|
||||||
|
const [isProMode, setIsProMode] = useState(JSON.parse(localStorage.getItem('isProMode')) || false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
axios.post(settingsHost(), { action: 'get' }).then(({ data }) => {
|
||||||
|
setSettings({ ...data, CacheSize: data.CacheSize / (1024 * 1024) })
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const handleSave = () => {
|
||||||
|
handleClose()
|
||||||
|
const sets = JSON.parse(JSON.stringify(settings))
|
||||||
|
sets.CacheSize = cacheSize * 1024 * 1024
|
||||||
|
sets.ReaderReadAHead = cachePercentage
|
||||||
|
axios.post(settingsHost(), { action: 'set', sets })
|
||||||
|
}
|
||||||
|
|
||||||
|
const inputForm = ({ target: { type, value, checked, id } }) => {
|
||||||
|
const sets = JSON.parse(JSON.stringify(settings))
|
||||||
|
|
||||||
|
if (type === 'number' || type === 'select-one') {
|
||||||
|
sets[id] = Number(value)
|
||||||
|
} else if (type === 'checkbox') {
|
||||||
|
if (
|
||||||
|
id === 'DisableTCP' ||
|
||||||
|
id === 'DisableUTP' ||
|
||||||
|
id === 'DisableUPNP' ||
|
||||||
|
id === 'DisableDHT' ||
|
||||||
|
id === 'DisablePEX' ||
|
||||||
|
id === 'DisableUpload'
|
||||||
|
)
|
||||||
|
sets[id] = Boolean(!checked)
|
||||||
|
else sets[id] = Boolean(checked)
|
||||||
|
} else if (type === 'url') {
|
||||||
|
sets[id] = value
|
||||||
|
}
|
||||||
|
setSettings(sets)
|
||||||
|
}
|
||||||
|
|
||||||
|
const { CacheSize, ReaderReadAHead } = settings || {}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!CacheSize || !ReaderReadAHead) return
|
||||||
|
|
||||||
|
setCacheSize(CacheSize)
|
||||||
|
setCachePercentage(ReaderReadAHead)
|
||||||
|
}, [CacheSize, ReaderReadAHead])
|
||||||
|
|
||||||
|
const updateSettings = newProps => setSettings({ ...settings, ...newProps })
|
||||||
|
const handleChange = (_, newValue) => setSelectedTab(newValue)
|
||||||
|
const handleChangeIndex = index => setSelectedTab(index)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open onClose={handleClose} fullScreen={fullScreen} fullWidth maxWidth='md'>
|
||||||
|
<SettingsHeader>
|
||||||
|
<div>{t('SettingsDialog.Settings')}</div>
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
checked={isProMode}
|
||||||
|
onChange={({ target: { checked } }) => {
|
||||||
|
setIsProMode(checked)
|
||||||
|
localStorage.setItem('isProMode', checked)
|
||||||
|
if (!checked) setSelectedTab(0)
|
||||||
|
}}
|
||||||
|
style={{ color: 'white' }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label={t('SettingsDialog.ProMode')}
|
||||||
|
/>
|
||||||
|
</SettingsHeader>
|
||||||
|
|
||||||
|
<AppBar position='static' color='default'>
|
||||||
|
<Tabs
|
||||||
|
value={selectedTab}
|
||||||
|
onChange={handleChange}
|
||||||
|
indicatorColor='secondary'
|
||||||
|
textColor='secondary'
|
||||||
|
variant='fullWidth'
|
||||||
|
>
|
||||||
|
<Tab label={t('SettingsDialog.Tabs.Main')} {...a11yProps(0)} />
|
||||||
|
|
||||||
|
<Tab
|
||||||
|
disabled={!isProMode}
|
||||||
|
label={
|
||||||
|
<>
|
||||||
|
<div>{t('SettingsDialog.Tabs.Additional')}</div>
|
||||||
|
{!isProMode && <div style={{ fontSize: '9px' }}>{t('SettingsDialog.Tabs.AdditionalDisabled')}</div>}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
{...a11yProps(1)}
|
||||||
|
/>
|
||||||
|
</Tabs>
|
||||||
|
</AppBar>
|
||||||
|
|
||||||
|
<Content isLoading={!settings}>
|
||||||
|
{settings ? (
|
||||||
|
<>
|
||||||
|
<SwipeableViews
|
||||||
|
axis={direction === 'rtl' ? 'x-reverse' : 'x'}
|
||||||
|
index={selectedTab}
|
||||||
|
onChangeIndex={handleChangeIndex}
|
||||||
|
>
|
||||||
|
<TabPanel value={selectedTab} index={0} dir={direction}>
|
||||||
|
<PrimarySettingsComponent
|
||||||
|
settings={settings}
|
||||||
|
inputForm={inputForm}
|
||||||
|
cachePercentage={cachePercentage}
|
||||||
|
cacheSize={cacheSize}
|
||||||
|
isProMode={isProMode}
|
||||||
|
setCacheSize={setCacheSize}
|
||||||
|
setCachePercentage={setCachePercentage}
|
||||||
|
updateSettings={updateSettings}
|
||||||
|
/>
|
||||||
|
</TabPanel>
|
||||||
|
|
||||||
|
<TabPanel value={selectedTab} index={1} dir={direction}>
|
||||||
|
<SecondarySettingsComponent settings={settings} inputForm={inputForm} />
|
||||||
|
</TabPanel>
|
||||||
|
</SwipeableViews>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<CircularProgress color='secondary' />
|
||||||
|
)}
|
||||||
|
</Content>
|
||||||
|
|
||||||
|
<FooterSection>
|
||||||
|
<Button onClick={handleClose} color='secondary' variant='outlined'>
|
||||||
|
{t('Cancel')}
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
setCacheSize(defaultSettings.CacheSize)
|
||||||
|
setCachePercentage(defaultSettings.ReaderReadAHead)
|
||||||
|
updateSettings(defaultSettings)
|
||||||
|
}}
|
||||||
|
color='secondary'
|
||||||
|
variant='outlined'
|
||||||
|
>
|
||||||
|
{t('SettingsDialog.ResetToDefault')}
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button variant='contained' onClick={handleSave} color='secondary'>
|
||||||
|
{t('Save')}
|
||||||
|
</Button>
|
||||||
|
</FooterSection>
|
||||||
|
</Dialog>
|
||||||
|
)
|
||||||
|
}
|
||||||
56
web/src/components/Settings/SliderInput.jsx
Normal file
56
web/src/components/Settings/SliderInput.jsx
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import { Grid, Input, Slider } from '@material-ui/core'
|
||||||
|
|
||||||
|
export default function SliderInput({
|
||||||
|
isProMode,
|
||||||
|
title,
|
||||||
|
value,
|
||||||
|
setValue,
|
||||||
|
sliderMin,
|
||||||
|
sliderMax,
|
||||||
|
inputMin,
|
||||||
|
inputMax,
|
||||||
|
step = 1,
|
||||||
|
onBlurCallback,
|
||||||
|
}) {
|
||||||
|
const onBlur = ({ target: { value } }) => {
|
||||||
|
if (value < inputMin) return setValue(inputMin)
|
||||||
|
if (value > inputMax) return setValue(inputMax)
|
||||||
|
|
||||||
|
onBlurCallback && onBlurCallback(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onInputChange = ({ target: { value } }) => setValue(value === '' ? '' : Number(value))
|
||||||
|
const onSliderChange = (_, newValue) => setValue(newValue)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div>{title}</div>
|
||||||
|
|
||||||
|
<Grid container spacing={2} alignItems='center'>
|
||||||
|
<Grid item xs>
|
||||||
|
<Slider
|
||||||
|
min={sliderMin}
|
||||||
|
max={sliderMax}
|
||||||
|
value={value}
|
||||||
|
onChange={onSliderChange}
|
||||||
|
step={step}
|
||||||
|
color='secondary'
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{isProMode && (
|
||||||
|
<Grid item>
|
||||||
|
<Input
|
||||||
|
value={value}
|
||||||
|
margin='dense'
|
||||||
|
onChange={onInputChange}
|
||||||
|
onBlur={onBlur}
|
||||||
|
style={{ width: '65px' }}
|
||||||
|
inputProps={{ step, min: inputMin, max: inputMax, type: 'number' }}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
)}
|
||||||
|
</Grid>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
25
web/src/components/Settings/defaultSettings.js
Normal file
25
web/src/components/Settings/defaultSettings.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
export default {
|
||||||
|
CacheSize: 96,
|
||||||
|
ReaderReadAHead: 95,
|
||||||
|
UseDisk: false,
|
||||||
|
UploadRateLimit: 0,
|
||||||
|
TorrentsSavePath: '',
|
||||||
|
ConnectionsLimit: 23,
|
||||||
|
DhtConnectionLimit: 500,
|
||||||
|
DisableDHT: false,
|
||||||
|
DisablePEX: false,
|
||||||
|
DisableTCP: false,
|
||||||
|
DisableUPNP: false,
|
||||||
|
DisableUTP: true,
|
||||||
|
DisableUpload: false,
|
||||||
|
DownloadRateLimit: 0,
|
||||||
|
EnableDebug: false,
|
||||||
|
EnableIPv6: false,
|
||||||
|
ForceEncrypt: false,
|
||||||
|
PeersListenPort: 0,
|
||||||
|
PreloadBuffer: false,
|
||||||
|
RemoveCacheOnDrop: false,
|
||||||
|
RetrackersMode: 1,
|
||||||
|
Strategy: 0,
|
||||||
|
TorrentDisconnectTimeout: 30,
|
||||||
|
}
|
||||||
29
web/src/components/Settings/index.jsx
Normal file
29
web/src/components/Settings/index.jsx
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import ListItem from '@material-ui/core/ListItem'
|
||||||
|
import ListItemIcon from '@material-ui/core/ListItemIcon'
|
||||||
|
import ListItemText from '@material-ui/core/ListItemText'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import SettingsIcon from '@material-ui/icons/Settings'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
|
import SettingsDialog from './SettingsDialog'
|
||||||
|
|
||||||
|
export default function SettingsDialogButton({ isOffline, isLoading }) {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const [isDialogOpen, setIsDialogOpen] = useState(false)
|
||||||
|
|
||||||
|
const handleClickOpen = () => setIsDialogOpen(true)
|
||||||
|
const handleClose = () => setIsDialogOpen(false)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<ListItem disabled={isOffline || isLoading} button onClick={handleClickOpen}>
|
||||||
|
<ListItemIcon>
|
||||||
|
<SettingsIcon />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText primary={t('Settings')} />
|
||||||
|
</ListItem>
|
||||||
|
|
||||||
|
{isDialogOpen && <SettingsDialog handleClose={handleClose} />}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
206
web/src/components/Settings/style.js
Normal file
206
web/src/components/Settings/style.js
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
import styled, { css } from 'styled-components'
|
||||||
|
import { mainColors } from 'style/colors'
|
||||||
|
import { Header } from 'style/DialogStyles'
|
||||||
|
|
||||||
|
export const cacheBeforeReaderColor = '#b3dfc9'
|
||||||
|
export const cacheAfterReaderColor = mainColors.light.primary
|
||||||
|
|
||||||
|
export const SettingsHeader = styled(Header)`
|
||||||
|
display: grid;
|
||||||
|
grid-auto-flow: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
@media (max-width: 340px) {
|
||||||
|
grid-auto-flow: row;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export const FooterSection = styled.div`
|
||||||
|
${({
|
||||||
|
theme: {
|
||||||
|
settingsDialog: { footerBG },
|
||||||
|
},
|
||||||
|
}) => css`
|
||||||
|
padding: 20px;
|
||||||
|
display: grid;
|
||||||
|
grid-auto-flow: column;
|
||||||
|
justify-content: end;
|
||||||
|
gap: 10px;
|
||||||
|
align-items: center;
|
||||||
|
background: ${footerBG};
|
||||||
|
|
||||||
|
@media (max-width: 500px) {
|
||||||
|
grid-auto-flow: row;
|
||||||
|
justify-content: stretch;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
`
|
||||||
|
export const Divider = styled.div`
|
||||||
|
height: 1px;
|
||||||
|
background-color: rgba(0, 0, 0, 0.12);
|
||||||
|
margin: 30px 0;
|
||||||
|
`
|
||||||
|
|
||||||
|
export const Content = styled.div`
|
||||||
|
${({
|
||||||
|
isLoading,
|
||||||
|
theme: {
|
||||||
|
settingsDialog: { contentBG },
|
||||||
|
},
|
||||||
|
}) => css`
|
||||||
|
background: ${contentBG};
|
||||||
|
overflow: auto;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
${isLoading &&
|
||||||
|
css`
|
||||||
|
min-height: 500px;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
`}
|
||||||
|
`}
|
||||||
|
`
|
||||||
|
|
||||||
|
export const PreloadCacheValue = styled.div`
|
||||||
|
${({ color }) => css`
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: max-content 100px 1fr;
|
||||||
|
gap: 10px;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
:not(:last-child) {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:before {
|
||||||
|
content: '';
|
||||||
|
background: ${color};
|
||||||
|
width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
`
|
||||||
|
|
||||||
|
export const MainSettingsContent = styled.div`
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 40px;
|
||||||
|
padding: 20px;
|
||||||
|
|
||||||
|
@media (max-width: 930px) {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
export const SecondarySettingsContent = styled.div`
|
||||||
|
padding: 20px;
|
||||||
|
`
|
||||||
|
|
||||||
|
export const StorageButton = styled.div`
|
||||||
|
${({ small, selected }) => css`
|
||||||
|
transition: 0.2s;
|
||||||
|
cursor: default;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
${!selected &&
|
||||||
|
css`
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
:hover {
|
||||||
|
filter: brightness(0.8);
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
|
||||||
|
${small
|
||||||
|
? css`
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: max-content 1fr;
|
||||||
|
gap: 20px;
|
||||||
|
align-items: center;
|
||||||
|
justify-items: start;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
`
|
||||||
|
: css`
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
`}
|
||||||
|
`}
|
||||||
|
`
|
||||||
|
|
||||||
|
export const StorageIconWrapper = styled.div`
|
||||||
|
${({ selected, small }) => css`
|
||||||
|
width: ${small ? '60px' : '150px'};
|
||||||
|
height: ${small ? '60px' : '150px'};
|
||||||
|
border-radius: 50%;
|
||||||
|
background: ${selected ? '#323637' : '#dee3e5'};
|
||||||
|
|
||||||
|
svg {
|
||||||
|
transform: rotate(-45deg) scale(0.75);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 930px) {
|
||||||
|
width: ${small ? '50px' : '90px'};
|
||||||
|
height: ${small ? '50px' : '90px'};
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
`
|
||||||
|
|
||||||
|
export const CacheStorageSelector = styled.div`
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: max-content 1fr;
|
||||||
|
grid-template-areas: 'label label';
|
||||||
|
place-items: center;
|
||||||
|
|
||||||
|
@media (max-width: 930px) {
|
||||||
|
justify-content: start;
|
||||||
|
column-gap: 30px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export const SettingSectionLabel = styled.div`
|
||||||
|
font-size: 25px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
|
||||||
|
small {
|
||||||
|
display: block;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export const PreloadCachePercentage = styled.div.attrs(({ value }) => ({
|
||||||
|
// this block is here according to styled-components recomendation about fast changable components
|
||||||
|
style: {
|
||||||
|
background: `linear-gradient(to right, ${cacheBeforeReaderColor} 0%, ${cacheBeforeReaderColor} ${value}%, ${cacheAfterReaderColor} ${value}%, ${cacheAfterReaderColor} 100%)`,
|
||||||
|
},
|
||||||
|
}))`
|
||||||
|
${({ label, isPreloadEnabled }) => css`
|
||||||
|
border: 1px solid #323637;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-radius: 5px;
|
||||||
|
color: #000;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
:before {
|
||||||
|
content: '${label}';
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
${isPreloadEnabled &&
|
||||||
|
css`
|
||||||
|
:after {
|
||||||
|
content: '';
|
||||||
|
width: 100%;
|
||||||
|
height: 2px;
|
||||||
|
background: #323637;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
`}
|
||||||
|
`
|
||||||
10
web/src/components/Settings/tabComponents.jsx
Normal file
10
web/src/components/Settings/tabComponents.jsx
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
export const a11yProps = index => ({
|
||||||
|
id: `full-width-tab-${index}`,
|
||||||
|
'aria-controls': `full-width-tabpanel-${index}`,
|
||||||
|
})
|
||||||
|
|
||||||
|
export const TabPanel = ({ children, value, index, ...other }) => (
|
||||||
|
<div role='tabpanel' hidden={value !== index} id={`full-width-tabpanel-${index}`} {...other}>
|
||||||
|
{value === index && <>{children}</>}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
File diff suppressed because one or more lines are too long
@@ -20,17 +20,14 @@
|
|||||||
},
|
},
|
||||||
"AddFromLink": "Add from Link",
|
"AddFromLink": "Add from Link",
|
||||||
"AddNewTorrent": "Add new torrent",
|
"AddNewTorrent": "Add new torrent",
|
||||||
"AddRetrackers": "Add retrackers",
|
|
||||||
"Buffer": "Preload Buffer / Cache",
|
"Buffer": "Preload Buffer / Cache",
|
||||||
"BufferNote": "Enable “Preload Buffer” in settings to see cache loading progress",
|
"BufferNote": "Enable “Preload Buffer” in settings to see cache loading progress",
|
||||||
"Cache": "Cache",
|
"Cache": "Cache",
|
||||||
"CacheSize": "Cache Size (Megabytes)",
|
|
||||||
"Cancel": "Cancel",
|
"Cancel": "Cancel",
|
||||||
"Clear": "Clear",
|
"Clear": "Clear",
|
||||||
"Close": "Close",
|
"Close": "Close",
|
||||||
"CloseServer?": "Do you want to turn off server?",
|
"CloseServer?": "Do you want to turn off server?",
|
||||||
"CloseServer": "Turn Off",
|
"CloseServer": "Turn Off",
|
||||||
"ConnectionsLimit": "Connections Limit",
|
|
||||||
"CopyHash": "Copy Hash",
|
"CopyHash": "Copy Hash",
|
||||||
"CopyLink": "Copy link",
|
"CopyLink": "Copy link",
|
||||||
"Data": "Data",
|
"Data": "Data",
|
||||||
@@ -42,21 +39,15 @@
|
|||||||
"header": "$t(DetailedCacheView.button)"
|
"header": "$t(DetailedCacheView.button)"
|
||||||
},
|
},
|
||||||
"Details": "Details",
|
"Details": "Details",
|
||||||
"DHT": "DHT (Distributed Hash Table)",
|
|
||||||
"DhtConnectionLimit": "DHT Connection Limit",
|
|
||||||
"Donate?": "Want to donate?",
|
"Donate?": "Want to donate?",
|
||||||
"Donate": "Donate",
|
"Donate": "Donate",
|
||||||
"DontAddRetrackers": "Don`t add retrackers",
|
|
||||||
"DownloadPlaylist": "Download Playlist",
|
"DownloadPlaylist": "Download Playlist",
|
||||||
"DownloadRateLimit": "Download Rate Limit (Kilobytes)",
|
|
||||||
"DownloadSpeed": "Download speed",
|
"DownloadSpeed": "Download speed",
|
||||||
"Drop": "Drop",
|
"Drop": "Drop",
|
||||||
"DropTorrent": "Reset Torrent",
|
"DropTorrent": "Reset Torrent",
|
||||||
"Edit": "Edit",
|
"Edit": "Edit",
|
||||||
"EditTorrent": "Edit torrent",
|
"EditTorrent": "Edit torrent",
|
||||||
"EnableIPv6": "IPv6",
|
|
||||||
"Episode": "Episode",
|
"Episode": "Episode",
|
||||||
"ForceEncrypt": "Force Encrypt Headers",
|
|
||||||
"FromLatestFile": "From Latest File",
|
"FromLatestFile": "From Latest File",
|
||||||
"Full": "Full",
|
"Full": "Full",
|
||||||
"Host": "Host",
|
"Host": "Host",
|
||||||
@@ -69,55 +60,74 @@
|
|||||||
"OK": "OK",
|
"OK": "OK",
|
||||||
"OpenLink": "Open link",
|
"OpenLink": "Open link",
|
||||||
"Peers": "Peers",
|
"Peers": "Peers",
|
||||||
"PeersListenPort": "Peers Listen Port",
|
|
||||||
"PEX": "PEX (Peer Exchange)",
|
|
||||||
"PiecesCount": "Pieces count",
|
"PiecesCount": "Pieces count",
|
||||||
"PiecesLength": "Pieces length",
|
"PiecesLength": "Pieces length",
|
||||||
"Preload": "Preload",
|
"Preload": "Preload",
|
||||||
"PreloadBuffer": "Preload Buffer",
|
|
||||||
"ProjectSource": "Project page",
|
"ProjectSource": "Project page",
|
||||||
"ReaderReadAHead": "Reader Read Ahead (5-100%)",
|
|
||||||
"Releases": "Releases",
|
"Releases": "Releases",
|
||||||
"RemoveAll": "Remove All",
|
"RemoveAll": "Remove All",
|
||||||
"RemoveCacheOnDrop": "Remove Cache from Disk on Drop Torrent",
|
|
||||||
"RemoveCacheOnDropDesc": "If disabled, remove cache on delete torrent.",
|
|
||||||
"RemoveRetrackers": "Remove retrackers",
|
|
||||||
"RemoveViews": "Remove View States",
|
"RemoveViews": "Remove View States",
|
||||||
"ReplaceRetrackers": "Replace retrackers",
|
|
||||||
"Resolution": "Resolution",
|
"Resolution": "Resolution",
|
||||||
"RetrackersMode": "Retrackers Mode",
|
|
||||||
"Save": "Save",
|
"Save": "Save",
|
||||||
"ScrollDown": "scroll down",
|
"ScrollDown": "scroll down",
|
||||||
"Season": "Season",
|
"Season": "Season",
|
||||||
"SelectSeason": "Select Season",
|
"SelectSeason": "Select Season",
|
||||||
"Settings": "Settings",
|
"SettingsDialog": {
|
||||||
|
"AddRetrackers": "Add retrackers",
|
||||||
|
"AdditionalSettings": "Additional Settings",
|
||||||
|
"CacheBeforeReaderDesc": "From cache will be saved before currently played frame",
|
||||||
|
"CacheAfterReaderDesc": "From cache will be loaded after currently played frame",
|
||||||
|
"CacheSize": "Cache Size",
|
||||||
|
"CacheSettings": "Cache Settings",
|
||||||
|
"CacheStorageLocation": "Cache Storage Location",
|
||||||
|
"ConnectionsLimit": "Connections Limit",
|
||||||
|
"DHT": "DHT (Distributed Hash Table)",
|
||||||
|
"DhtConnectionLimit": "DHT Connection Limit",
|
||||||
|
"Disk": "Disk",
|
||||||
|
"DontAddRetrackers": "Don`t add retrackers",
|
||||||
|
"DownloadRateLimit": "Download Rate Limit (Kilobytes)",
|
||||||
|
"ForceEncrypt": "Force Encrypt Headers",
|
||||||
|
"PeersListenPort": "Peers Listen Port",
|
||||||
|
"PreloadBuffer": "Preload Buffer",
|
||||||
|
"ProMode": "PRO mode",
|
||||||
|
"RAM": "RAM",
|
||||||
|
"ReaderReadAHead": "Reader Read Ahead (5-100%)",
|
||||||
|
"RemoveCacheOnDrop": "Remove Cache from Disk on Drop Torrent",
|
||||||
|
"RemoveCacheOnDropDesc": "If disabled, remove cache on delete torrent.",
|
||||||
|
"RemoveRetrackers": "Remove retrackers",
|
||||||
|
"ReplaceRetrackers": "Replace retrackers",
|
||||||
|
"RetrackersMode": "Retrackers Mode",
|
||||||
|
"ResetToDefault": "Reset to default",
|
||||||
|
"Settings": "Settings",
|
||||||
|
"TorrentDisconnectTimeout": "Torrent Disconnect Timeout",
|
||||||
|
"TorrentsSavePath": "Torrents Save Path",
|
||||||
|
"Upload": "Upload (not recommended to disable)",
|
||||||
|
"UploadRateLimit": "Upload Rate Limit (Kilobytes)",
|
||||||
|
"UseDiskDesc": "Better use external media on flash-based devices",
|
||||||
|
"Tabs": {
|
||||||
|
"Main": "Main",
|
||||||
|
"Additional": "Additional",
|
||||||
|
"AdditionalDisabled": "(enable PRO mode)"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Size": "Size",
|
"Size": "Size",
|
||||||
"SpecialThanks": "Special Thanks",
|
"SpecialThanks": "Special Thanks",
|
||||||
"Speed": "Speed",
|
"Speed": "Speed",
|
||||||
"Support": "Support",
|
"Support": "Support",
|
||||||
"TCP": "TCP (Transmission Control Protocol)",
|
|
||||||
"ThanksToEveryone": "Thanks to everyone who tested and helped.",
|
"ThanksToEveryone": "Thanks to everyone who tested and helped.",
|
||||||
"TorrentAdded": "Added",
|
"TorrentAdded": "Added",
|
||||||
"TorrentClosed": "Сlosed",
|
"TorrentClosed": "Сlosed",
|
||||||
"TorrentContent": "Torrent Content",
|
"TorrentContent": "Torrent Content",
|
||||||
"TorrentDetails": "Torrent Details",
|
"TorrentDetails": "Torrent Details",
|
||||||
"TorrentDisconnectTimeout": "Torrent Disconnect Timeout",
|
|
||||||
"TorrentGettingInfo": "Getting Info",
|
"TorrentGettingInfo": "Getting Info",
|
||||||
"TorrentInDb": "In DB",
|
"TorrentInDb": "In DB",
|
||||||
"TorrentPreload": "Preload",
|
"TorrentPreload": "Preload",
|
||||||
"TorrentSize": "Torrent size",
|
"TorrentSize": "Torrent size",
|
||||||
"TorrentsSavePath": "Torrents Save Path",
|
|
||||||
"TorrentState": "Torrent State",
|
"TorrentState": "Torrent State",
|
||||||
"TorrentStatus": "Torrent Status",
|
"TorrentStatus": "Torrent Status",
|
||||||
"TorrentWorking": "Active",
|
"TorrentWorking": "Active",
|
||||||
"TurnOff": "Turn Off",
|
"TurnOff": "Turn Off",
|
||||||
"Upload": "Upload (not recommended to disable)",
|
|
||||||
"UploadFile": "Upload File",
|
"UploadFile": "Upload File",
|
||||||
"UploadRateLimit": "Upload Rate Limit (Kilobytes)",
|
|
||||||
"UploadSpeed": "Upload speed",
|
"UploadSpeed": "Upload speed",
|
||||||
"UPNP": "UPnP (Universal Plug and Play)",
|
|
||||||
"UseDisk": "Use Disk for Cache",
|
|
||||||
"UseDiskDesc": "Better use external media on flash-based devices",
|
|
||||||
"UTP": "μTP (Micro Transport Protocol)",
|
|
||||||
"Viewed": "Viewed"
|
"Viewed": "Viewed"
|
||||||
}
|
}
|
||||||
@@ -20,17 +20,14 @@
|
|||||||
},
|
},
|
||||||
"AddFromLink": "Добавить",
|
"AddFromLink": "Добавить",
|
||||||
"AddNewTorrent": "Добавить новый торрент",
|
"AddNewTorrent": "Добавить новый торрент",
|
||||||
"AddRetrackers": "Добавлять",
|
|
||||||
"Buffer": "Предзагрузка / Кеш",
|
"Buffer": "Предзагрузка / Кеш",
|
||||||
"BufferNote": "Включите «Наполнять кеш перед началом воспроизведения» в настройках для показа заполнения кеша",
|
"BufferNote": "Включите «Наполнять кеш перед началом воспроизведения» в настройках для показа заполнения кеша",
|
||||||
"Cache": "Кеш",
|
"Cache": "Кеш",
|
||||||
"CacheSize": "Размер кеша (Мегабайты)",
|
|
||||||
"Cancel": "Отмена",
|
"Cancel": "Отмена",
|
||||||
"Clear": "Очистить",
|
"Clear": "Очистить",
|
||||||
"Close": "Закрыть",
|
"Close": "Закрыть",
|
||||||
"CloseServer?": "Хотите выключить сервер?",
|
"CloseServer?": "Хотите выключить сервер?",
|
||||||
"CloseServer": "Выкл. сервер",
|
"CloseServer": "Выкл. сервер",
|
||||||
"ConnectionsLimit": "Торрент-соединения (рек. 20-25)",
|
|
||||||
"CopyHash": "Скопировать хеш",
|
"CopyHash": "Скопировать хеш",
|
||||||
"CopyLink": "Копировать",
|
"CopyLink": "Копировать",
|
||||||
"Data": "Данные",
|
"Data": "Данные",
|
||||||
@@ -42,21 +39,15 @@
|
|||||||
"header": "Заполнение кеша"
|
"header": "Заполнение кеша"
|
||||||
},
|
},
|
||||||
"Details": "Инфо",
|
"Details": "Инфо",
|
||||||
"DHT": "DHT (Distributed Hash Table)",
|
|
||||||
"DhtConnectionLimit": "Лимит подключений DHT",
|
|
||||||
"Donate?": "Хотите поддержать проект?",
|
"Donate?": "Хотите поддержать проект?",
|
||||||
"Donate": "Поддержка",
|
"Donate": "Поддержка",
|
||||||
"DontAddRetrackers": "Ничего не делать",
|
|
||||||
"DownloadPlaylist": "Скачать плейлист",
|
"DownloadPlaylist": "Скачать плейлист",
|
||||||
"DownloadRateLimit": "Ограничение скорости загрузки (Килобайты)",
|
|
||||||
"DownloadSpeed": "Скорость загрузки",
|
"DownloadSpeed": "Скорость загрузки",
|
||||||
"Drop": "Сброс",
|
"Drop": "Сброс",
|
||||||
"DropTorrent": "Сбросить торрент",
|
"DropTorrent": "Сбросить торрент",
|
||||||
"Edit": "Изменить",
|
"Edit": "Изменить",
|
||||||
"EditTorrent": "Изменить торрент",
|
"EditTorrent": "Изменить торрент",
|
||||||
"EnableIPv6": "IPv6",
|
|
||||||
"Episode": "Серия",
|
"Episode": "Серия",
|
||||||
"ForceEncrypt": "Принудительное шифрование заголовков",
|
|
||||||
"FromLatestFile": "C последнего файла",
|
"FromLatestFile": "C последнего файла",
|
||||||
"Full": "Полный",
|
"Full": "Полный",
|
||||||
"Host": "Хост",
|
"Host": "Хост",
|
||||||
@@ -69,55 +60,74 @@
|
|||||||
"OK": "OK",
|
"OK": "OK",
|
||||||
"OpenLink": "Открыть",
|
"OpenLink": "Открыть",
|
||||||
"Peers": "Пиры",
|
"Peers": "Пиры",
|
||||||
"PeersListenPort": "Порт для входящих подключений",
|
|
||||||
"PEX": "PEX (Peer Exchange)",
|
|
||||||
"PiecesCount": "Кол-во блоков",
|
"PiecesCount": "Кол-во блоков",
|
||||||
"PiecesLength": "Размер блока",
|
"PiecesLength": "Размер блока",
|
||||||
"Preload": "Предзагр.",
|
"Preload": "Предзагр.",
|
||||||
"PreloadBuffer": "Наполнять кеш перед началом воспроизведения",
|
|
||||||
"ProjectSource": "Сайт проекта",
|
"ProjectSource": "Сайт проекта",
|
||||||
"ReaderReadAHead": "Кеш предзагрузки (5-100%, рек. 95%)",
|
|
||||||
"Releases": "Релизы",
|
"Releases": "Релизы",
|
||||||
"RemoveAll": "Удалить все",
|
"RemoveAll": "Удалить все",
|
||||||
"RemoveCacheOnDrop": "Очищать кеш на диске при отключении торрента",
|
|
||||||
"RemoveCacheOnDropDesc": "Если отключено, кэш очищается при удалении торрента.",
|
|
||||||
"RemoveRetrackers": "Удалять",
|
|
||||||
"RemoveViews": "Очистить просмотры",
|
"RemoveViews": "Очистить просмотры",
|
||||||
"ReplaceRetrackers": "Заменять",
|
|
||||||
"Resolution": "Разреш.",
|
"Resolution": "Разреш.",
|
||||||
"RetrackersMode": "Ретрекеры",
|
|
||||||
"Save": "Сохранить",
|
"Save": "Сохранить",
|
||||||
"ScrollDown": "прокрутить вниз",
|
"ScrollDown": "прокрутить вниз",
|
||||||
"Season": "Сезон",
|
"Season": "Сезон",
|
||||||
"SelectSeason": "Выбор сезона",
|
"SelectSeason": "Выбор сезона",
|
||||||
"Settings": "Настройки",
|
"SettingsDialog": {
|
||||||
|
"AddRetrackers": "Добавлять",
|
||||||
|
"AdditionalSettings": "Дополнительные настройки",
|
||||||
|
"CacheBeforeReaderDesc": "От кеша будет оставаться позади воспроизводимого кадра",
|
||||||
|
"CacheAfterReaderDesc": "От кеша будет спереди от воспроизводимого кадра",
|
||||||
|
"CacheSize": "Размер кеша",
|
||||||
|
"CacheSettings": "Настройки кеша",
|
||||||
|
"CacheStorageLocation": "Место хранения кеша",
|
||||||
|
"ConnectionsLimit": "Торрент-соединения (рек. 20-25)",
|
||||||
|
"DHT": "DHT (Distributed Hash Table)",
|
||||||
|
"DhtConnectionLimit": "Лимит подключений DHT",
|
||||||
|
"Disk": "Диск",
|
||||||
|
"DontAddRetrackers": "Ничего не делать",
|
||||||
|
"DownloadRateLimit": "Ограничение скорости загрузки (Килобайты)",
|
||||||
|
"ForceEncrypt": "Принудительное шифрование заголовков",
|
||||||
|
"PeersListenPort": "Порт для входящих подключений",
|
||||||
|
"PreloadBuffer": "Наполнять кеш перед началом воспроизведения",
|
||||||
|
"ProMode": "ПРО режим",
|
||||||
|
"RAM": "Оперативная память",
|
||||||
|
"ReaderReadAHead": "Кеш предзагрузки (5-100%, рек. 95%)",
|
||||||
|
"RemoveCacheOnDrop": "Очищать кеш на диске при отключении торрента",
|
||||||
|
"RemoveCacheOnDropDesc": "Если отключено, кэш очищается при удалении торрента.",
|
||||||
|
"RemoveRetrackers": "Удалять",
|
||||||
|
"ReplaceRetrackers": "Заменять",
|
||||||
|
"RetrackersMode": "Ретрекеры",
|
||||||
|
"ResetToDefault": "Сбросить по умолчанию",
|
||||||
|
"Settings": "Настройки",
|
||||||
|
"TorrentDisconnectTimeout": "Тайм-аут отключения торрента (секунды)",
|
||||||
|
"TorrentsSavePath": "Путь хранения кеша",
|
||||||
|
"Upload": "Отдача (не рекомендуется отключать)",
|
||||||
|
"UploadRateLimit": "Ограничение скорости отдачи (Килобайты)",
|
||||||
|
"UseDiskDesc": "Рекомендуется использовать внешние носители на устройствах с flash-памятью",
|
||||||
|
"Tabs": {
|
||||||
|
"Main": "Основные",
|
||||||
|
"Additional": "Дополнительные",
|
||||||
|
"AdditionalDisabled": "(включите ПРО режим)"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Size": "Размер",
|
"Size": "Размер",
|
||||||
"SpecialThanks": "Отдельное спасибо",
|
"SpecialThanks": "Отдельное спасибо",
|
||||||
"Speed": "Скорость",
|
"Speed": "Скорость",
|
||||||
"Support": "Поддержать",
|
"Support": "Поддержать",
|
||||||
"TCP": "TCP (Transmission Control Protocol)",
|
|
||||||
"ThanksToEveryone": "Спасибо всем, кто тестировал и помогал!",
|
"ThanksToEveryone": "Спасибо всем, кто тестировал и помогал!",
|
||||||
"TorrentAdded": "Добавлен",
|
"TorrentAdded": "Добавлен",
|
||||||
"TorrentClosed": "Закрыт",
|
"TorrentClosed": "Закрыт",
|
||||||
"TorrentContent": "Содержимое торрента",
|
"TorrentContent": "Содержимое торрента",
|
||||||
"TorrentDetails": "Информация о торренте",
|
"TorrentDetails": "Информация о торренте",
|
||||||
"TorrentDisconnectTimeout": "Тайм-аут отключения торрента (секунды)",
|
|
||||||
"TorrentGettingInfo": "Получение инфо",
|
"TorrentGettingInfo": "Получение инфо",
|
||||||
"TorrentInDb": "Торрент в БД",
|
"TorrentInDb": "Торрент в БД",
|
||||||
"TorrentPreload": "Предзагрузка",
|
"TorrentPreload": "Предзагрузка",
|
||||||
"TorrentSize": "Размер торрента",
|
"TorrentSize": "Размер торрента",
|
||||||
"TorrentsSavePath": "Путь хранения кеша",
|
|
||||||
"TorrentState": "Данные торрента",
|
"TorrentState": "Данные торрента",
|
||||||
"TorrentStatus": "Состояние торрента",
|
"TorrentStatus": "Состояние торрента",
|
||||||
"TorrentWorking": "Активен",
|
"TorrentWorking": "Активен",
|
||||||
"TurnOff": "Выключить",
|
"TurnOff": "Выключить",
|
||||||
"Upload": "Отдача (не рекомендуется отключать)",
|
|
||||||
"UploadFile": "Загрузить файл",
|
"UploadFile": "Загрузить файл",
|
||||||
"UploadRateLimit": "Ограничение скорости отдачи (Килобайты)",
|
|
||||||
"UploadSpeed": "Скорость отдачи",
|
"UploadSpeed": "Скорость отдачи",
|
||||||
"UPNP": "UPnP (Universal Plug and Play)",
|
|
||||||
"UseDisk": "Использовать диск для кеша",
|
|
||||||
"UseDiskDesc": "Рекомендуется использовать внешние носители на устройствах с flash-памятью",
|
|
||||||
"UTP": "μTP (Micro Transport Protocol)",
|
|
||||||
"Viewed": "Просм."
|
"Viewed": "Просм."
|
||||||
}
|
}
|
||||||
24
web/src/style/DialogStyles.js
Normal file
24
web/src/style/DialogStyles.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import styled, { css } from 'styled-components'
|
||||||
|
|
||||||
|
export const Header = styled.div`
|
||||||
|
${({ theme: { primary } }) => css`
|
||||||
|
background: ${primary};
|
||||||
|
color: rgba(0, 0, 0, 0.87);
|
||||||
|
font-size: 20px;
|
||||||
|
color: #fff;
|
||||||
|
font-weight: 600;
|
||||||
|
box-shadow: 0px 2px 4px -1px rgb(0 0 0 / 20%), 0px 4px 5px 0px rgb(0 0 0 / 14%), 0px 1px 10px 0px rgb(0 0 0 / 12%);
|
||||||
|
padding: 15px 24px;
|
||||||
|
position: relative;
|
||||||
|
`}
|
||||||
|
`
|
||||||
|
|
||||||
|
export const ButtonWrapper = styled.div`
|
||||||
|
padding: 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
> :not(:last-child) {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
`
|
||||||
@@ -47,6 +47,10 @@ export const themeColors = {
|
|||||||
defaultSecondaryColor: '#00a383',
|
defaultSecondaryColor: '#00a383',
|
||||||
defaultTertiaryColor: '#03aa89',
|
defaultTertiaryColor: '#03aa89',
|
||||||
},
|
},
|
||||||
|
settingsDialog: {
|
||||||
|
contentBG: '#f1eff3',
|
||||||
|
footerBG: '#f1eff3',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
dark: {
|
dark: {
|
||||||
app: {
|
app: {
|
||||||
@@ -94,6 +98,10 @@ export const themeColors = {
|
|||||||
defaultSecondaryColor: rgba('#545a5e', 0.9),
|
defaultSecondaryColor: rgba('#545a5e', 0.9),
|
||||||
defaultTertiaryColor: '#545a5e',
|
defaultTertiaryColor: '#545a5e',
|
||||||
},
|
},
|
||||||
|
settingsDialog: {
|
||||||
|
contentBG: '#5A6166',
|
||||||
|
footerBG: '#323637',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1167,6 +1167,13 @@
|
|||||||
core-js-pure "^3.0.0"
|
core-js-pure "^3.0.0"
|
||||||
regenerator-runtime "^0.13.4"
|
regenerator-runtime "^0.13.4"
|
||||||
|
|
||||||
|
"@babel/runtime@7.0.0":
|
||||||
|
version "7.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.0.0.tgz#adeb78fedfc855aa05bc041640f3f6f98e85424c"
|
||||||
|
integrity sha512-7hGhzlcmg01CvH1EHdSPVXYX1aJ8KCEyz6I9xYIi/asDtzBPMyMhVibhM/K6g/5qnKBwjZtp10bNZIEFTRW1MA==
|
||||||
|
dependencies:
|
||||||
|
regenerator-runtime "^0.12.0"
|
||||||
|
|
||||||
"@babel/runtime@7.12.1":
|
"@babel/runtime@7.12.1":
|
||||||
version "7.12.1"
|
version "7.12.1"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.1.tgz#b4116a6b6711d010b2dad3b7b6e43bf1b9954740"
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.1.tgz#b4116a6b6711d010b2dad3b7b6e43bf1b9954740"
|
||||||
@@ -7894,6 +7901,11 @@ just-debounce@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/just-debounce/-/just-debounce-1.1.0.tgz#2f81a3ad4121a76bc7cb45dbf704c0d76a8e5ddf"
|
resolved "https://registry.yarnpkg.com/just-debounce/-/just-debounce-1.1.0.tgz#2f81a3ad4121a76bc7cb45dbf704c0d76a8e5ddf"
|
||||||
integrity sha512-qpcRocdkUmf+UTNBYx5w6dexX5J31AKK1OmPwH630a83DdVVUIngk55RSAiIGpQyoH0dlr872VHfPjnQnK1qDQ==
|
integrity sha512-qpcRocdkUmf+UTNBYx5w6dexX5J31AKK1OmPwH630a83DdVVUIngk55RSAiIGpQyoH0dlr872VHfPjnQnK1qDQ==
|
||||||
|
|
||||||
|
keycode@^2.1.7:
|
||||||
|
version "2.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.2.0.tgz#3d0af56dc7b8b8e5cba8d0a97f107204eec22b04"
|
||||||
|
integrity sha1-PQr1bce4uOXLqNCpfxByBO7CKwQ=
|
||||||
|
|
||||||
killable@^1.0.1:
|
killable@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892"
|
resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892"
|
||||||
@@ -8158,7 +8170,7 @@ loglevel@^1.6.8:
|
|||||||
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.1.tgz#005fde2f5e6e47068f935ff28573e125ef72f197"
|
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.1.tgz#005fde2f5e6e47068f935ff28573e125ef72f197"
|
||||||
integrity sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==
|
integrity sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==
|
||||||
|
|
||||||
loose-envify@^1.1.0, loose-envify@^1.4.0:
|
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
|
||||||
version "1.4.0"
|
version "1.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
||||||
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
||||||
@@ -10207,7 +10219,7 @@ prompts@^2.0.1:
|
|||||||
kleur "^3.0.3"
|
kleur "^3.0.3"
|
||||||
sisteransi "^1.0.5"
|
sisteransi "^1.0.5"
|
||||||
|
|
||||||
prop-types@^15.5.8, prop-types@^15.6.2, prop-types@^15.7.2:
|
prop-types@^15.5.4, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2:
|
||||||
version "15.7.2"
|
version "15.7.2"
|
||||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
||||||
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
|
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
|
||||||
@@ -10451,6 +10463,15 @@ react-error-overlay@^6.0.9:
|
|||||||
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a"
|
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a"
|
||||||
integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==
|
integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==
|
||||||
|
|
||||||
|
react-event-listener@^0.6.0:
|
||||||
|
version "0.6.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-event-listener/-/react-event-listener-0.6.6.tgz#758f7b991cad9086dd39fd29fad72127e1d8962a"
|
||||||
|
integrity sha512-+hCNqfy7o9wvO6UgjqFmBzARJS7qrNoda0VqzvOuioEpoEXKutiKuv92dSz6kP7rYLmyHPyYNLesi5t/aH1gfw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.2.0"
|
||||||
|
prop-types "^15.6.0"
|
||||||
|
warning "^4.0.1"
|
||||||
|
|
||||||
react-i18next@^11.10.0:
|
react-i18next@^11.10.0:
|
||||||
version "11.10.0"
|
version "11.10.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.10.0.tgz#f34257447e18e710e36d8fd3f721dd7d37c7004f"
|
resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.10.0.tgz#f34257447e18e710e36d8fd3f721dd7d37c7004f"
|
||||||
@@ -10559,6 +10580,37 @@ react-scripts@4.0.3:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents "^2.1.3"
|
fsevents "^2.1.3"
|
||||||
|
|
||||||
|
react-swipeable-views-core@^0.14.0:
|
||||||
|
version "0.14.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-swipeable-views-core/-/react-swipeable-views-core-0.14.0.tgz#6ac443a7cc7bc5ea022fbd549292bb5fff361cce"
|
||||||
|
integrity sha512-0W/e9uPweNEOSPjmYtuKSC/SvKKg1sfo+WtPdnxeLF3t2L82h7jjszuOHz9C23fzkvLfdgkaOmcbAxE9w2GEjA==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "7.0.0"
|
||||||
|
warning "^4.0.1"
|
||||||
|
|
||||||
|
react-swipeable-views-utils@^0.14.0:
|
||||||
|
version "0.14.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-swipeable-views-utils/-/react-swipeable-views-utils-0.14.0.tgz#6b76e251906747482730c22002fe47ab1014ba32"
|
||||||
|
integrity sha512-W+fXBOsDqgFK1/g7MzRMVcDurp3LqO3ksC8UgInh2P/tKgb5DusuuB1geKHFc6o1wKl+4oyER4Zh3Lxmr8xbXA==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "7.0.0"
|
||||||
|
keycode "^2.1.7"
|
||||||
|
prop-types "^15.6.0"
|
||||||
|
react-event-listener "^0.6.0"
|
||||||
|
react-swipeable-views-core "^0.14.0"
|
||||||
|
shallow-equal "^1.2.1"
|
||||||
|
|
||||||
|
react-swipeable-views@^0.14.0:
|
||||||
|
version "0.14.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-swipeable-views/-/react-swipeable-views-0.14.0.tgz#149c0df3d92220cc89e3f6d5c04a78dfe46f9b54"
|
||||||
|
integrity sha512-wrTT6bi2nC3JbmyNAsPXffUXLn0DVT9SbbcFr36gKpbaCgEp7rX/OFxsu5hPc/NBsUhHyoSRGvwqJNNrWTwCww==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "7.0.0"
|
||||||
|
prop-types "^15.5.4"
|
||||||
|
react-swipeable-views-core "^0.14.0"
|
||||||
|
react-swipeable-views-utils "^0.14.0"
|
||||||
|
warning "^4.0.1"
|
||||||
|
|
||||||
react-transition-group@^4.4.0:
|
react-transition-group@^4.4.0:
|
||||||
version "4.4.1"
|
version "4.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.1.tgz#63868f9325a38ea5ee9535d828327f85773345c9"
|
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.1.tgz#63868f9325a38ea5ee9535d828327f85773345c9"
|
||||||
@@ -10699,6 +10751,11 @@ regenerator-runtime@^0.11.0:
|
|||||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
|
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
|
||||||
integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
|
integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
|
||||||
|
|
||||||
|
regenerator-runtime@^0.12.0:
|
||||||
|
version "0.12.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de"
|
||||||
|
integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==
|
||||||
|
|
||||||
regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.7:
|
regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.7:
|
||||||
version "0.13.7"
|
version "0.13.7"
|
||||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
|
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
|
||||||
@@ -11315,6 +11372,11 @@ sha.js@^2.4.0, sha.js@^2.4.8:
|
|||||||
inherits "^2.0.1"
|
inherits "^2.0.1"
|
||||||
safe-buffer "^5.0.1"
|
safe-buffer "^5.0.1"
|
||||||
|
|
||||||
|
shallow-equal@^1.2.1:
|
||||||
|
version "1.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/shallow-equal/-/shallow-equal-1.2.1.tgz#4c16abfa56043aa20d050324efa68940b0da79da"
|
||||||
|
integrity sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==
|
||||||
|
|
||||||
shallowequal@^1.1.0:
|
shallowequal@^1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
|
resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
|
||||||
@@ -12751,6 +12813,13 @@ walker@^1.0.7, walker@~1.0.5:
|
|||||||
dependencies:
|
dependencies:
|
||||||
makeerror "1.0.x"
|
makeerror "1.0.x"
|
||||||
|
|
||||||
|
warning@^4.0.1:
|
||||||
|
version "4.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3"
|
||||||
|
integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==
|
||||||
|
dependencies:
|
||||||
|
loose-envify "^1.0.0"
|
||||||
|
|
||||||
watchpack-chokidar2@^2.0.1:
|
watchpack-chokidar2@^2.0.1:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz#38500072ee6ece66f3769936950ea1771be1c957"
|
resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz#38500072ee6ece66f3769936950ea1771be1c957"
|
||||||
|
|||||||
Reference in New Issue
Block a user