This commit is contained in:
Daniel Shleifman
2021-06-17 03:28:22 +03:00
parent 3930c26715
commit fd6e227b4f
8 changed files with 107 additions and 47 deletions

View File

@@ -9,6 +9,9 @@ import useChangeLanguage from 'utils/useChangeLanguage'
import { useMediaQuery } from '@material-ui/core' import { useMediaQuery } from '@material-ui/core'
import CircularProgress from '@material-ui/core/CircularProgress' import CircularProgress from '@material-ui/core/CircularProgress'
import usePreviousState from 'utils/usePreviousState' import usePreviousState from 'utils/usePreviousState'
import { useQuery } from 'react-query'
import { getTorrents } from 'utils/Utils'
import parseTorrent from 'parse-torrent'
import { checkImageURL, getMoviePosters, chechTorrentSource, parseTorrentTitle } from './helpers' import { checkImageURL, getMoviePosters, chechTorrentSource, parseTorrentTitle } from './helpers'
import { ButtonWrapper, Content, Header } from './style' import { ButtonWrapper, Content, Header } from './style'
@@ -31,6 +34,7 @@ export default function AddDialog({
const [posterUrl, setPosterUrl] = useState(originalPoster || '') const [posterUrl, setPosterUrl] = useState(originalPoster || '')
const [isPosterUrlCorrect, setIsPosterUrlCorrect] = useState(false) const [isPosterUrlCorrect, setIsPosterUrlCorrect] = useState(false)
const [isTorrentSourceCorrect, setIsTorrentSourceCorrect] = useState(false) const [isTorrentSourceCorrect, setIsTorrentSourceCorrect] = useState(false)
const [isHashAlreadyExists, setIsHashAlreadyExists] = useState(false)
const [posterList, setPosterList] = useState() const [posterList, setPosterList] = useState()
const [isUserInteractedWithPoster, setIsUserInteractedWithPoster] = useState(isEditMode) const [isUserInteractedWithPoster, setIsUserInteractedWithPoster] = useState(isEditMode)
const [currentLang] = useChangeLanguage() const [currentLang] = useChangeLanguage()
@@ -40,6 +44,19 @@ export default function AddDialog({
const [skipDebounce, setSkipDebounce] = useState(false) const [skipDebounce, setSkipDebounce] = useState(false)
const [isCustomTitleEnabled, setIsCustomTitleEnabled] = useState(false) const [isCustomTitleEnabled, setIsCustomTitleEnabled] = useState(false)
const { data: torrents } = useQuery('torrents', getTorrents, {
retry: 1,
refetchInterval: 1000,
})
useEffect(() => {
const allHashes = torrents.map(({ hash }) => hash)
parseTorrent.remote(selectedFile || torrentSource, (err, { infoHash } = {}) => {
setIsHashAlreadyExists(allHashes.includes(infoHash))
})
}, [selectedFile, torrentSource, torrents])
const fullScreen = useMediaQuery('@media (max-width:930px)') const fullScreen = useMediaQuery('@media (max-width:930px)')
const updateTitleFromSource = useCallback(() => { const updateTitleFromSource = useCallback(() => {
@@ -58,6 +75,7 @@ export default function AddDialog({
if (!selectedFile && !torrentSource) { if (!selectedFile && !torrentSource) {
setTitle('') setTitle('')
setOriginalTorrentTitle('') setOriginalTorrentTitle('')
setParsedTitle('')
setIsCustomTitleEnabled(false) setIsCustomTitleEnabled(false)
setPosterList() setPosterList()
removePoster() removePoster()
@@ -143,6 +161,7 @@ export default function AddDialog({
if (parsedTitle) { if (parsedTitle) {
posterSearch(parsedTitle, posterSearchLanguage) posterSearch(parsedTitle, posterSearchLanguage)
} else { } else {
delayedPosterSearch.cancel()
!isUserInteractedWithPoster && removePoster() !isUserInteractedWithPoster && removePoster()
} }
} else { } else {
@@ -217,6 +236,7 @@ export default function AddDialog({
setIsUserInteractedWithPoster={setIsUserInteractedWithPoster} setIsUserInteractedWithPoster={setIsUserInteractedWithPoster}
setPosterList={setPosterList} setPosterList={setPosterList}
isTorrentSourceCorrect={isTorrentSourceCorrect} isTorrentSourceCorrect={isTorrentSourceCorrect}
isHashAlreadyExists={isHashAlreadyExists}
title={title} title={title}
parsedTitle={parsedTitle} parsedTitle={parsedTitle}
posterUrl={posterUrl} posterUrl={posterUrl}
@@ -231,6 +251,7 @@ export default function AddDialog({
torrentSource={torrentSource} torrentSource={torrentSource}
isCustomTitleEnabled={isCustomTitleEnabled} isCustomTitleEnabled={isCustomTitleEnabled}
setIsCustomTitleEnabled={setIsCustomTitleEnabled} setIsCustomTitleEnabled={setIsCustomTitleEnabled}
isEditMode={isEditMode}
/> />
</Content> </Content>
@@ -242,7 +263,7 @@ export default function AddDialog({
<Button <Button
variant='contained' variant='contained'
style={{ minWidth: '110px' }} style={{ minWidth: '110px' }}
disabled={!torrentSource} disabled={!torrentSource || isHashAlreadyExists || !isTorrentSourceCorrect}
onClick={handleSave} onClick={handleSave}
color='primary' color='primary'
> >

View File

@@ -50,8 +50,8 @@ export default function LeftSideComponent({
onChange={handleTorrentSourceChange} onChange={handleTorrentSourceChange}
value={torrentSource} value={torrentSource}
margin='dense' margin='dense'
label={t('TorrentSourceLink')} label={t('AddDialog.TorrentSourceLink')}
helperText={t('TorrentSourceOptions')} helperText={t('AddDialog.TorrentSourceOptions')}
type='text' type='text'
fullWidth fullWidth
onFocus={() => setIsTorrentSourceActive(true)} onFocus={() => setIsTorrentSourceActive(true)}
@@ -74,11 +74,11 @@ export default function LeftSideComponent({
) : ( ) : (
<LeftSideBottomSectionNoFile isDragActive={isDragActive} {...getRootProps()}> <LeftSideBottomSectionNoFile isDragActive={isDragActive} {...getRootProps()}>
<input {...getInputProps()} /> <input {...getInputProps()} />
<div>{t('AppendFile.Or')}</div> <div>{t('AddDialog.AppendFile.Or')}</div>
<IconWrapper> <IconWrapper>
<AddItemIcon color='primary' /> <AddItemIcon color='primary' />
<div>{t('AppendFile.ClickOrDrag')}</div> <div>{t('AddDialog.AppendFile.ClickOrDrag')}</div>
</IconWrapper> </IconWrapper>
</LeftSideBottomSectionNoFile> </LeftSideBottomSectionNoFile>
)} )}

View File

@@ -22,6 +22,7 @@ export default function RightSideComponent({
setIsUserInteractedWithPoster, setIsUserInteractedWithPoster,
setPosterList, setPosterList,
isTorrentSourceCorrect, isTorrentSourceCorrect,
isHashAlreadyExists,
title, title,
parsedTitle, parsedTitle,
posterUrl, posterUrl,
@@ -37,6 +38,7 @@ export default function RightSideComponent({
updateTitleFromSource, updateTitleFromSource,
isCustomTitleEnabled, isCustomTitleEnabled,
setIsCustomTitleEnabled, setIsCustomTitleEnabled,
isEditMode,
}) { }) {
const { t } = useTranslation() const { t } = useTranslation()
@@ -55,14 +57,13 @@ export default function RightSideComponent({
return ( return (
<RightSide> <RightSide>
<RightSideContainer isHidden={!isTorrentSourceCorrect}> <RightSideContainer isHidden={!isTorrentSourceCorrect || (isHashAlreadyExists && !isEditMode)}>
{originalTorrentTitle ? ( {originalTorrentTitle ? (
<> <>
<TextField <TextField
value={originalTorrentTitle} value={originalTorrentTitle}
margin='dense' margin='dense'
// label={t('Title')} label={t('AddDialog.OriginalTorrentTitle')}
label='Оригинальное название торрента'
type='text' type='text'
fullWidth fullWidth
disabled={isCustomTitleEnabled} disabled={isCustomTitleEnabled}
@@ -74,7 +75,7 @@ export default function RightSideComponent({
onBlur={({ target: { value } }) => !value && setIsCustomTitleEnabled(false)} onBlur={({ target: { value } }) => !value && setIsCustomTitleEnabled(false)}
value={title} value={title}
margin='dense' margin='dense'
label='Использовать свое название (не обязательно)' label={t('AddDialog.CustomTorrentTitle')}
type='text' type='text'
fullWidth fullWidth
InputProps={{ InputProps={{
@@ -101,7 +102,7 @@ export default function RightSideComponent({
onChange={handleTitleChange} onChange={handleTitleChange}
value={title} value={title}
margin='dense' margin='dense'
label='Использовать свое название (не обязательно)' label={t('AddDialog.TitleBlank')}
type='text' type='text'
fullWidth fullWidth
/> />
@@ -110,7 +111,7 @@ export default function RightSideComponent({
onChange={handlePosterUrlChange} onChange={handlePosterUrlChange}
value={posterUrl} value={posterUrl}
margin='dense' margin='dense'
label={t('AddPosterLinkInput')} label={t('AddDialog.AddPosterLinkInput')}
type='url' type='url'
fullWidth fullWidth
/> />
@@ -165,11 +166,15 @@ export default function RightSideComponent({
</RightSideContainer> </RightSideContainer>
<RightSideContainer <RightSideContainer
isError={torrentSource && !isTorrentSourceCorrect} isError={torrentSource && (!isTorrentSourceCorrect || isHashAlreadyExists)}
notificationMessage={ notificationMessage={
!torrentSource ? t('AddTorrentSourceNotification') : !isTorrentSourceCorrect && t('WrongTorrentSource') !torrentSource
? t('AddDialog.AddTorrentSourceNotification')
: !isTorrentSourceCorrect
? t('AddDialog.WrongTorrentSource')
: isHashAlreadyExists && t('AddDialog.HashExists')
} }
isHidden={isTorrentSourceCorrect} isHidden={isEditMode || (isTorrentSourceCorrect && !isHashAlreadyExists)}
/> />
</RightSide> </RightSide>
) )

View File

@@ -30,6 +30,10 @@ export const Content = styled.div`
@media (max-width: 930px) { @media (max-width: 930px) {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
@media (max-width: 500px) {
align-content: start;
}
`} `}
` `
@@ -66,6 +70,10 @@ export const RightSideContainer = styled.div`
css` css`
display: none; display: none;
`}; `};
@media (max-width: 500px) {
height: 170px;
}
`} `}
` `
export const LeftSide = styled.div` export const LeftSide = styled.div`
@@ -105,6 +113,15 @@ export const LeftSideBottomSectionNoFile = styled.div`
place-items: center; place-items: center;
grid-template-rows: 40% 1fr; grid-template-rows: 40% 1fr;
} }
@media (max-width: 500px) {
height: 170px;
grid-template-rows: 1fr;
> div:first-of-type {
display: none;
}
}
` `
export const LeftSideBottomSectionFileSelected = styled.div` export const LeftSideBottomSectionFileSelected = styled.div`
@@ -114,6 +131,10 @@ export const LeftSideBottomSectionFileSelected = styled.div`
@media (max-width: 930px) { @media (max-width: 930px) {
height: 400px; height: 400px;
} }
@media (max-width: 500px) {
height: 170px;
}
` `
export const TorrentIconWrapper = styled.div` export const TorrentIconWrapper = styled.div`

View File

@@ -1,21 +1,11 @@
import { useState } from 'react' import { useState } from 'react'
import { Typography } from '@material-ui/core' import { Typography } from '@material-ui/core'
import { torrentsHost } from 'utils/Hosts'
import TorrentCard from 'components/TorrentCard' import TorrentCard from 'components/TorrentCard'
import axios from 'axios'
import CircularProgress from '@material-ui/core/CircularProgress' import CircularProgress from '@material-ui/core/CircularProgress'
import { TorrentListWrapper, CenteredGrid } from 'components/App/style' import { TorrentListWrapper, CenteredGrid } from 'components/App/style'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useQuery } from 'react-query' import { useQuery } from 'react-query'
import { getTorrents } from 'utils/Utils'
const getTorrents = async () => {
try {
const { data } = await axios.post(torrentsHost(), { action: 'list' })
return data
} catch (error) {
throw new Error(null)
}
}
export default function TorrentList() { export default function TorrentList() {
const { t } = useTranslation() const { t } = useTranslation()

View File

@@ -2,15 +2,24 @@
"About": "About", "About": "About",
"Actions": "Actions", "Actions": "Actions",
"Add": "Add", "Add": "Add",
"AddFromLink": "Add from Link", "AddDialog": {
"AddNewTorrent": "Add new torrent",
"AddPosterLinkInput": "Poster link", "AddPosterLinkInput": "Poster link",
"AddRetrackers": "Add retrackers",
"AddTorrentSourceNotification": "First add your torrent source", "AddTorrentSourceNotification": "First add your torrent source",
"AppendFile": { "AppendFile": {
"Or": "OR", "Or": "OR",
"ClickOrDrag": "CLICK / DRAG & DROP (.torrent)" "ClickOrDrag": "CLICK / DRAG & DROP (.torrent)"
}, },
"CustomTorrentTitle": "Custom title (optional)",
"HashExists": "This torrent is already in database",
"OriginalTorrentTitle": "Original torrent title",
"TitleBlank": "Title (blank for orig. torrent title)",
"TorrentSourceLink": "Torrent source link",
"TorrentSourceOptions": "magnet / hash / .torrent file link",
"WrongTorrentSource": "Wrong torrent source"
},
"AddFromLink": "Add from Link",
"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",
@@ -85,7 +94,6 @@
"Support": "Support", "Support": "Support",
"TCP": "TCP (Transmission Control Protocol)", "TCP": "TCP (Transmission Control Protocol)",
"ThanksToEveryone": "Thanks to everyone who tested and helped.", "ThanksToEveryone": "Thanks to everyone who tested and helped.",
"Title": "Title",
"TorrentAdded": "Added", "TorrentAdded": "Added",
"TorrentClosed": "Сlosed", "TorrentClosed": "Сlosed",
"TorrentContent": "Torrent Content", "TorrentContent": "Torrent Content",
@@ -95,8 +103,6 @@
"TorrentInDb": "In DB", "TorrentInDb": "In DB",
"TorrentPreload": "Preload", "TorrentPreload": "Preload",
"TorrentSize": "Torrent size", "TorrentSize": "Torrent size",
"TorrentSourceLink": "Torrent source link",
"TorrentSourceOptions": "magnet / hash / .torrent file link",
"TorrentsSavePath": "Torrents Save Path", "TorrentsSavePath": "Torrents Save Path",
"TorrentState": "Torrent State", "TorrentState": "Torrent State",
"TorrentStatus": "Torrent Status", "TorrentStatus": "Torrent Status",
@@ -110,6 +116,5 @@
"UseDisk": "Use Disk for Cache", "UseDisk": "Use Disk for Cache",
"UseDiskDesc": "Better use external media on flash-based devices", "UseDiskDesc": "Better use external media on flash-based devices",
"UTP": "μTP (Micro Transport Protocol)", "UTP": "μTP (Micro Transport Protocol)",
"Viewed": "Viewed", "Viewed": "Viewed"
"WrongTorrentSource": "Wrong torrent source"
} }

View File

@@ -2,15 +2,24 @@
"About": "О сервере", "About": "О сервере",
"Actions": "Действия", "Actions": "Действия",
"Add": "Добавить", "Add": "Добавить",
"AddFromLink": "Добавить", "AddDialog": {
"AddNewTorrent": "Добавить новый торрент",
"AddPosterLinkInput": "Ссылка на постер", "AddPosterLinkInput": "Ссылка на постер",
"AddRetrackers": "Добавлять",
"AddTorrentSourceNotification": "Сначала добавьте torrent-источник", "AddTorrentSourceNotification": "Сначала добавьте torrent-источник",
"AppendFile": { "AppendFile": {
"Or": "ИЛИ", "Or": "ИЛИ",
"ClickOrDrag": "НАЖМИТЕ / ПЕРЕТАЩИТЕ ФАЙЛ (.torrent)" "ClickOrDrag": "НАЖМИТЕ / ПЕРЕТАЩИТЕ ФАЙЛ (.torrent)"
}, },
"CustomTorrentTitle": "Cвое имя (не обязательно)",
"HashExists": "Этот торрент уже есть в базе данных",
"OriginalTorrentTitle": "Оригинальное имя торрента",
"TitleBlank": "Имя (пустое - ориг. имя торрента)",
"TorrentSourceLink": "Ссылка на источник торрента",
"TorrentSourceOptions": "magnet-ссылка / хеш / ссылка на .torrent файл",
"WrongTorrentSource": "Неправильный torrent-источник"
},
"AddFromLink": "Добавить",
"AddNewTorrent": "Добавить новый торрент",
"AddRetrackers": "Добавлять",
"Buffer": "Предзагрузка / Кеш", "Buffer": "Предзагрузка / Кеш",
"BufferNote": "Включите «Наполнять кеш перед началом воспроизведения» в настройках для показа заполнения кеша", "BufferNote": "Включите «Наполнять кеш перед началом воспроизведения» в настройках для показа заполнения кеша",
"Cache": "Кеш", "Cache": "Кеш",
@@ -85,7 +94,6 @@
"Support": "Поддержать", "Support": "Поддержать",
"TCP": "TCP (Transmission Control Protocol)", "TCP": "TCP (Transmission Control Protocol)",
"ThanksToEveryone": "Спасибо всем, кто тестировал и помогал!", "ThanksToEveryone": "Спасибо всем, кто тестировал и помогал!",
"Title": "Название",
"TorrentAdded": "Добавлен", "TorrentAdded": "Добавлен",
"TorrentClosed": "Закрыт", "TorrentClosed": "Закрыт",
"TorrentContent": "Содержимое торрента", "TorrentContent": "Содержимое торрента",
@@ -95,8 +103,6 @@
"TorrentInDb": "Торрент в БД", "TorrentInDb": "Торрент в БД",
"TorrentPreload": "Предзагрузка", "TorrentPreload": "Предзагрузка",
"TorrentSize": "Размер торрента", "TorrentSize": "Размер торрента",
"TorrentSourceLink": "Ссылка на источник торрента",
"TorrentSourceOptions": "magnet-ссылка / хеш / ссылка на .torrent файл",
"TorrentsSavePath": "Путь хранения кеша", "TorrentsSavePath": "Путь хранения кеша",
"TorrentState": "Данные торрента", "TorrentState": "Данные торрента",
"TorrentStatus": "Состояние торрента", "TorrentStatus": "Состояние торрента",
@@ -110,6 +116,5 @@
"UseDisk": "Использовать диск для кеша", "UseDisk": "Использовать диск для кеша",
"UseDiskDesc": "Рекомендуется использовать внешние носители на устройствах с flash-памятью", "UseDiskDesc": "Рекомендуется использовать внешние носители на устройствах с flash-памятью",
"UTP": "μTP (Micro Transport Protocol)", "UTP": "μTP (Micro Transport Protocol)",
"Viewed": "Просм.", "Viewed": "Просм."
"WrongTorrentSource": "Неправильный torrent-источник"
} }

View File

@@ -1,3 +1,7 @@
import axios from 'axios'
import { torrentsHost } from './Hosts'
export function humanizeSize(size) { export function humanizeSize(size) {
if (!size) return '' if (!size) return ''
const i = Math.floor(Math.log(size) / Math.log(1024)) const i = Math.floor(Math.log(size) / Math.log(1024))
@@ -41,3 +45,12 @@ export const removeRedundantCharacters = string => {
return hasThreeDotsAtTheEnd ? `${trimmedString}..` : trimmedString return hasThreeDotsAtTheEnd ? `${trimmedString}..` : trimmedString
} }
export const getTorrents = async () => {
try {
const { data } = await axios.post(torrentsHost(), { action: 'list' })
return data
} catch (error) {
throw new Error(null)
}
}