diff --git a/web/.eslintcache b/web/.eslintcache
index a51a1d1..d47970e 100644
--- a/web/.eslintcache
+++ b/web/.eslintcache
@@ -1 +1 @@
-[{"/space/Projects/GO/TorrServer/web/src/index.js":"1","/space/Projects/GO/TorrServer/web/src/App.js":"2","/space/Projects/GO/TorrServer/web/src/components/Appbar/index.js":"3","/space/Projects/GO/TorrServer/web/src/components/Upload.js":"4","/space/Projects/GO/TorrServer/web/src/components/About.js":"5","/space/Projects/GO/TorrServer/web/src/components/TorrentList.js":"6","/space/Projects/GO/TorrServer/web/src/components/Settings.js":"7","/space/Projects/GO/TorrServer/web/src/components/Appbar/useStyles.js":"8","/space/Projects/GO/TorrServer/web/src/components/Donate.js":"9","/space/Projects/GO/TorrServer/web/src/components/RemoveAll.js":"10","/space/Projects/GO/TorrServer/web/src/utils/Hosts.js":"11","/space/Projects/GO/TorrServer/web/src/components/Add/index.js":"12","/space/Projects/GO/TorrServer/web/src/components/Torrent/index.js":"13","/space/Projects/GO/TorrServer/web/src/components/Add/AddDialog.js":"14","/space/Projects/GO/TorrServer/web/src/components/Torrent/style.js":"15","/space/Projects/GO/TorrServer/web/src/utils/Utils.js":"16","/space/Projects/GO/TorrServer/web/src/components/DialogTorrentInfo.js":"17","/space/Projects/GO/TorrServer/web/src/components/DialogCacheInfo.js":"18","/space/Projects/GO/TorrServer/web/src/icons/index.js":"19"},{"size":224,"mtime":1609258964582,"results":"20","hashOfConfig":"21"},{"size":753,"mtime":1621874529390,"results":"22","hashOfConfig":"21"},{"size":4788,"mtime":1621875508715,"results":"23","hashOfConfig":"21"},{"size":1348,"mtime":1609258964582,"results":"24","hashOfConfig":"21"},{"size":2278,"mtime":1609258964578,"results":"25","hashOfConfig":"21"},{"size":1618,"mtime":1621874529390,"results":"26","hashOfConfig":"21"},{"size":9039,"mtime":1621789228910,"results":"27","hashOfConfig":"21"},{"size":1728,"mtime":1621874529390,"results":"28","hashOfConfig":"21"},{"size":3831,"mtime":1621875426378,"results":"29","hashOfConfig":"21"},{"size":1325,"mtime":1621874529390,"results":"30","hashOfConfig":"21"},{"size":796,"mtime":1614406016579,"results":"31","hashOfConfig":"21"},{"size":880,"mtime":1621874529390,"results":"32","hashOfConfig":"21"},{"size":6309,"mtime":1621874529390,"results":"33","hashOfConfig":"21"},{"size":2440,"mtime":1621874529390,"results":"34","hashOfConfig":"21"},{"size":2139,"mtime":1621874529390,"results":"35","hashOfConfig":"21"},{"size":419,"mtime":1614194039304,"results":"36","hashOfConfig":"21"},{"size":7486,"mtime":1619026270555,"results":"37","hashOfConfig":"21"},{"size":4995,"mtime":1621875727408,"results":"38","hashOfConfig":"21"},{"size":2468,"mtime":1621874529390,"results":"39","hashOfConfig":"21"},{"filePath":"40","messages":"41","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"42"},"1gum1a2",{"filePath":"43","messages":"44","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"42"},{"filePath":"45","messages":"46","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"42"},{"filePath":"47","messages":"48","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"42"},{"filePath":"49","messages":"50","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"42"},{"filePath":"51","messages":"52","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"42"},{"filePath":"53","messages":"54","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"55","usedDeprecatedRules":"42"},{"filePath":"56","messages":"57","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"42"},{"filePath":"58","messages":"59","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"42"},{"filePath":"60","messages":"61","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"42"},{"filePath":"62","messages":"63","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"42"},{"filePath":"64","messages":"65","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"42"},{"filePath":"66","messages":"67","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"42"},{"filePath":"68","messages":"69","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"42"},{"filePath":"70","messages":"71","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"42"},{"filePath":"72","messages":"73","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"42"},{"filePath":"74","messages":"75","errorCount":0,"warningCount":5,"fixableErrorCount":0,"fixableWarningCount":0,"source":"76","usedDeprecatedRules":"42"},{"filePath":"77","messages":"78","errorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"79","messages":"80","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"42"},"/space/Projects/GO/TorrServer/web/src/index.js",[],["81","82"],"/space/Projects/GO/TorrServer/web/src/App.js",[],"/space/Projects/GO/TorrServer/web/src/components/Appbar/index.js",[],"/space/Projects/GO/TorrServer/web/src/components/Upload.js",[],"/space/Projects/GO/TorrServer/web/src/components/About.js",[],"/space/Projects/GO/TorrServer/web/src/components/TorrentList.js",[],"/space/Projects/GO/TorrServer/web/src/components/Settings.js",["83"],"import ListItem from '@material-ui/core/ListItem'\nimport ListItemIcon from '@material-ui/core/ListItemIcon'\nimport ListItemText from '@material-ui/core/ListItemText'\nimport React, { useEffect } from 'react'\nimport SettingsIcon from '@material-ui/icons/Settings'\nimport Dialog from '@material-ui/core/Dialog'\nimport DialogTitle from '@material-ui/core/DialogTitle'\nimport DialogContent from '@material-ui/core/DialogContent'\nimport TextField from '@material-ui/core/TextField'\nimport DialogActions from '@material-ui/core/DialogActions'\nimport Button from '@material-ui/core/Button'\nimport { FormControlLabel, InputLabel, Select, Switch } from '@material-ui/core'\nimport { settingsHost, setTorrServerHost, torrserverHost } from '../utils/Hosts'\n\nexport default function SettingsDialog() {\n const [open, setOpen] = React.useState(false)\n const [settings, setSets] = React.useState({})\n const [show, setShow] = React.useState(false)\n const [tsHost, setTSHost] = React.useState(torrserverHost ? torrserverHost : window.location.protocol + '//' + window.location.hostname + (window.location.port ? ':' + window.location.port : ''))\n\n const handleClickOpen = () => {\n setOpen(true)\n }\n const handleClose = () => {\n setOpen(false)\n }\n const handleCloseSave = () => {\n setOpen(false)\n let sets = JSON.parse(JSON.stringify(settings))\n sets.CacheSize *= 1024 * 1024\n sets.PreloadBufferSize *= 1024 * 1024\n fetch(settingsHost(), {\n method: 'post',\n body: JSON.stringify({ action: 'set', sets: sets }),\n headers: {\n Accept: 'application/json, text/plain, */*',\n 'Content-Type': 'application/json',\n },\n })\n }\n\n useEffect(() => {\n fetch(settingsHost(), {\n method: 'post',\n body: JSON.stringify({ action: 'get' }),\n headers: {\n Accept: 'application/json, text/plain, */*',\n 'Content-Type': 'application/json',\n },\n })\n .then((res) => res.json())\n .then(\n (json) => {\n json.CacheSize /= 1024 * 1024\n json.PreloadBufferSize /= 1024 * 1024\n setSets(json)\n setShow(true)\n },\n (error) => {\n setShow(false)\n console.log(error)\n }\n )\n .catch((e) => {\n setShow(false)\n console.log(e)\n })\n }, [tsHost])\n\n const onInputHost = (event) => {\n let host = event.target.value\n setTorrServerHost(host)\n setTSHost(host)\n }\n\n const inputForm = (event) => {\n let sets = JSON.parse(JSON.stringify(settings))\n if (event.target.type === 'number' || event.target.type === 'select-one') {\n sets[event.target.id] = Number(event.target.value)\n } else if (event.target.type === 'checkbox') {\n sets[event.target.id] = Boolean(event.target.checked)\n } else if (event.target.type === 'url') {\n sets[event.target.id] = event.target.value\n }\n setSets(sets)\n }\n\n return (\n
\n \n \n \n \n \n \n \n
\n )\n}\n\n","/space/Projects/GO/TorrServer/web/src/components/Appbar/useStyles.js",[],"/space/Projects/GO/TorrServer/web/src/components/Donate.js",[],"/space/Projects/GO/TorrServer/web/src/components/RemoveAll.js",[],"/space/Projects/GO/TorrServer/web/src/utils/Hosts.js",[],"/space/Projects/GO/TorrServer/web/src/components/Add/index.js",[],"/space/Projects/GO/TorrServer/web/src/components/Torrent/index.js",[],"/space/Projects/GO/TorrServer/web/src/components/Add/AddDialog.js",[],"/space/Projects/GO/TorrServer/web/src/components/Torrent/style.js",[],"/space/Projects/GO/TorrServer/web/src/utils/Utils.js",[],"/space/Projects/GO/TorrServer/web/src/components/DialogTorrentInfo.js",["84","85","86","87","88"],"import React, { useEffect } from 'react'\nimport Typography from '@material-ui/core/Typography'\nimport { Button, ButtonGroup, Grid, List, ListItem } from '@material-ui/core'\nimport CachedIcon from '@material-ui/icons/Cached'\nimport LinearProgress from '@material-ui/core/LinearProgress';\n\nimport { getPeerString, humanizeSize } from '../utils/Utils'\nimport { playlistTorrHost, streamHost, viewedHost } from '../utils/Hosts'\nimport DialogTitle from '@material-ui/core/DialogTitle'\nimport DialogContent from '@material-ui/core/DialogContent'\n\nconst style = {\n width100: {\n width: '100%',\n },\n width80: {\n width: '80%',\n },\n poster: {\n display: 'flex',\n flexDirection: 'row',\n borderRadius: '5px',\n },\n}\n\nexport default function DialogTorrentInfo(props) {\n const [torrent, setTorrent] = React.useState(props.torrent)\n const [viewed, setViewed] = React.useState(null)\n const [progress, setProgress] = React.useState(-1)\n\n useEffect(() => {\n setTorrent(props.torrent)\n if(torrent.stat==2)\n setProgress(torrent.preloaded_bytes * 100 / torrent.preload_size)\n getViewed(props.torrent.hash,(list) => {\n if (list) {\n let lst = list.map((itm) => itm.file_index)\n setViewed(lst)\n }else\n setViewed(null)\n })\n }, [props.torrent, props.open])\n\n return (\n \n
\n \n {torrent.poster &&
}\n \n {torrent.title} {torrent.name && torrent.name !== torrent.title && ' | ' + torrent.name}\n \n Peers: {getPeerString(torrent)}\n
\n Loaded: {getPreload(torrent)}\n
\n Speed: {humanizeSize(torrent.download_speed)}\n
\n Status: {torrent.stat_string}\n
\n \n \n \n {torrent.stat==2 && }\n \n
\n \n \n \n \n \n \n \n \n {getPlayableFile(torrent) &&\n getPlayableFile(torrent).map((file) => (\n \n \n \n \n ))}\n
\n \n
\n )\n}\n\nfunction remViews(hash){\n try {\n if (hash)\n fetch(viewedHost(), {\n method: 'post',\n body: JSON.stringify({ action: 'rem', hash: hash, file_index:-1 }),\n headers: {\n Accept: 'application/json, text/plain, */*',\n 'Content-Type': 'application/json',\n },\n })\n } catch (e) {\n console.error(e)\n }\n}\n\nfunction getViewed(hash, callback) {\n try {\n fetch(viewedHost(), {\n method: 'post',\n body: JSON.stringify({ action: 'list', hash: hash }),\n headers: {\n Accept: 'application/json, text/plain, */*',\n 'Content-Type': 'application/json',\n },\n })\n .then((res) => res.json())\n .then(\n (json) => {\n callback(json)\n },\n (error) => {\n callback(null)\n }\n )\n } catch (e) {\n console.error(e)\n }\n}\n\nfunction getPlayableFile(torrent){\n if (!torrent || !torrent.file_stats)\n return null\n return torrent.file_stats.filter(file => extPlayable.includes(getExt(file.path)))\n}\n\nfunction getExt(filename){\n const ext = filename.split('.').pop()\n if (ext == filename)\n return ''\n return ext.toLowerCase()\n}\n\nfunction getPreload(torrent) {\n if (torrent.preloaded_bytes > 0 && torrent.preload_size > 0 && torrent.preloaded_bytes < torrent.preload_size) {\n let progress = ((torrent.preloaded_bytes * 100) / torrent.preload_size).toFixed(2)\n return humanizeSize(torrent.preloaded_bytes) + ' / ' + humanizeSize(torrent.preload_size) + ' ' + progress + '%'\n }\n\n if (!torrent.preloaded_bytes) return humanizeSize(0)\n\n return humanizeSize(torrent.preloaded_bytes)\n}\n\nconst extPlayable = [\n// video\n \"3g2\",\n \"3gp\",\n \"aaf\",\n \"asf\",\n \"avchd\",\n \"avi\",\n \"drc\",\n \"flv\",\n \"iso\",\n \"m2v\",\n \"m2ts\",\n \"m4p\",\n \"m4v\",\n \"mkv\",\n \"mng\",\n \"mov\",\n \"mp2\",\n \"mp4\",\n \"mpe\",\n \"mpeg\",\n \"mpg\",\n \"mpv\",\n \"mxf\",\n \"nsv\",\n \"ogg\",\n \"ogv\",\n \"ts\",\n \"qt\",\n \"rm\",\n \"rmvb\",\n \"roq\",\n \"svi\",\n \"vob\",\n \"webm\",\n \"wmv\",\n \"yuv\",\n// audio\n \"aac\",\n \"aiff\",\n \"ape\",\n \"au\",\n \"flac\",\n \"gsm\",\n \"it\",\n \"m3u\",\n \"m4a\",\n \"mid\",\n \"mod\",\n \"mp3\",\n \"mpa\",\n \"pls\",\n \"ra\",\n \"s3m\",\n \"sid\",\n \"wav\",\n \"wma\",\n \"xm\"\n]\n","/space/Projects/GO/TorrServer/web/src/components/DialogCacheInfo.js",["89","90"],"/space/Projects/GO/TorrServer/web/src/icons/index.js",[],{"ruleId":"91","replacedBy":"92"},{"ruleId":"93","replacedBy":"94"},{"ruleId":"95","severity":1,"message":"96","line":105,"column":29,"nodeType":"97","endLine":105,"endColumn":35},{"ruleId":"98","severity":1,"message":"99","line":33,"column":24,"nodeType":"100","messageId":"101","endLine":33,"endColumn":26},{"ruleId":"102","severity":1,"message":"103","line":42,"column":8,"nodeType":"104","endLine":42,"endColumn":35,"suggestions":"105"},{"ruleId":"98","severity":1,"message":"99","line":63,"column":30,"nodeType":"100","messageId":"101","endLine":63,"endColumn":32},{"ruleId":"98","severity":1,"message":"106","line":91,"column":152,"nodeType":"100","messageId":"101","endLine":91,"endColumn":154},{"ruleId":"98","severity":1,"message":"99","line":154,"column":13,"nodeType":"100","messageId":"101","endLine":154,"endColumn":15},{"ruleId":"107","severity":1,"message":"108","line":44,"column":39,"nodeType":"109","messageId":"110","endLine":50,"endColumn":18},{"ruleId":"102","severity":1,"message":"111","line":60,"column":8,"nodeType":"104","endLine":60,"endColumn":22,"suggestions":"112"},"no-native-reassign",["113"],"no-negated-in-lhs",["114"],"jsx-a11y/heading-has-content","Headings must have content and the content must be accessible by a screen reader.","JSXOpeningElement","eqeqeq","Expected '===' and instead saw '=='.","BinaryExpression","unexpected","react-hooks/exhaustive-deps","React Hook useEffect has missing dependencies: 'torrent.preload_size', 'torrent.preloaded_bytes', and 'torrent.stat'. Either include them or remove the dependency array. You can also replace multiple useState variables with useReducer if 'setProgress' needs the current value of 'torrent.preloaded_bytes'.","ArrayExpression",["115"],"Expected '!==' and instead saw '!='.","no-loop-func","Function declared in a loop contains unsafe references to variable(s) 'cls', 'cls'.","ArrowFunctionExpression","unsafeRefs","React Hook useEffect has a missing dependency: 'cache'. Either include it or remove the dependency array.",["116"],"no-global-assign","no-unsafe-negation",{"desc":"117","fix":"118"},{"desc":"119","fix":"120"},"Update the dependencies array to be: [props.torrent, props.open, torrent.stat, torrent.preloaded_bytes, torrent.preload_size]",{"range":"121","text":"122"},"Update the dependencies array to be: [cache, cache.Pieces]",{"range":"123","text":"124"},[1372,1399],"[props.torrent, props.open, torrent.stat, torrent.preloaded_bytes, torrent.preload_size]",[2056,2070],"[cache, cache.Pieces]"]
\ No newline at end of file
+[{"/Users/daniel/Desktop/TorrServer/web/src/index.js":"1","/Users/daniel/Desktop/TorrServer/web/src/App.js":"2","/Users/daniel/Desktop/TorrServer/web/src/components/RemoveAll.js":"3","/Users/daniel/Desktop/TorrServer/web/src/components/TorrentList.js":"4","/Users/daniel/Desktop/TorrServer/web/src/components/Settings.js":"5","/Users/daniel/Desktop/TorrServer/web/src/components/About.js":"6","/Users/daniel/Desktop/TorrServer/web/src/components/Upload.js":"7","/Users/daniel/Desktop/TorrServer/web/src/utils/Hosts.js":"8","/Users/daniel/Desktop/TorrServer/web/src/utils/Utils.js":"9","/Users/daniel/Desktop/TorrServer/web/src/components/DialogTorrentInfo.js":"10","/Users/daniel/Desktop/TorrServer/web/src/components/DialogCacheInfo.js":"11","/Users/daniel/Desktop/TorrServer/web/src/components/Appbar/index.js":"12","/Users/daniel/Desktop/TorrServer/web/src/components/Add/index.js":"13","/Users/daniel/Desktop/TorrServer/web/src/components/Add/AddDialog.js":"14","/Users/daniel/Desktop/TorrServer/web/src/components/Torrent/index.js":"15","/Users/daniel/Desktop/TorrServer/web/src/components/Torrent/style.js":"16","/Users/daniel/Desktop/TorrServer/web/src/icons/index.js":"17","/Users/daniel/Desktop/TorrServer/web/src/components/Appbar/useStyles.js":"18","/Users/daniel/Desktop/TorrServer/web/src/components/Donate/index.js":"19","/Users/daniel/Desktop/TorrServer/web/src/components/Donate/DonateDialog.js":"20"},{"size":224,"mtime":1621760841794,"results":"21","hashOfConfig":"22"},{"size":753,"mtime":1621877374478,"results":"23","hashOfConfig":"22"},{"size":1325,"mtime":1621877374484,"results":"24","hashOfConfig":"22"},{"size":1618,"mtime":1621877374485,"results":"25","hashOfConfig":"22"},{"size":9039,"mtime":1621760841794,"results":"26","hashOfConfig":"22"},{"size":2278,"mtime":1621760841792,"results":"27","hashOfConfig":"22"},{"size":1348,"mtime":1621776545759,"results":"28","hashOfConfig":"22"},{"size":796,"mtime":1621885999076,"results":"29","hashOfConfig":"22"},{"size":419,"mtime":1621760841795,"results":"30","hashOfConfig":"22"},{"size":7486,"mtime":1621760841793,"results":"31","hashOfConfig":"22"},{"size":4995,"mtime":1621878159479,"results":"32","hashOfConfig":"22"},{"size":5537,"mtime":1621881892590,"results":"33","hashOfConfig":"22"},{"size":880,"mtime":1621877374481,"results":"34","hashOfConfig":"22"},{"size":2440,"mtime":1621877374480,"results":"35","hashOfConfig":"22"},{"size":6309,"mtime":1621877374485,"results":"36","hashOfConfig":"22"},{"size":2167,"mtime":1621885800440,"results":"37","hashOfConfig":"22"},{"size":2468,"mtime":1621877374486,"results":"38","hashOfConfig":"22"},{"size":1728,"mtime":1621885463938,"results":"39","hashOfConfig":"22"},{"size":1700,"mtime":1621881811820,"results":"40","hashOfConfig":"22"},{"size":1919,"mtime":1621880179325,"results":"41","hashOfConfig":"22"},{"filePath":"42","messages":"43","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},"x6sab4",{"filePath":"45","messages":"46","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"47","messages":"48","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"49","messages":"50","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"51","messages":"52","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"53","usedDeprecatedRules":"44"},{"filePath":"54","messages":"55","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"56","messages":"57","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"58","messages":"59","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"60","messages":"61","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"62","messages":"63","errorCount":0,"warningCount":5,"fixableErrorCount":0,"fixableWarningCount":0,"source":"64","usedDeprecatedRules":"44"},{"filePath":"65","messages":"66","errorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"67","usedDeprecatedRules":"44"},{"filePath":"68","messages":"69","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"70","messages":"71","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"72","messages":"73","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"74","messages":"75","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"76","messages":"77","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"78","messages":"79","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"80","messages":"81","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"82","messages":"83","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},{"filePath":"84","messages":"85","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"44"},"/Users/daniel/Desktop/TorrServer/web/src/index.js",[],["86","87"],"/Users/daniel/Desktop/TorrServer/web/src/App.js",[],"/Users/daniel/Desktop/TorrServer/web/src/components/RemoveAll.js",[],"/Users/daniel/Desktop/TorrServer/web/src/components/TorrentList.js",[],"/Users/daniel/Desktop/TorrServer/web/src/components/Settings.js",["88"],"import ListItem from '@material-ui/core/ListItem'\nimport ListItemIcon from '@material-ui/core/ListItemIcon'\nimport ListItemText from '@material-ui/core/ListItemText'\nimport React, { useEffect } from 'react'\nimport SettingsIcon from '@material-ui/icons/Settings'\nimport Dialog from '@material-ui/core/Dialog'\nimport DialogTitle from '@material-ui/core/DialogTitle'\nimport DialogContent from '@material-ui/core/DialogContent'\nimport TextField from '@material-ui/core/TextField'\nimport DialogActions from '@material-ui/core/DialogActions'\nimport Button from '@material-ui/core/Button'\nimport { FormControlLabel, InputLabel, Select, Switch } from '@material-ui/core'\nimport { settingsHost, setTorrServerHost, torrserverHost } from '../utils/Hosts'\n\nexport default function SettingsDialog() {\n const [open, setOpen] = React.useState(false)\n const [settings, setSets] = React.useState({})\n const [show, setShow] = React.useState(false)\n const [tsHost, setTSHost] = React.useState(torrserverHost ? torrserverHost : window.location.protocol + '//' + window.location.hostname + (window.location.port ? ':' + window.location.port : ''))\n\n const handleClickOpen = () => {\n setOpen(true)\n }\n const handleClose = () => {\n setOpen(false)\n }\n const handleCloseSave = () => {\n setOpen(false)\n let sets = JSON.parse(JSON.stringify(settings))\n sets.CacheSize *= 1024 * 1024\n sets.PreloadBufferSize *= 1024 * 1024\n fetch(settingsHost(), {\n method: 'post',\n body: JSON.stringify({ action: 'set', sets: sets }),\n headers: {\n Accept: 'application/json, text/plain, */*',\n 'Content-Type': 'application/json',\n },\n })\n }\n\n useEffect(() => {\n fetch(settingsHost(), {\n method: 'post',\n body: JSON.stringify({ action: 'get' }),\n headers: {\n Accept: 'application/json, text/plain, */*',\n 'Content-Type': 'application/json',\n },\n })\n .then((res) => res.json())\n .then(\n (json) => {\n json.CacheSize /= 1024 * 1024\n json.PreloadBufferSize /= 1024 * 1024\n setSets(json)\n setShow(true)\n },\n (error) => {\n setShow(false)\n console.log(error)\n }\n )\n .catch((e) => {\n setShow(false)\n console.log(e)\n })\n }, [tsHost])\n\n const onInputHost = (event) => {\n let host = event.target.value\n setTorrServerHost(host)\n setTSHost(host)\n }\n\n const inputForm = (event) => {\n let sets = JSON.parse(JSON.stringify(settings))\n if (event.target.type === 'number' || event.target.type === 'select-one') {\n sets[event.target.id] = Number(event.target.value)\n } else if (event.target.type === 'checkbox') {\n sets[event.target.id] = Boolean(event.target.checked)\n } else if (event.target.type === 'url') {\n sets[event.target.id] = event.target.value\n }\n setSets(sets)\n }\n\n return (\n \n \n \n \n \n \n \n \n
\n )\n}\n\n","/Users/daniel/Desktop/TorrServer/web/src/components/About.js",[],"/Users/daniel/Desktop/TorrServer/web/src/components/Upload.js",[],"/Users/daniel/Desktop/TorrServer/web/src/utils/Hosts.js",[],"/Users/daniel/Desktop/TorrServer/web/src/utils/Utils.js",[],"/Users/daniel/Desktop/TorrServer/web/src/components/DialogTorrentInfo.js",["89","90","91","92","93"],"import React, { useEffect } from 'react'\nimport Typography from '@material-ui/core/Typography'\nimport { Button, ButtonGroup, Grid, List, ListItem } from '@material-ui/core'\nimport CachedIcon from '@material-ui/icons/Cached'\nimport LinearProgress from '@material-ui/core/LinearProgress';\n\nimport { getPeerString, humanizeSize } from '../utils/Utils'\nimport { playlistTorrHost, streamHost, viewedHost } from '../utils/Hosts'\nimport DialogTitle from '@material-ui/core/DialogTitle'\nimport DialogContent from '@material-ui/core/DialogContent'\n\nconst style = {\n width100: {\n width: '100%',\n },\n width80: {\n width: '80%',\n },\n poster: {\n display: 'flex',\n flexDirection: 'row',\n borderRadius: '5px',\n },\n}\n\nexport default function DialogTorrentInfo(props) {\n const [torrent, setTorrent] = React.useState(props.torrent)\n const [viewed, setViewed] = React.useState(null)\n const [progress, setProgress] = React.useState(-1)\n\n useEffect(() => {\n setTorrent(props.torrent)\n if(torrent.stat==2)\n setProgress(torrent.preloaded_bytes * 100 / torrent.preload_size)\n getViewed(props.torrent.hash,(list) => {\n if (list) {\n let lst = list.map((itm) => itm.file_index)\n setViewed(lst)\n }else\n setViewed(null)\n })\n }, [props.torrent, props.open])\n\n return (\n \n
\n \n {torrent.poster &&
}\n \n {torrent.title} {torrent.name && torrent.name !== torrent.title && ' | ' + torrent.name}\n \n Peers: {getPeerString(torrent)}\n
\n Loaded: {getPreload(torrent)}\n
\n Speed: {humanizeSize(torrent.download_speed)}\n
\n Status: {torrent.stat_string}\n
\n \n \n \n {torrent.stat==2 && }\n \n
\n \n \n \n \n \n \n \n \n {getPlayableFile(torrent) &&\n getPlayableFile(torrent).map((file) => (\n \n \n \n \n ))}\n
\n \n
\n )\n}\n\nfunction remViews(hash){\n try {\n if (hash)\n fetch(viewedHost(), {\n method: 'post',\n body: JSON.stringify({ action: 'rem', hash: hash, file_index:-1 }),\n headers: {\n Accept: 'application/json, text/plain, */*',\n 'Content-Type': 'application/json',\n },\n })\n } catch (e) {\n console.error(e)\n }\n}\n\nfunction getViewed(hash, callback) {\n try {\n fetch(viewedHost(), {\n method: 'post',\n body: JSON.stringify({ action: 'list', hash: hash }),\n headers: {\n Accept: 'application/json, text/plain, */*',\n 'Content-Type': 'application/json',\n },\n })\n .then((res) => res.json())\n .then(\n (json) => {\n callback(json)\n },\n (error) => {\n callback(null)\n }\n )\n } catch (e) {\n console.error(e)\n }\n}\n\nfunction getPlayableFile(torrent){\n if (!torrent || !torrent.file_stats)\n return null\n return torrent.file_stats.filter(file => extPlayable.includes(getExt(file.path)))\n}\n\nfunction getExt(filename){\n const ext = filename.split('.').pop()\n if (ext == filename)\n return ''\n return ext.toLowerCase()\n}\n\nfunction getPreload(torrent) {\n if (torrent.preloaded_bytes > 0 && torrent.preload_size > 0 && torrent.preloaded_bytes < torrent.preload_size) {\n let progress = ((torrent.preloaded_bytes * 100) / torrent.preload_size).toFixed(2)\n return humanizeSize(torrent.preloaded_bytes) + ' / ' + humanizeSize(torrent.preload_size) + ' ' + progress + '%'\n }\n\n if (!torrent.preloaded_bytes) return humanizeSize(0)\n\n return humanizeSize(torrent.preloaded_bytes)\n}\n\nconst extPlayable = [\n// video\n \"3g2\",\n \"3gp\",\n \"aaf\",\n \"asf\",\n \"avchd\",\n \"avi\",\n \"drc\",\n \"flv\",\n \"iso\",\n \"m2v\",\n \"m2ts\",\n \"m4p\",\n \"m4v\",\n \"mkv\",\n \"mng\",\n \"mov\",\n \"mp2\",\n \"mp4\",\n \"mpe\",\n \"mpeg\",\n \"mpg\",\n \"mpv\",\n \"mxf\",\n \"nsv\",\n \"ogg\",\n \"ogv\",\n \"ts\",\n \"qt\",\n \"rm\",\n \"rmvb\",\n \"roq\",\n \"svi\",\n \"vob\",\n \"webm\",\n \"wmv\",\n \"yuv\",\n// audio\n \"aac\",\n \"aiff\",\n \"ape\",\n \"au\",\n \"flac\",\n \"gsm\",\n \"it\",\n \"m3u\",\n \"m4a\",\n \"mid\",\n \"mod\",\n \"mp3\",\n \"mpa\",\n \"pls\",\n \"ra\",\n \"s3m\",\n \"sid\",\n \"wav\",\n \"wma\",\n \"xm\"\n]\n","/Users/daniel/Desktop/TorrServer/web/src/components/DialogCacheInfo.js",["94","95"],"import React, { useEffect, useRef } from 'react'\nimport Typography from '@material-ui/core/Typography'\n\nimport { getPeerString, humanizeSize } from '../utils/Utils'\nimport DialogTitle from '@material-ui/core/DialogTitle'\nimport DialogContent from '@material-ui/core/DialogContent'\nimport { cacheHost } from '../utils/Hosts'\n\nexport default function DialogCacheInfo(props) {\n const [hash] = React.useState(props.hash)\n const [cache, setCache] = React.useState({})\n const timerID = useRef(-1)\n const [pMap, setPMap] = React.useState([])\n\n useEffect(() => {\n if (hash)\n timerID.current = setInterval(() => {\n getCache(hash, (cache) => {\n setCache(cache)\n })\n }, 100)\n else clearInterval(timerID.current)\n\n return () => {\n clearInterval(timerID.current)\n }\n }, [hash, props.open])\n\n useEffect(() => {\n if (cache && cache.PiecesCount && cache.Pieces) {\n var map = [];\n for (let i = 0; i < cache.PiecesCount; i++) {\n var reader = 0\n var cls = \"piece\"\n var prc = 0\n if (cache.Pieces[i]) {\n if (cache.Pieces[i].Completed && cache.Pieces[i].Size >= cache.Pieces[i].Length)\n cls += \" piece-complete\"\n else\n cls += \" piece-loading\"\n prc = (cache.Pieces[i].Size / cache.Pieces[i].Length * 100).toFixed(2)\n }\n\n cache.Readers.forEach(r => {\n if (i >= r.Start && i <= r.End && i !== r.Reader)\n cls += \" reader-range\"\n if (i === r.Reader) {\n cls += \" piece-reader\"\n }\n })\n map.push({\n prc: prc,\n class: cls,\n info: i,\n reader: reader,\n })\n }\n setPMap(map)\n }\n }, [cache.Pieces])\n\n return (\n \n
\n \n Hash {cache.Hash}\n
\n Capacity {humanizeSize(cache.Capacity)}\n
\n Filled {humanizeSize(cache.Filled)}\n
\n Torrent size {cache.Torrent && cache.Torrent.torrent_size && humanizeSize(cache.Torrent.torrent_size)}\n
\n Pieces length {humanizeSize(cache.PiecesLength)}\n
\n Pieces count {cache.PiecesCount}\n
\n Peers: {getPeerString(cache.Torrent)}\n
\n Download speed {cache.Torrent && cache.Torrent.download_speed ? humanizeSize(cache.Torrent.download_speed) + '/sec' : ''}\n
\n Upload speed {cache.Torrent && cache.Torrent.upload_speed ? humanizeSize(cache.Torrent.upload_speed) + '/sec' : ''}\n
\n Status {cache.Torrent && cache.Torrent.stat_string && cache.Torrent.stat_string}\n \n \n \n
\n \n {pMap.map(itm => (\n
\n {itm.prc > 0 && itm.prc < 100 && (\n \n )}\n \n ))}\n
\n \n
\n )\n}\n\nfunction getCache(hash, callback) {\n try {\n fetch(cacheHost(), {\n method: 'post',\n body: JSON.stringify({ action: 'get', hash: hash }),\n headers: {\n Accept: 'application/json, text/plain, */*',\n 'Content-Type': 'application/json',\n },\n })\n .then((res) => res.json())\n .then(\n (json) => {\n callback(json)\n },\n (error) => {\n callback({})\n console.error(error)\n }\n )\n } catch (e) {\n console.error(e)\n callback({})\n }\n}\n/*\n{\n \"Hash\": \"41e36c8de915d80db83fc134bee4e7e2d292657e\",\n \"Capacity\": 209715200,\n \"Filled\": 2914808,\n \"PiecesLength\": 4194304,\n \"PiecesCount\": 2065,\n \"DownloadSpeed\": 32770.860273455524,\n \"Pieces\": {\n \"2064\": {\n \"Id\": 2064,\n \"Length\": 2914808,\n \"Size\": 162296,\n \"Completed\": false\n }\n }\n}\n */\n","/Users/daniel/Desktop/TorrServer/web/src/components/Appbar/index.js",[],"/Users/daniel/Desktop/TorrServer/web/src/components/Add/index.js",[],"/Users/daniel/Desktop/TorrServer/web/src/components/Add/AddDialog.js",[],"/Users/daniel/Desktop/TorrServer/web/src/components/Torrent/index.js",[],"/Users/daniel/Desktop/TorrServer/web/src/components/Torrent/style.js",[],"/Users/daniel/Desktop/TorrServer/web/src/icons/index.js",[],"/Users/daniel/Desktop/TorrServer/web/src/components/Appbar/useStyles.js",[],"/Users/daniel/Desktop/TorrServer/web/src/components/Donate/index.js",[],"/Users/daniel/Desktop/TorrServer/web/src/components/Donate/DonateDialog.js",[],{"ruleId":"96","replacedBy":"97"},{"ruleId":"98","replacedBy":"99"},{"ruleId":"100","severity":1,"message":"101","line":105,"column":29,"nodeType":"102","endLine":105,"endColumn":35},{"ruleId":"103","severity":1,"message":"104","line":33,"column":24,"nodeType":"105","messageId":"106","endLine":33,"endColumn":26},{"ruleId":"107","severity":1,"message":"108","line":42,"column":8,"nodeType":"109","endLine":42,"endColumn":35,"suggestions":"110"},{"ruleId":"103","severity":1,"message":"104","line":63,"column":30,"nodeType":"105","messageId":"106","endLine":63,"endColumn":32},{"ruleId":"103","severity":1,"message":"111","line":91,"column":152,"nodeType":"105","messageId":"106","endLine":91,"endColumn":154},{"ruleId":"103","severity":1,"message":"104","line":154,"column":13,"nodeType":"105","messageId":"106","endLine":154,"endColumn":15},{"ruleId":"112","severity":1,"message":"113","line":83,"column":39,"nodeType":"114","messageId":"115","endLine":89,"endColumn":18},{"ruleId":"107","severity":1,"message":"116","line":99,"column":8,"nodeType":"109","endLine":99,"endColumn":22,"suggestions":"117"},"no-native-reassign",["118"],"no-negated-in-lhs",["119"],"jsx-a11y/heading-has-content","Headings must have content and the content must be accessible by a screen reader.","JSXOpeningElement","eqeqeq","Expected '===' and instead saw '=='.","BinaryExpression","unexpected","react-hooks/exhaustive-deps","React Hook useEffect has missing dependencies: 'torrent.preload_size', 'torrent.preloaded_bytes', and 'torrent.stat'. Either include them or remove the dependency array. You can also replace multiple useState variables with useReducer if 'setProgress' needs the current value of 'torrent.preloaded_bytes'.","ArrayExpression",["120"],"Expected '!==' and instead saw '!='.","no-loop-func","Function declared in a loop contains unsafe references to variable(s) 'cls', 'cls'.","ArrowFunctionExpression","unsafeRefs","React Hook useEffect has a missing dependency: 'cache'. Either include it or remove the dependency array.",["121"],"no-global-assign","no-unsafe-negation",{"desc":"122","fix":"123"},{"desc":"124","fix":"125"},"Update the dependencies array to be: [props.torrent, props.open, torrent.stat, torrent.preloaded_bytes, torrent.preload_size]",{"range":"126","text":"127"},"Update the dependencies array to be: [cache, cache.Pieces]",{"range":"128","text":"129"},[1372,1399],"[props.torrent, props.open, torrent.stat, torrent.preloaded_bytes, torrent.preload_size]",[3003,3017],"[cache, cache.Pieces]"]
\ No newline at end of file
diff --git a/web/src/components/Appbar/index.js b/web/src/components/Appbar/index.js
index a1da5e3..d4bd34b 100644
--- a/web/src/components/Appbar/index.js
+++ b/web/src/components/Appbar/index.js
@@ -14,6 +14,7 @@ import ChevronRightIcon from '@material-ui/icons/ChevronRight'
import ListItem from '@material-ui/core/ListItem'
import ListItemIcon from '@material-ui/core/ListItemIcon'
import ListItemText from '@material-ui/core/ListItemText'
+import CreditCardIcon from '@material-ui/icons/CreditCard'
import ListIcon from '@material-ui/icons/List'
import PowerSettingsNewIcon from '@material-ui/icons/PowerSettingsNew'
@@ -25,22 +26,24 @@ import RemoveAll from '../RemoveAll'
import SettingsDialog from '../Settings'
import AboutDialog from '../About'
import { playlistAllHost, shutdownHost, torrserverHost } from '../../utils/Hosts'
-import DonateDialog from '../Donate'
+import DonateSnackbar from '../Donate'
+import DonateDialog from '../Donate/DonateDialog'
import UploadDialog from '../Upload'
import useStyles from './useStyles'
export default function MiniDrawer() {
const classes = useStyles()
const theme = useTheme()
- const [open, setOpen] = useState(false)
+ const [isDrawerOpen, setIsDrawerOpen] = useState(false)
+ const [isDonationDialogOpen, setIsDonationDialogOpen] = useState(false)
const [tsVersion, setTSVersion] = useState('')
const handleDrawerOpen = () => {
- setOpen(true)
+ setIsDrawerOpen(true)
}
const handleDrawerClose = () => {
- setOpen(false)
+ setIsDrawerOpen(false)
}
useEffect(() => {
@@ -49,14 +52,14 @@ export default function MiniDrawer() {
.then((txt) => {
if (!txt.startsWith('')) setTSVersion(txt)
})
- }, [open])
+ }, [isDrawerOpen])
return (
@@ -66,7 +69,7 @@ export default function MiniDrawer() {
onClick={handleDrawerOpen}
edge="start"
className={clsx(classes.menuButton, {
- [classes.hide]: open,
+ [classes.hide]: isDrawerOpen,
})}
>
@@ -80,13 +83,13 @@ export default function MiniDrawer() {
@@ -95,7 +98,7 @@ export default function MiniDrawer() {
{theme.direction === 'rtl' ? : }
-
+
@@ -114,7 +117,6 @@ export default function MiniDrawer() {
-
fetch(shutdownHost())}>
@@ -123,15 +125,27 @@ export default function MiniDrawer() {
+
+
+
+
+ setIsDonationDialogOpen(true)}>
+
+
+
+
+
+
-
+
-
+
-
+ {isDonationDialogOpen && setIsDonationDialogOpen(false)} />}
+ {!JSON.parse(localStorage.getItem('snackbarIsClosed')) && }
)
}
diff --git a/web/src/components/Appbar/useStyles.js b/web/src/components/Appbar/useStyles.js
index d0cdb59..7c71d42 100644
--- a/web/src/components/Appbar/useStyles.js
+++ b/web/src/components/Appbar/useStyles.js
@@ -29,7 +29,7 @@ export default makeStyles((theme) => ({
},
drawer: {
width: drawerWidth,
- flexShrink: 0,
+ flexShrink: 1,
whiteSpace: 'nowrap',
},
drawerOpen: {
diff --git a/web/src/components/Donate.js b/web/src/components/Donate.js
deleted file mode 100644
index 17d8ec9..0000000
--- a/web/src/components/Donate.js
+++ /dev/null
@@ -1,86 +0,0 @@
-import React from 'react'
-import ListItem from '@material-ui/core/ListItem'
-import ListItemIcon from '@material-ui/core/ListItemIcon'
-import ListItemText from '@material-ui/core/ListItemText'
-import Dialog from '@material-ui/core/Dialog'
-import DialogTitle from '@material-ui/core/DialogTitle'
-import DialogContent from '@material-ui/core/DialogContent'
-import DialogActions from '@material-ui/core/DialogActions'
-import Button from '@material-ui/core/Button'
-import Snackbar from '@material-ui/core/Snackbar'
-import IconButton from '@material-ui/core/IconButton'
-import CreditCardIcon from '@material-ui/icons/CreditCard'
-import List from '@material-ui/core/List'
-import ButtonGroup from '@material-ui/core/ButtonGroup'
-
-const donateFrame =
- ''
-
-export default function DonateDialog() {
- const [open, setOpen] = React.useState(false)
- const [snakeOpen, setSnakeOpen] = React.useState(true)
-
- // NOT USED FOR NOW
- const handleClickOpen = () => {
- setOpen(true)
- }
- const handleClose = () => {
- setOpen(false)
- }
-
- return (
-
- {/* !!!!!!!!!!! Should be removed or moved to sidebar because it is not visible. It is hiddent behind header */}
-
-
-
-
-
-
- {/* !!!!!!!!!!!!!!!!!!!! */}
-
-
-
-
{ setSnakeOpen(false) }}
- autoHideDuration={6000}
- message="Donate?"
- action={
-
- {
- setSnakeOpen(false)
- setOpen(true)
- }}>
-
-
-
- }
- />
-
- )
-}
diff --git a/web/src/components/Donate/DonateDialog.js b/web/src/components/Donate/DonateDialog.js
new file mode 100644
index 0000000..ab5c112
--- /dev/null
+++ b/web/src/components/Donate/DonateDialog.js
@@ -0,0 +1,38 @@
+import ListItem from '@material-ui/core/ListItem'
+import Dialog from '@material-ui/core/Dialog'
+import DialogTitle from '@material-ui/core/DialogTitle'
+import DialogContent from '@material-ui/core/DialogContent'
+import DialogActions from '@material-ui/core/DialogActions'
+import List from '@material-ui/core/List'
+import ButtonGroup from '@material-ui/core/ButtonGroup'
+import Button from '@material-ui/core/Button'
+
+const donateFrame =
+ ''
+
+export default function DonateDialog ({ onClose }) {
+ return (
+
+ )
+}
\ No newline at end of file
diff --git a/web/src/components/Donate/index.js b/web/src/components/Donate/index.js
new file mode 100644
index 0000000..8a91e84
--- /dev/null
+++ b/web/src/components/Donate/index.js
@@ -0,0 +1,48 @@
+import { useState } from 'react'
+import Button from '@material-ui/core/Button'
+import Snackbar from '@material-ui/core/Snackbar'
+import IconButton from '@material-ui/core/IconButton'
+import CreditCardIcon from '@material-ui/icons/CreditCard'
+import CloseIcon from '@material-ui/icons/Close'
+import DonateDialog from './DonateDialog'
+
+export default function DonateSnackbar() {
+ const [open, setOpen] = useState(false)
+ const [snackbarOpen, setSnackbarOpen] = useState(true)
+
+ const disableSnackbar = () => {
+ setSnackbarOpen(false)
+ localStorage.setItem('snackbarIsClosed', true)
+ }
+
+ return (
+ <>
+ {open && setOpen(false)} />}
+
+
+
+
+
+
+
+ >
+ }
+ />
+ >
+ )
+}
diff --git a/web/src/components/Torrent/style.js b/web/src/components/Torrent/style.js
index 68874f4..f7cd3b3 100644
--- a/web/src/components/Torrent/style.js
+++ b/web/src/components/Torrent/style.js
@@ -50,6 +50,7 @@ export const TorrentCardDescription = styled.div`
background: #74c39c;
border-radius: 5px;
padding: 5px;
+ word-break: break-word;
`
export const TorrentCardDescriptionLabel = styled.div`