- {name && name !== title ? (
+ {title && name !== title ? (
<>
-
{shortenText(getTitle(name), 50)}
-
{shortenText(title, 160)}
+
{shortenText(getParsedTitle(), 55)}
+
{shortenText(ptt.parse(name).title, 110)}
>
) : (
-
{shortenText(getTitle(title), 50)}
+
{shortenText(getParsedTitle(), 55)}
)}
diff --git a/web/src/components/Settings.jsx b/web/src/components/Settings.jsx
index f54a944..3e5cb5c 100644
--- a/web/src/components/Settings.jsx
+++ b/web/src/components/Settings.jsx
@@ -40,8 +40,8 @@ export default function SettingsDialog() {
.catch(() => setShow(false))
}, [tsHost])
- const onInputHost = event => {
- const host = event.target.value
+ const onInputHost = ({ target: { value } }) => {
+ const host = value.replace(/\/$/gi, '')
setTorrServerHost(host)
setTSHost(host)
}
diff --git a/web/src/components/TorrentCard/index.jsx b/web/src/components/TorrentCard/index.jsx
index b9abfa6..dc88def 100644
--- a/web/src/components/TorrentCard/index.jsx
+++ b/web/src/components/TorrentCard/index.jsx
@@ -1,6 +1,11 @@
import 'fontsource-roboto'
-import { forwardRef, useState } from 'react'
-import { UnfoldMore as UnfoldMoreIcon, Close as CloseIcon, Delete as DeleteIcon } from '@material-ui/icons'
+import { forwardRef, memo, useState } from 'react'
+import {
+ UnfoldMore as UnfoldMoreIcon,
+ Edit as EditIcon,
+ Close as CloseIcon,
+ Delete as DeleteIcon,
+} from '@material-ui/icons'
import { getPeerString, humanizeSize, shortenText } from 'utils/Utils'
import { torrentsHost } from 'utils/Hosts'
import { NoImageIcon } from 'icons'
@@ -11,12 +16,13 @@ import { Button, DialogActions, DialogTitle, useMediaQuery, useTheme } from '@ma
import axios from 'axios'
import ptt from 'parse-torrent-title'
import { useTranslation } from 'react-i18next'
+import AddDialog from 'components/Add/AddDialog'
import { StyledButton, TorrentCard, TorrentCardButtons, TorrentCardDescription, TorrentCardPoster } from './style'
const Transition = forwardRef((props, ref) => )
-export default function Torrent({ torrent }) {
+const Torrent = ({ torrent }) => {
const { t } = useTranslation()
const [isDetailedInfoOpened, setIsDetailedInfoOpened] = useState(false)
const [isDeleteTorrentOpened, setIsDeleteTorrentOpened] = useState(false)
@@ -36,6 +42,10 @@ export default function Torrent({ torrent }) {
const parsedTitle = (title || name) && ptt.parse(title || name).title
+ const [isEditDialogOpen, setIsEditDialogOpen] = useState(false)
+ const handleClickOpenEditDialog = () => setIsEditDialogOpen(true)
+ const handleCloseEditDialog = () => setIsEditDialogOpen(false)
+
return (
<>
@@ -49,6 +59,11 @@ export default function Torrent({ torrent }) {
{t('Details')}
+
+
+ {t('Edit')}
+
+
dropTorrent(torrent)}>
{t('Drop')}
@@ -118,6 +133,12 @@ export default function Torrent({ torrent }) {
+
+ {isEditDialogOpen && (
+
+ )}
>
)
}
+
+export default memo(Torrent)
diff --git a/web/src/components/TorrentCard/style.js b/web/src/components/TorrentCard/style.js
index 7695aba..eb696bb 100644
--- a/web/src/components/TorrentCard/style.js
+++ b/web/src/components/TorrentCard/style.js
@@ -66,7 +66,11 @@ export const TorrentCardButtons = styled.div`
gap: 10px;
@media (max-width: 1260px), (max-height: 500px) {
- grid-template-columns: repeat(3, 1fr);
+ grid-template-columns: repeat(4, 1fr);
+ }
+
+ @media (max-width: 340px) {
+ gap: 5px;
}
`
export const TorrentCardDescription = styled.div`
@@ -165,10 +169,13 @@ export const StyledButton = styled.button`
text-transform: uppercase;
background: #268757;
color: #fff;
- font-size: 1rem;
+ font-size: 0.9rem;
font-family: 'Roboto', 'Helvetica', 'Arial', sans-serif;
letter-spacing: 0.009em;
- padding: 10px 20px;
+ padding: 0 12px;
+ svg {
+ width: 20px;
+ }
:hover {
background: #2a7e54;
@@ -179,28 +186,21 @@ export const StyledButton = styled.button`
}
@media (max-width: 1260px), (max-height: 500px) {
- padding: 5px 10px;
- font-size: 0.8rem;
-
- svg {
- width: 20px;
- }
- }
-
- @media (max-width: 770px) {
- font-size: 0.7rem;
-
- svg {
- width: 15px;
- }
- }
-
- @media (max-width: 420px) {
padding: 7px 10px;
justify-content: center;
+ font-size: 0.8rem;
svg {
display: none;
}
}
+
+ @media (max-width: 770px) {
+ font-size: 0.7rem;
+ }
+
+ @media (max-width: 420px) {
+ font-size: 0.6rem;
+ padding: 7px 5px;
+ }
`
diff --git a/web/src/components/TorrentList.jsx b/web/src/components/TorrentList.jsx
index e4119fd..0a4fc5f 100644
--- a/web/src/components/TorrentList.jsx
+++ b/web/src/components/TorrentList.jsx
@@ -1,4 +1,4 @@
-import { useEffect, useRef, useState } from 'react'
+import { useState } from 'react'
import { Typography } from '@material-ui/core'
import { torrentsHost } from 'utils/Hosts'
import TorrentCard from 'components/TorrentCard'
@@ -6,34 +6,26 @@ import axios from 'axios'
import CircularProgress from '@material-ui/core/CircularProgress'
import { TorrentListWrapper, CenteredGrid } from 'components/App/style'
import { useTranslation } from 'react-i18next'
+import { useQuery } from 'react-query'
+
+const getTorrents = async () => {
+ try {
+ const { data } = await axios.post(torrentsHost(), { action: 'list' })
+ return data
+ } catch (error) {
+ throw new Error(null)
+ }
+}
export default function TorrentList() {
const { t } = useTranslation()
- const [torrents, setTorrents] = useState([])
- const [isLoading, setIsLoading] = useState(true)
const [isOffline, setIsOffline] = useState(true)
- const timerID = useRef(-1)
-
- useEffect(() => {
- timerID.current = setInterval(() => {
- // getting torrent list
- axios
- .post(torrentsHost(), { action: 'list' })
- .then(({ data }) => {
- // updating torrent list
- setTorrents(data)
- setIsOffline(false)
- })
- .catch(() => {
- // resetting torrent list
- setTorrents([])
- setIsOffline(true)
- })
- .finally(() => setIsLoading(false))
- }, 1000)
-
- return () => clearInterval(timerID.current)
- }, [])
+ const { data: torrents, isLoading } = useQuery('torrents', getTorrents, {
+ retry: 1,
+ refetchInterval: 1000,
+ onError: () => setIsOffline(true),
+ onSuccess: () => setIsOffline(false),
+ })
if (isLoading || isOffline || !torrents.length) {
return (
diff --git a/web/src/index.jsx b/web/src/index.jsx
index 1e33667..d9e88e1 100644
--- a/web/src/index.jsx
+++ b/web/src/index.jsx
@@ -1,13 +1,19 @@
import { StrictMode } from 'react'
import ReactDOM from 'react-dom'
+import { QueryClientProvider, QueryClient } from 'react-query'
+
+import App from './components/App'
import 'i18n'
import './index.css'
-import App from './components/App'
+
+const queryClient = new QueryClient()
ReactDOM.render(
-
+
+
+
,
document.getElementById('root'),
)
diff --git a/web/src/locales/en/translation.json b/web/src/locales/en/translation.json
index 98a1532..6e0b6d3 100644
--- a/web/src/locales/en/translation.json
+++ b/web/src/locales/en/translation.json
@@ -4,6 +4,7 @@
"Add": "Add",
"AddFromLink": "Add from Link",
"AddNewTorrent": "Add new torrent",
+ "EditTorrent": "Edit torrent",
"AddRetrackers": "Add retrackers",
"Buffer": "Preload Buffer / Cache",
"BufferNote": "Enable “Preload Buffer” in settings to see cache loading progress",
@@ -110,5 +111,6 @@
"WrongTorrentSource": "Wrong torrent source",
"ScrollDown": "scroll down",
"Cache": "Cache",
- "Data": "Data"
+ "Data": "Data",
+ "Edit": "Edit"
}
\ No newline at end of file
diff --git a/web/src/locales/ru/translation.json b/web/src/locales/ru/translation.json
index 198d5a2..2fce006 100644
--- a/web/src/locales/ru/translation.json
+++ b/web/src/locales/ru/translation.json
@@ -4,6 +4,7 @@
"Add": "Добавить",
"AddFromLink": "Добавить",
"AddNewTorrent": "Добавить новый торрент",
+ "EditTorrent": "Изменить торрент",
"AddRetrackers": "Добавлять",
"Buffer": "Предзагрузка / Кеш",
"BufferNote": "Включите «Наполнять кеш перед началом воспроизведения» в настройках для показа заполнения кеша",
@@ -109,6 +110,7 @@
"AddTorrentSourceNotification": "Сначала добавьте торрент источник",
"WrongTorrentSource": "Неправильный torrent источник",
"ScrollDown": "прокрутить вниз",
- "Cache": "Кэш",
- "Data": "Данные"
+ "Cache": "Кеш",
+ "Data": "Данные",
+ "Edit": "Изменить"
}
\ No newline at end of file
diff --git a/web/yarn.lock b/web/yarn.lock
index bb34a6a..4e7b69f 100644
--- a/web/yarn.lock
+++ b/web/yarn.lock
@@ -1181,6 +1181,13 @@
dependencies:
regenerator-runtime "^0.13.4"
+"@babel/runtime@^7.12.5", "@babel/runtime@^7.6.2":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.5.tgz#665450911c6031af38f81db530f387ec04cd9a98"
+ integrity sha512-121rumjddw9c3NCQ55KGkyE1h/nzWhU/owjhw0l4mQrkzz4x9SGS1X8gFLraHwX7td3Yo4QTL+qj0NcIzN87BA==
+ dependencies:
+ regenerator-runtime "^0.13.4"
+
"@babel/template@^7.10.4", "@babel/template@^7.12.13", "@babel/template@^7.3.3":
version "7.12.13"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.13.tgz#530265be8a2589dbb37523844c5bcb55947fb327"
@@ -3245,6 +3252,11 @@ bfj@^7.0.2:
hoopy "^0.1.4"
tryer "^1.0.1"
+big-integer@^1.6.16:
+ version "1.6.48"
+ resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.48.tgz#8fd88bd1632cba4a1c8c3e3d7159f08bb95b4b9e"
+ integrity sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==
+
big.js@^5.2.2:
version "5.2.2"
resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
@@ -3356,6 +3368,20 @@ braces@^3.0.1, braces@~3.0.2:
dependencies:
fill-range "^7.0.1"
+broadcast-channel@^3.4.1:
+ version "3.7.0"
+ resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-3.7.0.tgz#2dfa5c7b4289547ac3f6705f9c00af8723889937"
+ integrity sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg==
+ dependencies:
+ "@babel/runtime" "^7.7.2"
+ detect-node "^2.1.0"
+ js-sha3 "0.8.0"
+ microseconds "0.2.0"
+ nano-time "1.0.0"
+ oblivious-set "1.0.0"
+ rimraf "3.0.2"
+ unload "2.2.0"
+
brorand@^1.0.1, brorand@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
@@ -4674,7 +4700,7 @@ detect-newline@^3.0.0:
resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651"
integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==
-detect-node@^2.0.4:
+detect-node@^2.0.4, detect-node@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1"
integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==
@@ -7668,6 +7694,11 @@ jest@26.6.0:
import-local "^3.0.2"
jest-cli "^26.6.0"
+js-sha3@0.8.0:
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840"
+ integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==
+
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@@ -8221,6 +8252,14 @@ map-visit@^1.0.0:
dependencies:
object-visit "^1.0.0"
+match-sorter@^6.0.2:
+ version "6.3.0"
+ resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-6.3.0.tgz#454a1b31ed218cddbce6231a0ecb5fdc549fed01"
+ integrity sha512-efYOf/wUpNb8FgNY+cOD2EIJI1S5I7YPKsw0LBp7wqPh5pmMS6i/wr3ZWwfwrAw1NvqTA2KUReVRWDX84lUcOQ==
+ dependencies:
+ "@babel/runtime" "^7.12.5"
+ remove-accents "0.4.2"
+
matchdep@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/matchdep/-/matchdep-2.0.0.tgz#c6f34834a0d8dbc3b37c27ee8bbcb27c7775582e"
@@ -8340,6 +8379,11 @@ micromatch@^4.0.2:
braces "^3.0.1"
picomatch "^2.2.3"
+microseconds@0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/microseconds/-/microseconds-0.2.0.tgz#233b25f50c62a65d861f978a4a4f8ec18797dc39"
+ integrity sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA==
+
miller-rabin@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d"
@@ -8539,6 +8583,13 @@ nan@^2.12.1:
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19"
integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==
+nano-time@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/nano-time/-/nano-time-1.0.0.tgz#b0554f69ad89e22d0907f7a12b0993a5d96137ef"
+ integrity sha1-sFVPaa2J4i0JB/ehKwmTpdlhN+8=
+ dependencies:
+ big-integer "^1.6.16"
+
nanoid@^3.1.23:
version "3.1.23"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.23.tgz#f744086ce7c2bc47ee0a8472574d5c78e4183a81"
@@ -8868,6 +8919,11 @@ object.values@^1.1.0, object.values@^1.1.3:
es-abstract "^1.18.0-next.2"
has "^1.0.3"
+oblivious-set@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/oblivious-set/-/oblivious-set-1.0.0.tgz#c8316f2c2fb6ff7b11b6158db3234c49f733c566"
+ integrity sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw==
+
obuf@^1.0.0, obuf@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e"
@@ -10439,6 +10495,15 @@ react-measure@^2.5.2:
prop-types "^15.6.2"
resize-observer-polyfill "^1.5.0"
+react-query@^3.17.0:
+ version "3.17.0"
+ resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.17.0.tgz#461c0a030044760cd874c7ea8aa9d55c2dceb15d"
+ integrity sha512-/qUNb6ESCz75Z/bR5p/ztp5ipRj8IQSiIpHK3AkCLTT4IqZsceAoD+9B+wbitA0LkxsR3snGrpgKUc9MMYQ/Ow==
+ dependencies:
+ "@babel/runtime" "^7.5.5"
+ broadcast-channel "^3.4.1"
+ match-sorter "^6.0.2"
+
react-reconciler@~0.26.2:
version "0.26.2"
resolved "https://registry.yarnpkg.com/react-reconciler/-/react-reconciler-0.26.2.tgz#bbad0e2d1309423f76cf3c3309ac6c96e05e9d91"
@@ -10739,6 +10804,11 @@ relateurl@^0.2.7:
resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=
+remove-accents@0.4.2:
+ version "0.4.2"
+ resolved "https://registry.yarnpkg.com/remove-accents/-/remove-accents-0.4.2.tgz#0a43d3aaae1e80db919e07ae254b285d9e1c7bb5"
+ integrity sha1-CkPTqq4egNuRngeuJUsoXZ4ce7U=
+
remove-bom-buffer@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz#c2bf1e377520d324f623892e33c10cac2c252b53"
@@ -10962,6 +11032,13 @@ rgba-regex@^1.0.0:
resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3"
integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=
+rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
+ integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
+ dependencies:
+ glob "^7.1.3"
+
rimraf@^2.5.4, rimraf@^2.6.3:
version "2.7.1"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
@@ -10969,13 +11046,6 @@ rimraf@^2.5.4, rimraf@^2.6.3:
dependencies:
glob "^7.1.3"
-rimraf@^3.0.0, rimraf@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
- integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
- dependencies:
- glob "^7.1.3"
-
ripemd160@^2.0.0, ripemd160@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c"
@@ -12455,6 +12525,14 @@ universalify@^2.0.0:
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
+unload@2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/unload/-/unload-2.2.0.tgz#ccc88fdcad345faa06a92039ec0f80b488880ef7"
+ integrity sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA==
+ dependencies:
+ "@babel/runtime" "^7.6.2"
+ detect-node "^2.0.4"
+
unpipe@1.0.0, unpipe@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"