mirror of
https://github.com/Ernous/TorrServerJellyfin.git
synced 2025-12-19 21:46:11 +05:00
merge maser
This commit is contained in:
@@ -46,7 +46,7 @@ export const Section = styled.section`
|
||||
padding: 20px;
|
||||
|
||||
> span {
|
||||
font-size: 20px;
|
||||
font-size: 22px;
|
||||
display: block;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
@@ -87,7 +87,7 @@ export const LinkWrapper = styled.a`
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
border: 1px solid;
|
||||
padding: 10px;
|
||||
padding: 7px 10px;
|
||||
border-radius: 5px;
|
||||
text-transform: uppercase;
|
||||
text-decoration: none;
|
||||
@@ -105,7 +105,7 @@ export const LinkWrapper = styled.a`
|
||||
filter: brightness(1.1);
|
||||
|
||||
> * {
|
||||
transform: translateY(-1px);
|
||||
transform: translateY(0px);
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
@@ -14,7 +14,7 @@ import { getTorrents } from 'utils/Utils'
|
||||
import parseTorrent from 'parse-torrent'
|
||||
import { ButtonWrapper, Header } from 'style/DialogStyles'
|
||||
|
||||
import { checkImageURL, getMoviePosters, chechTorrentSource, parseTorrentTitle } from './helpers'
|
||||
import { checkImageURL, getMoviePosters, checkTorrentSource, parseTorrentTitle } from './helpers'
|
||||
import { Content } from './style'
|
||||
import RightSideComponent from './RightSideComponent'
|
||||
import LeftSideComponent from './LeftSideComponent'
|
||||
@@ -147,7 +147,7 @@ export default function AddDialog({
|
||||
const prevTorrentSourceState = usePreviousState(torrentSource)
|
||||
|
||||
useEffect(() => {
|
||||
const isCorrectSource = chechTorrentSource(torrentSource)
|
||||
const isCorrectSource = checkTorrentSource(torrentSource)
|
||||
if (!isCorrectSource) return setIsTorrentSourceCorrect(false)
|
||||
|
||||
setIsTorrentSourceCorrect(true)
|
||||
@@ -227,10 +227,10 @@ export default function AddDialog({
|
||||
{!isEditMode && (
|
||||
<LeftSideComponent
|
||||
setIsUserInteractedWithPoster={setIsUserInteractedWithPoster}
|
||||
selectedFile={selectedFile}
|
||||
setSelectedFile={setSelectedFile}
|
||||
torrentSource={torrentSource}
|
||||
setTorrentSource={setTorrentSource}
|
||||
selectedFile={selectedFile}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -271,7 +271,7 @@ export default function AddDialog({
|
||||
style={{ minWidth: '110px' }}
|
||||
disabled={!torrentSource || (isHashAlreadyExists && !isEditMode) || !isTorrentSourceCorrect}
|
||||
onClick={handleSave}
|
||||
color='primary'
|
||||
color='secondary'
|
||||
>
|
||||
{isSaving ? <CircularProgress style={{ color: 'white' }} size={20} /> : t(isEditMode ? 'Save' : 'Add')}
|
||||
</Button>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { rgba } from 'polished'
|
||||
import { NoImageIcon } from 'icons'
|
||||
import { IconButton, InputAdornment, TextField, useTheme } from '@material-ui/core'
|
||||
import { CheckBox as CheckBoxIcon } from '@material-ui/icons'
|
||||
import { HighlightOff as HighlightOffIcon } from '@material-ui/icons'
|
||||
|
||||
import {
|
||||
ClearPosterButton,
|
||||
@@ -84,7 +85,7 @@ export default function RightSideComponent({
|
||||
endAdornment: (
|
||||
<InputAdornment position='end'>
|
||||
<IconButton
|
||||
style={{ padding: '0 0 0 7px' }}
|
||||
style={{ padding: '1px' }}
|
||||
onClick={() => {
|
||||
setTitle('')
|
||||
setIsCustomTitleEnabled(!isCustomTitleEnabled)
|
||||
@@ -92,7 +93,7 @@ export default function RightSideComponent({
|
||||
setIsUserInteractedWithPoster(false)
|
||||
}}
|
||||
>
|
||||
<CheckBoxIcon style={{ color: isCustomTitleEnabled ? primary : 'gray' }} />
|
||||
<HighlightOffIcon style={{ color: isCustomTitleEnabled ? primary : rgba('#ccc', 0.5) }} />
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
),
|
||||
|
||||
@@ -22,20 +22,19 @@ export const getMoviePosters = (movieName, language = 'en') => {
|
||||
|
||||
export const checkImageURL = async url => {
|
||||
if (!url || !url.match(/.(jpg|jpeg|png|gif)$/i)) return false
|
||||
|
||||
try {
|
||||
await fetch(url, { mode: 'no-cors' })
|
||||
return true
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
const magnetRegex = /^magnet:\?xt=urn:[a-z0-9].*/i
|
||||
export const hashRegex = /^\b[0-9a-f]{32}\b$|^\b[0-9a-f]{40}\b$|^\b[0-9a-f]{64}\b$/i
|
||||
const torrentRegex = /^.*\.(torrent)$/i
|
||||
export const chechTorrentSource = source =>
|
||||
source.match(hashRegex) !== null || source.match(magnetRegex) !== null || source.match(torrentRegex) !== null
|
||||
const linkRegex = /^(http(s?)):\/\/.*/i
|
||||
|
||||
export const checkTorrentSource = source =>
|
||||
source.match(hashRegex) !== null ||
|
||||
source.match(magnetRegex) !== null ||
|
||||
source.match(torrentRegex) !== null ||
|
||||
source.match(linkRegex) !== null
|
||||
|
||||
export const parseTorrentTitle = (parsingSource, callback) => {
|
||||
parseTorrent.remote(parsingSource, (err, { name, files } = {}) => {
|
||||
|
||||
@@ -1,34 +1,31 @@
|
||||
import Button from '@material-ui/core/Button'
|
||||
import { AppBar, IconButton, makeStyles, Toolbar, Typography } from '@material-ui/core'
|
||||
import CloseIcon from '@material-ui/icons/Close'
|
||||
import { ArrowBack } from '@material-ui/icons'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
const useStyles = makeStyles({
|
||||
appBar: { position: 'relative' },
|
||||
title: { marginLeft: '6px', flex: 1 },
|
||||
}))
|
||||
title: { marginLeft: '5px', flex: 1 },
|
||||
})
|
||||
|
||||
export default function DialogHeader({ title, onClose, onBack }) {
|
||||
const { t } = useTranslation()
|
||||
const classes = useStyles()
|
||||
|
||||
return (
|
||||
<AppBar className={classes.appBar}>
|
||||
<Toolbar>
|
||||
<IconButton edge='start' color='inherit' onClick={onBack || onClose} aria-label='close'>
|
||||
{onBack ? <ArrowBack /> : <CloseIcon />}
|
||||
</IconButton>
|
||||
{onBack && (
|
||||
<IconButton edge='start' color='inherit' onClick={onBack} aria-label='back'>
|
||||
<ArrowBack />
|
||||
</IconButton>
|
||||
)}
|
||||
|
||||
<Typography variant='h6' className={classes.title}>
|
||||
{title}
|
||||
</Typography>
|
||||
|
||||
{onBack && (
|
||||
<Button autoFocus color='inherit' onClick={onClose}>
|
||||
{t('Close')}
|
||||
</Button>
|
||||
)}
|
||||
<IconButton autoFocus color='inherit' onClick={onClose} aria-label='close' style={{ marginRight: '-10px' }}>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
)
|
||||
|
||||
@@ -62,9 +62,10 @@ const TorrentCache = ({ cache, isMini }) => {
|
||||
|
||||
ctx.clearRect(0, 0, canvasWidth, height)
|
||||
|
||||
source.forEach(({ percentage, isReader, isReaderRange }, i) => {
|
||||
source.forEach(({ percentage, priority, isReader, isReaderRange }, i) => {
|
||||
const inProgress = percentage > 0 && percentage < 100
|
||||
const isCompleted = percentage === 100
|
||||
const peacePriority = priority
|
||||
const currentRow = i % piecesInOneRow
|
||||
const currentColumn = Math.floor(i / piecesInOneRow)
|
||||
const fixBlurStroke = borderWidth % 2 === 0 ? 0 : 0.5
|
||||
@@ -90,6 +91,20 @@ const TorrentCache = ({ cache, isMini }) => {
|
||||
ctx.fillRect(0, 0, pieceSize, pieceSize)
|
||||
ctx.strokeRect(0, 0, pieceSize, pieceSize)
|
||||
ctx.setTransform(1, 0, 0, 1, 0, 0)
|
||||
|
||||
if (peacePriority > 0) {
|
||||
let info = ''
|
||||
if (peacePriority === 1) info = '*'
|
||||
else if (peacePriority === 2) info = 'H'
|
||||
else if (peacePriority === 3) info = 'R'
|
||||
else if (peacePriority === 4) info = 'N'
|
||||
else if (peacePriority === 5) info = 'A'
|
||||
ctx.font = isMini ? '12px monospace' : '10px monospace'
|
||||
const xpad = isMini ? pieceSize * 0.34 : pieceSize * 0.28
|
||||
const ypad = isMini ? pieceSize * 0.69 : pieceSize * 0.78
|
||||
ctx.fillStyle = 'black'
|
||||
ctx.fillText(info, x + xpad, y + ypad)
|
||||
}
|
||||
})
|
||||
}, [
|
||||
cacheMap,
|
||||
@@ -107,6 +122,7 @@ const TorrentCache = ({ cache, isMini }) => {
|
||||
completeColor,
|
||||
readerColor,
|
||||
rangeColor,
|
||||
isMini,
|
||||
theme,
|
||||
])
|
||||
|
||||
|
||||
@@ -4,14 +4,14 @@ import { mainColors } from 'style/colors'
|
||||
export const snakeSettings = {
|
||||
dark: {
|
||||
default: {
|
||||
borderWidth: 2,
|
||||
borderWidth: 1,
|
||||
pieceSize: 14,
|
||||
gapBetweenPieces: 3,
|
||||
borderColor: mainColors.dark.secondary,
|
||||
completeColor: rgba(mainColors.dark.primary, 0.65),
|
||||
borderColor: rgba('#949ca0', 0.25),
|
||||
completeColor: rgba(mainColors.dark.primary, 0.5),
|
||||
backgroundColor: '#f1eff3',
|
||||
progressColor: mainColors.dark.secondary,
|
||||
readerColor: '#000',
|
||||
readerColor: '#8f0405',
|
||||
rangeColor: '#cda184',
|
||||
},
|
||||
mini: {
|
||||
@@ -19,11 +19,11 @@ export const snakeSettings = {
|
||||
borderWidth: 2,
|
||||
pieceSize: 23,
|
||||
gapBetweenPieces: 6,
|
||||
borderColor: '#545a5e',
|
||||
completeColor: '#545a5e',
|
||||
backgroundColor: '#dee3e5',
|
||||
progressColor: '#dee3e5',
|
||||
readerColor: '#000',
|
||||
borderColor: '#5c6469',
|
||||
completeColor: '#5c6469',
|
||||
backgroundColor: '#949ca0',
|
||||
progressColor: '#949ca0',
|
||||
readerColor: '#ccc',
|
||||
rangeColor: '#cda184',
|
||||
},
|
||||
},
|
||||
@@ -48,7 +48,7 @@ export const snakeSettings = {
|
||||
completeColor: '#4db380',
|
||||
backgroundColor: '#dbf2e8',
|
||||
progressColor: '#dbf2e8',
|
||||
readerColor: '#2d714f',
|
||||
readerColor: '#0a0a0a',
|
||||
rangeColor: '#afa6e3',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -43,9 +43,9 @@ export const useCreateCacheMap = cache => {
|
||||
const map = []
|
||||
|
||||
for (let i = 0; i < PiecesCount; i++) {
|
||||
const { Size, Length } = Pieces[i] || {}
|
||||
const { Size, Length, Priority } = Pieces[i] || {}
|
||||
|
||||
const newPiece = { id: i, percentage: (Size / Length) * 100 || 0 }
|
||||
const newPiece = { id: i, percentage: (Size / Length) * 100 || 0, priority: Priority || 0 }
|
||||
|
||||
Readers.forEach(r => {
|
||||
if (i === r.Reader) newPiece.isReader = true
|
||||
|
||||
@@ -204,6 +204,7 @@ export default function DialogTorrentDetailsContent({ closeDialog, torrent }) {
|
||||
{bufferSize <= 33554432 && <SectionSubName>{t('BufferNote')}</SectionSubName>}
|
||||
<LoadingProgress
|
||||
value={Filled}
|
||||
style={{ marginTop: '5px' }}
|
||||
fullAmount={bufferSize}
|
||||
label={`${humanizeSize(bufferSize)} / ${humanizeSize(Filled) || `0 ${t('B')}`}`}
|
||||
/>
|
||||
|
||||
@@ -129,12 +129,15 @@ export const SectionSubName = styled.div`
|
||||
},
|
||||
}) => css`
|
||||
${({ mb }) => css`
|
||||
${mb && `margin-top: ${mb / 3}px`};
|
||||
${mb && `margin-bottom: ${mb}px`};
|
||||
line-height: 1.2;
|
||||
color: ${subNameFontColor};
|
||||
|
||||
@media (max-width: 800px) {
|
||||
${mb && `margin-top: ${mb / 4}px`};
|
||||
${mb && `margin-bottom: ${mb / 2}px`};
|
||||
font-size: 11px;
|
||||
font-size: 14px;
|
||||
}
|
||||
`}
|
||||
`}
|
||||
@@ -149,14 +152,15 @@ export const SectionTitle = styled.div`
|
||||
}) => css`
|
||||
${({ mb }) => css`
|
||||
${mb && `margin-bottom: ${mb}px`};
|
||||
font-size: 35px;
|
||||
font-size: 34px;
|
||||
font-weight: 300;
|
||||
line-height: 1;
|
||||
word-break: break-word;
|
||||
color: ${color || titleFontColor};
|
||||
|
||||
@media (max-width: 800px) {
|
||||
font-size: 25px;
|
||||
font-size: 24px;
|
||||
line-height: 1.1;
|
||||
${mb && `margin-bottom: ${mb / 2}px`};
|
||||
}
|
||||
`}
|
||||
@@ -258,15 +262,16 @@ export const WidgetFieldValue = styled.div`
|
||||
},
|
||||
}) => css`
|
||||
grid-area: value;
|
||||
padding: 0 20px;
|
||||
font-size: 24px;
|
||||
padding: 0 20px 0 0;
|
||||
color: ${widgetFontColor};
|
||||
font-size: 25px;
|
||||
background: ${bgColor};
|
||||
border-radius: 0 5px 5px 0;
|
||||
white-space: nowrap;
|
||||
|
||||
@media (max-width: 800px) {
|
||||
font-size: 18px;
|
||||
padding: 0 4px;
|
||||
padding: 0 16px 0 0;
|
||||
}
|
||||
`}
|
||||
`
|
||||
@@ -276,7 +281,7 @@ export const LoadingProgress = styled.div.attrs(
|
||||
value,
|
||||
fullAmount,
|
||||
theme: {
|
||||
dialogTorrentDetailsContent: { gradientEndColor },
|
||||
dialogTorrentDetailsContent: { gradientStartColor, gradientEndColor },
|
||||
},
|
||||
}) => {
|
||||
const percentage = Math.min(100, (value * 100) / fullAmount)
|
||||
@@ -284,7 +289,7 @@ export const LoadingProgress = styled.div.attrs(
|
||||
return {
|
||||
// this block is here according to styled-components recomendation about fast changable components
|
||||
style: {
|
||||
background: `linear-gradient(to right, ${gradientEndColor} 0%, ${gradientEndColor} ${percentage}%, #fff ${percentage}%, #fff 100%)`,
|
||||
background: `linear-gradient(to right, ${gradientStartColor} 0%, ${gradientEndColor} ${percentage}%, #fff ${percentage}%, #fff 100%)`,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
@@ -50,13 +50,13 @@ export default function PrimarySettingsComponent({
|
||||
|
||||
<PreloadCachePercentage
|
||||
value={100 - cachePercentage}
|
||||
label={`${t('Cache')} ${cacheSize} MB`}
|
||||
label={`${t('Cache')} ${cacheSize} ${t('MB')}`}
|
||||
preloadCachePercentage={preloadCachePercentage}
|
||||
/>
|
||||
|
||||
<PreloadCacheValue color={cacheBeforeReaderColor}>
|
||||
<div>
|
||||
{100 - cachePercentage}% ({Math.round((cacheSize / 100) * (100 - cachePercentage))} MB)
|
||||
{100 - cachePercentage}% ({Math.round((cacheSize / 100) * (100 - cachePercentage))} {t('MB')})
|
||||
</div>
|
||||
|
||||
<div>{t('SettingsDialog.CacheBeforeReaderDesc')}</div>
|
||||
@@ -64,7 +64,7 @@ export default function PrimarySettingsComponent({
|
||||
|
||||
<PreloadCacheValue color={cacheAfterReaderColor}>
|
||||
<div>
|
||||
{cachePercentage}% ({Math.round((cacheSize / 100) * cachePercentage)} MB)
|
||||
{cachePercentage}% ({Math.round((cacheSize / 100) * cachePercentage)} {t('MB')})
|
||||
</div>
|
||||
|
||||
<div>{t('SettingsDialog.CacheAfterReaderDesc')}</div>
|
||||
@@ -80,9 +80,9 @@ export default function PrimarySettingsComponent({
|
||||
sliderMin={32}
|
||||
sliderMax={1024}
|
||||
inputMin={32}
|
||||
inputMax={20000}
|
||||
step={8}
|
||||
onBlurCallback={value => setCacheSize(Math.round(value / 8) * 8)}
|
||||
inputMax={999999}
|
||||
step={4}
|
||||
onBlurCallback={value => setCacheSize(Math.round(value / 4) * 4)}
|
||||
/>
|
||||
|
||||
<SliderInput
|
||||
@@ -98,7 +98,7 @@ export default function PrimarySettingsComponent({
|
||||
|
||||
<SliderInput
|
||||
isProMode={isProMode}
|
||||
title={`${t('SettingsDialog.PreloadCache')} - ${preloadCachePercentage}% (${preloadCacheSize} MB)`}
|
||||
title={`${t('SettingsDialog.PreloadCache')} - ${preloadCachePercentage}% (${preloadCacheSize} ${t('MB')})`}
|
||||
value={preloadCachePercentage}
|
||||
setValue={setPreloadCachePercentage}
|
||||
sliderMin={0}
|
||||
|
||||
@@ -85,16 +85,6 @@ export default function SecondarySettingsComponent({ settings, inputForm }) {
|
||||
label={t('SettingsDialog.DHT')}
|
||||
labelPlacement='start'
|
||||
/>
|
||||
<TextField
|
||||
onChange={inputForm}
|
||||
margin='normal'
|
||||
id='DhtConnectionLimit'
|
||||
label={t('SettingsDialog.DhtConnectionLimit')}
|
||||
value={DhtConnectionLimit}
|
||||
type='number'
|
||||
variant='outlined'
|
||||
fullWidth
|
||||
/>
|
||||
<br />
|
||||
<TextField
|
||||
onChange={inputForm}
|
||||
@@ -134,6 +124,7 @@ export default function SecondarySettingsComponent({ settings, inputForm }) {
|
||||
margin='normal'
|
||||
id='PeersListenPort'
|
||||
label={t('SettingsDialog.PeersListenPort')}
|
||||
helperText={t('SettingsDialog.PeersListenPortHint')}
|
||||
value={PeersListenPort}
|
||||
type='number'
|
||||
variant='outlined'
|
||||
|
||||
@@ -129,7 +129,7 @@ const Torrent = ({ torrent }) => {
|
||||
<Dialog open={isDeleteTorrentOpened} onClose={closeDeleteTorrentAlert}>
|
||||
<DialogTitle>{t('DeleteTorrent?')}</DialogTitle>
|
||||
<DialogActions>
|
||||
<Button variant='outlined' onClick={closeDeleteTorrentAlert} color='primary'>
|
||||
<Button variant='outlined' onClick={closeDeleteTorrentAlert} color='secondary'>
|
||||
{t('Cancel')}
|
||||
</Button>
|
||||
|
||||
@@ -139,7 +139,7 @@ const Torrent = ({ torrent }) => {
|
||||
deleteTorrent(torrent)
|
||||
closeDeleteTorrentAlert()
|
||||
}}
|
||||
color='primary'
|
||||
color='secondary'
|
||||
autoFocus
|
||||
>
|
||||
{t('OK')}
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
"HashExists": "This torrent is already in database",
|
||||
"OriginalTorrentTitle": "Original torrent title",
|
||||
"TitleBlank": "Title (blank for orig. torrent title)",
|
||||
"TorrentSourceLink": "Torrent source link",
|
||||
"TorrentSourceLink": "Torrent source",
|
||||
"TorrentSourceOptions": "magnet / hash / .torrent file link",
|
||||
"WrongTorrentSource": "Wrong torrent source"
|
||||
},
|
||||
"AddFromLink": "Add from Link",
|
||||
"AddFromLink": "Add Torrent",
|
||||
"AddNewTorrent": "Add new torrent",
|
||||
"B": "B",
|
||||
"bps": "bps",
|
||||
@@ -100,6 +100,7 @@
|
||||
"DownloadRateLimit": "Download Rate Limit",
|
||||
"ForceEncrypt": "Force Encrypt Headers",
|
||||
"PeersListenPort": "Peers Listen Port",
|
||||
"PeersListenPortHint": "1024 - 65535, 0 - auto",
|
||||
"PreloadCache": "Preload Cache Before Play",
|
||||
"ProMode": "PRO mode",
|
||||
"RAM": "RAM",
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
"Or": "ИЛИ",
|
||||
"ClickOrDrag": "НАЖМИТЕ / ПЕРЕТАЩИТЕ ФАЙЛ (.torrent)"
|
||||
},
|
||||
"CustomTorrentTitle": "Cвое имя (не обязательно)",
|
||||
"CustomTorrentTitle": "Cвое название (не обязательно)",
|
||||
"CustomTorrentTitleHelperText": "Напишите свое название, чтобы найти постер",
|
||||
"HashExists": "Этот торрент уже есть в базе данных",
|
||||
"OriginalTorrentTitle": "Оригинальное имя торрента",
|
||||
"TitleBlank": "Имя (пустое - ориг. имя торрента)",
|
||||
"OriginalTorrentTitle": "Оригинальное название торрента",
|
||||
"TitleBlank": "Название (пустое - ориг. название торрента)",
|
||||
"TorrentSourceLink": "Ссылка на источник торрента",
|
||||
"TorrentSourceOptions": "magnet-ссылка / хеш / ссылка на .torrent файл",
|
||||
"WrongTorrentSource": "Неправильный torrent-источник"
|
||||
@@ -100,6 +100,7 @@
|
||||
"DownloadRateLimit": "Ограничение скорости загрузки",
|
||||
"ForceEncrypt": "Принудительное шифрование заголовков",
|
||||
"PeersListenPort": "Порт для входящих подключений",
|
||||
"PeersListenPortHint": "1024 - 65535, 0 - авто",
|
||||
"PreloadCache": "Буфер предзагрузки",
|
||||
"ProMode": "ПРО-режим",
|
||||
"RAM": "Оперативная память",
|
||||
|
||||
Reference in New Issue
Block a user