added few sections

This commit is contained in:
Daniel Shleifman
2021-05-28 17:33:21 +03:00
parent 461fc9014b
commit 8de8139f87
5 changed files with 402 additions and 242 deletions

View File

@@ -0,0 +1,14 @@
import { StatisticsFieldWrapper, StatisticsFieldIcon, StatisticsFieldValue, StatisticsFieldTitle } from './style'
export default function StatisticsField({ icon: Icon, title, value, iconBg, valueBg }) {
return (
<StatisticsFieldWrapper>
<StatisticsFieldTitle>{title}</StatisticsFieldTitle>
<StatisticsFieldIcon bgColor={iconBg}>
<Icon />
</StatisticsFieldIcon>
<StatisticsFieldValue bgColor={valueBg}>{value}</StatisticsFieldValue>
</StatisticsFieldWrapper>
)
}

View File

@@ -1,5 +1,5 @@
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
import { cacheHost } from 'utils/Hosts' import { cacheHost, settingsHost } from 'utils/Hosts'
import axios from 'axios' import axios from 'axios'
export const useUpdateCache = hash => { export const useUpdateCache = hash => {
@@ -71,3 +71,12 @@ export const useCreateCacheMap = cache => {
return cacheMap return cacheMap
} }
export const useGetSettings = cache => {
const [settings, setSettings] = useState()
useEffect(() => {
axios.post(settingsHost(), { action: 'get' }).then(({ data }) => setSettings(data))
}, [cache])
return settings
}

View File

@@ -1,121 +1,34 @@
import styled, { css } from 'styled-components' import styled, { css } from 'styled-components'
import { NoImageIcon } from 'icons' import { NoImageIcon } from 'icons'
import { getPeerString, humanizeSize } from 'utils/Utils' import { getPeerString, humanizeSize } from 'utils/Utils'
import { viewedHost } from 'utils/Hosts' // import { viewedHost } from 'utils/Hosts'
import { CopyToClipboard } from 'react-copy-to-clipboard' import { CopyToClipboard } from 'react-copy-to-clipboard'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { Button } from '@material-ui/core' import { Button } from '@material-ui/core'
import { ArrowDownward, ArrowUpward, SwapVerticalCircle, ViewAgenda } from '@material-ui/icons'
import axios from 'axios'
import { torrentsHost } from 'utils/Hosts'
import { useUpdateCache, useCreateCacheMap } from './customHooks' import { useUpdateCache, useCreateCacheMap, useGetSettings } from './customHooks'
import DialogHeader from './DialogHeader' import DialogHeader from './DialogHeader'
import TorrentCache from './TorrentCache' import TorrentCache from './TorrentCache'
import {
const DialogContentGrid = styled.div` DetailedTorrentCacheViewWrapper,
display: grid; DialogContentGrid,
grid-template-rows: min-content min-content 80px min-content; TorrentMainSection,
` Poster,
const Poster = styled.div` TorrentData,
${({ poster }) => css` SectionTitle,
height: 400px; SectionSubName,
border-radius: 5px; StatisticsWrapper,
overflow: hidden; ButtonSection,
LoadingProgress,
${poster SectionHeader,
? css` CacheSection,
img { ButtonSectionButton,
border-radius: 5px; TorrentFilesSection,
height: 100%; } from './style'
} import StatisticsField from './StatisticsField'
`
: css`
width: 300px;
display: grid;
place-items: center;
background: #74c39c;
svg {
transform: scale(2.5) translateY(-3px);
}
`}
`}
`
const TorrentMainSection = styled.section`
padding: 40px;
display: grid;
grid-template-columns: min-content 1fr;
gap: 30px;
background: lightgray;
`
const TorrentData = styled.div`
> :not(:last-child) {
margin-bottom: 20px;
}
`
const CacheSection = styled.section`
padding: 40px;
display: flex;
flex-direction: column;
`
const ButtonSection = styled.section`
box-shadow: 0px 4px 4px -1px rgb(0 0 0 / 30%);
display: flex;
justify-content: space-evenly;
align-items: center;
text-transform: uppercase;
`
const ButtonSectionButton = styled.div`
background: lightblue;
height: 100%;
flex: 1;
display: grid;
place-items: center;
cursor: pointer;
font-size: 15px;
:not(:last-child) {
border-right: 1px solid blue;
}
:hover {
background: red;
}
.hash-group {
display: grid;
place-items: center;
}
.hash-text {
font-size: 10px;
color: #7c7b7c;
}
`
const TorrentFilesSection = styled.div``
const TorrentName = styled.div`
font-size: 50px;
font-weight: 200;
line-height: 1;
`
const TorrentSubName = styled.div`
color: #7c7b7c;
`
const SectionTitle = styled.div`
font-size: 35px;
font-weight: 200;
line-height: 1;
margin-bottom: 20px;
`
const DetailedTorrentCacheViewWrapper = styled.div`
padding-top: 50px;
`
const shortenText = (text, count) => text.slice(0, count) + (text.length > count ? '...' : '') const shortenText = (text, count) => text.slice(0, count) + (text.length > count ? '...' : '')
@@ -135,13 +48,22 @@ export default function DialogTorrentDetailsContent({ closeDialog, torrent }) {
const cache = useUpdateCache(hash) const cache = useUpdateCache(hash)
const cacheMap = useCreateCacheMap(cache) const cacheMap = useCreateCacheMap(cache)
const settings = useGetSettings(cache)
const dropTorrent = hash => {
axios.post(torrentsHost(), { action: 'drop', hash }).then(() => console.log('torrent dropped'))
}
const { Capacity, PiecesCount, PiecesLength, Filled } = cache
useEffect(() => { useEffect(() => {
const torrentLoaded = torrent.stat_string !== 'Torrent in db' && torrent.stat_string !== 'Torrent getting info' const cacheIsLoading = !Object.entries(cache).length
torrentLoaded && isLoading && setIsLoading(false)
}, [torrent, isLoading])
const { Capacity, PiecesCount, PiecesLength } = cache if (cacheIsLoading && !isLoading) setIsLoading(true)
if (!cacheIsLoading && isLoading) setIsLoading(false)
}, [cache, isLoading])
const bufferSize = settings?.PreloadBuffer ? Capacity : 33554432 // Default is 32mb if PreloadBuffer is false
return ( return (
<> <>
@@ -156,6 +78,9 @@ export default function DialogTorrentDetailsContent({ closeDialog, torrent }) {
'loading' 'loading'
) : isDetailedCacheView ? ( ) : isDetailedCacheView ? (
<DetailedTorrentCacheViewWrapper> <DetailedTorrentCacheViewWrapper>
<div>PiecesCount: {PiecesCount}</div>
<div>PiecesLength: {humanizeSize(PiecesLength)}</div>
<div>status: {statString}</div>
<TorrentCache cache={cache} cacheMap={cacheMap} /> <TorrentCache cache={cache} cacheMap={cacheMap} />
</DetailedTorrentCacheViewWrapper> </DetailedTorrentCacheViewWrapper>
) : ( ) : (
@@ -167,34 +92,62 @@ export default function DialogTorrentDetailsContent({ closeDialog, torrent }) {
<div> <div>
{name && name !== title ? ( {name && name !== title ? (
<> <>
<TorrentName>{shortenText(name, 50)}</TorrentName> <SectionTitle>{shortenText(name, 50)}</SectionTitle>
<TorrentSubName>{shortenText(title, 160)}</TorrentSubName> <SectionSubName>{shortenText(title, 160)}</SectionSubName>
</> </>
) : ( ) : (
<TorrentName>{shortenText(title, 50)}</TorrentName> <SectionTitle>{shortenText(title, 50)}</SectionTitle>
)} )}
</div> </div>
<div>peers: {getPeerString(torrent)}</div> <StatisticsWrapper>
<div>loaded: {getPreload(torrent)}</div> <StatisticsField
<div>download speed: {humanizeSize(downloadSpeed)}</div> title='Download speed'
<div>upload speed: {humanizeSize(uploadSpeed)}</div> value={humanizeSize(downloadSpeed) || '0 B'}
<div>status: {statString}</div> iconBg='#118f00'
<div>torrent size: {humanizeSize(torrentSize)}</div> valueBg='#13a300'
icon={ArrowDownward}
/>
<div>Capacity: {humanizeSize(Capacity)}</div> <StatisticsField
<div>PiecesCount: {PiecesCount}</div> title='Upload speed'
<div>PiecesLength: {humanizeSize(PiecesLength)}</div> value={humanizeSize(uploadSpeed) || '0 B'}
iconBg='#0146ad'
valueBg='#0058db'
icon={ArrowUpward}
/>
<StatisticsField
title='Peers'
value={getPeerString(torrent)}
iconBg='#0146ad'
valueBg='#0058db'
icon={SwapVerticalCircle}
/>
<StatisticsField
title='Torrent size'
value={humanizeSize(torrentSize)}
iconBg='#0146ad'
valueBg='#0058db'
icon={ViewAgenda}
/>
</StatisticsWrapper>
</TorrentData> </TorrentData>
</TorrentMainSection> </TorrentMainSection>
<CacheSection> <CacheSection>
<SectionTitle>Cache</SectionTitle> <SectionHeader>
<SectionTitle>Buffer</SectionTitle>
{!settings?.PreloadBuffer && (
<SectionSubName>Enable &quot;Preload Buffer&quot; in settings to change buffer size</SectionSubName>
)}
<LoadingProgress value={Filled} fullAmount={bufferSize} label={humanizeSize(bufferSize)} />
</SectionHeader>
<TorrentCache isMini cache={cache} cacheMap={cacheMap} /> <TorrentCache isMini cache={cache} cacheMap={cacheMap} />
<Button <Button
style={{ alignSelf: 'flex-end', marginTop: '30px' }} style={{ marginTop: '30px' }}
variant='contained' variant='contained'
color='primary' color='primary'
size='large' size='large'
@@ -216,131 +169,133 @@ export default function DialogTorrentDetailsContent({ closeDialog, torrent }) {
<ButtonSectionButton>remove views</ButtonSectionButton> <ButtonSectionButton>remove views</ButtonSectionButton>
<ButtonSectionButton>drop torrent</ButtonSectionButton> <ButtonSectionButton onClick={() => dropTorrent(hash)}>drop torrent</ButtonSectionButton>
<ButtonSectionButton>download playlist</ButtonSectionButton> <ButtonSectionButton>download playlist</ButtonSectionButton>
<ButtonSectionButton>download playlist after last view</ButtonSectionButton> <ButtonSectionButton>download playlist after last view</ButtonSectionButton>
</ButtonSection> </ButtonSection>
<TorrentFilesSection /> <TorrentFilesSection>
<SectionTitle>Torrent Content</SectionTitle>
</TorrentFilesSection>
</DialogContentGrid> </DialogContentGrid>
)} )}
</> </>
) )
} }
function getPreload(torrent) { // function getPreload(torrent) {
if (torrent.preloaded_bytes > 0 && torrent.preload_size > 0 && torrent.preloaded_bytes < torrent.preload_size) { // if (torrent.preloaded_bytes > 0 && torrent.preload_size > 0 && torrent.preloaded_bytes < torrent.preload_size) {
const progress = ((torrent.preloaded_bytes * 100) / torrent.preload_size).toFixed(2) // const progress = ((torrent.preloaded_bytes * 100) / torrent.preload_size).toFixed(2)
return `${humanizeSize(torrent.preloaded_bytes)} / ${humanizeSize(torrent.preload_size)} ${progress}%` // return `${humanizeSize(torrent.preloaded_bytes)} / ${humanizeSize(torrent.preload_size)} ${progress}%`
} // }
if (!torrent.preloaded_bytes) return humanizeSize(0) // if (!torrent.preloaded_bytes) return humanizeSize(0)
return humanizeSize(torrent.preloaded_bytes) // return humanizeSize(torrent.preloaded_bytes)
} // }
function remViews(hash) { // function remViews(hash) {
try { // try {
if (hash) // if (hash)
fetch(viewedHost(), { // fetch(viewedHost(), {
method: 'post', // method: 'post',
body: JSON.stringify({ action: 'rem', hash, file_index: -1 }), // body: JSON.stringify({ action: 'rem', hash, file_index: -1 }),
headers: { // headers: {
Accept: 'application/json, text/plain, */*', // Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/json', // 'Content-Type': 'application/json',
}, // },
}) // })
} catch (e) { // } catch (e) {
console.error(e) // console.error(e)
} // }
} // }
function getViewed(hash, callback) { // function getViewed(hash, callback) {
try { // try {
fetch(viewedHost(), { // fetch(viewedHost(), {
method: 'post', // method: 'post',
body: JSON.stringify({ action: 'list', hash }), // body: JSON.stringify({ action: 'list', hash }),
headers: { // headers: {
Accept: 'application/json, text/plain, */*', // Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/json', // 'Content-Type': 'application/json',
}, // },
}) // })
.then(res => res.json()) // .then(res => res.json())
.then(callback) // .then(callback)
} catch (e) { // } catch (e) {
console.error(e) // console.error(e)
} // }
} // }
function getPlayableFile(torrent) { // function getPlayableFile(torrent) {
if (!torrent || !torrent.file_stats) return null // if (!torrent || !torrent.file_stats) return null
return torrent.file_stats.filter(file => extPlayable.includes(getExt(file.path))) // return torrent.file_stats.filter(file => extPlayable.includes(getExt(file.path)))
} // }
function getExt(filename) { // function getExt(filename) {
const ext = filename.split('.').pop() // const ext = filename.split('.').pop()
if (ext === filename) return '' // if (ext === filename) return ''
return ext.toLowerCase() // return ext.toLowerCase()
} // }
const extPlayable = [ // const extPlayable = [
// video // // video
'3g2', // '3g2',
'3gp', // '3gp',
'aaf', // 'aaf',
'asf', // 'asf',
'avchd', // 'avchd',
'avi', // 'avi',
'drc', // 'drc',
'flv', // 'flv',
'iso', // 'iso',
'm2v', // 'm2v',
'm2ts', // 'm2ts',
'm4p', // 'm4p',
'm4v', // 'm4v',
'mkv', // 'mkv',
'mng', // 'mng',
'mov', // 'mov',
'mp2', // 'mp2',
'mp4', // 'mp4',
'mpe', // 'mpe',
'mpeg', // 'mpeg',
'mpg', // 'mpg',
'mpv', // 'mpv',
'mxf', // 'mxf',
'nsv', // 'nsv',
'ogg', // 'ogg',
'ogv', // 'ogv',
'ts', // 'ts',
'qt', // 'qt',
'rm', // 'rm',
'rmvb', // 'rmvb',
'roq', // 'roq',
'svi', // 'svi',
'vob', // 'vob',
'webm', // 'webm',
'wmv', // 'wmv',
'yuv', // 'yuv',
// audio // // audio
'aac', // 'aac',
'aiff', // 'aiff',
'ape', // 'ape',
'au', // 'au',
'flac', // 'flac',
'gsm', // 'gsm',
'it', // 'it',
'm3u', // 'm3u',
'm4a', // 'm4a',
'mid', // 'mid',
'mod', // 'mod',
'mp3', // 'mp3',
'mpa', // 'mpa',
'pls', // 'pls',
'ra', // 'ra',
's3m', // 's3m',
'sid', // 'sid',
'wav', // 'wav',
'wma', // 'wma',
'xm', // 'xm',
] // ]

View File

@@ -0,0 +1,185 @@
import styled, { css } from 'styled-components'
export const DialogContentGrid = styled.div`
display: grid;
grid-template-columns: 70% 1fr;
grid-template-rows: min-content 80px min-content;
grid-template-areas:
'main cache'
'buttons buttons'
'file-list file-list';
`
export const Poster = styled.div`
${({ poster }) => css`
height: 400px;
border-radius: 5px;
overflow: hidden;
${poster
? css`
img {
border-radius: 5px;
height: 100%;
}
`
: css`
width: 300px;
display: grid;
place-items: center;
background: #74c39c;
svg {
transform: scale(2.5) translateY(-3px);
}
`}
`}
`
export const TorrentMainSection = styled.section`
grid-area: main;
padding: 40px;
display: grid;
grid-template-columns: min-content 1fr;
gap: 30px;
background: linear-gradient(145deg, #e4f6ed, #b5dec9);
`
export const TorrentData = styled.div`
> :not(:last-child) {
margin-bottom: 20px;
}
`
export const CacheSection = styled.section`
grid-area: cache;
padding: 40px;
display: grid;
align-content: start;
grid-template-rows: min-content 1fr min-content;
`
export const ButtonSection = styled.section`
grid-area: buttons;
box-shadow: 0px 4px 4px -1px rgb(0 0 0 / 30%);
display: flex;
justify-content: space-evenly;
align-items: center;
text-transform: uppercase;
`
export const ButtonSectionButton = styled.div`
background: lightblue;
height: 100%;
flex: 1;
display: grid;
place-items: center;
cursor: pointer;
font-size: 15px;
:not(:last-child) {
border-right: 1px solid blue;
}
:hover {
background: red;
}
.hash-group {
display: grid;
place-items: center;
}
.hash-text {
font-size: 10px;
color: #7c7b7c;
}
`
export const TorrentFilesSection = styled.div`
grid-area: file-list;
padding: 40px;
`
export const SectionSubName = styled.div`
color: #7c7b7c;
`
export const SectionTitle = styled.div`
font-size: 35px;
font-weight: 200;
line-height: 1;
word-break: break-word;
`
export const SectionHeader = styled.div`
margin-bottom: 20px;
`
export const DetailedTorrentCacheViewWrapper = styled.div`
padding-top: 50px;
`
export const StatisticsWrapper = styled.div`
display: grid;
grid-template-columns: repeat(auto-fit, minmax(190px, min-content));
gap: 20px;
`
export const StatisticsFieldWrapper = styled.div`
display: grid;
grid-template-columns: 40px max-content;
grid-template-rows: min-content 50px;
grid-template-areas:
'title title'
'icon value';
> * {
display: grid;
place-items: center;
}
`
export const StatisticsFieldTitle = styled.div`
grid-area: title;
justify-self: start;
text-transform: uppercase;
font-size: 11px;
margin-bottom: 2px;
font-weight: 500;
`
export const StatisticsFieldIcon = styled.div`
${({ bgColor }) => css`
grid-area: icon;
color: rgba(255, 255, 255, 0.8);
background: ${bgColor};
border-radius: 5px 0 0 5px;
`}
`
export const StatisticsFieldValue = styled.div`
${({ bgColor }) => css`
grid-area: value;
min-width: 150px;
padding: 0 20px;
color: #fff;
font-size: 25px;
background: ${bgColor};
border-radius: 0 5px 5px 0;
`}
`
export const LoadingProgress = styled.div.attrs(({ value, fullAmount }) => ({
percentage: Math.min(100, (value * 100) / fullAmount),
}))`
${({ percentage, label }) => css`
border: 1px solid;
padding: 10px 20px;
border-radius: 5px;
background: linear-gradient(to right, #b5dec9 0%, #b5dec9 ${percentage}%, #fff ${percentage}%, #fff 100%);
:before {
content: '${label}';
display: grid;
place-items: center;
font-size: 20px;
}
`}
`

View File

@@ -26,7 +26,6 @@ export default function SettingsDialog() {
setOpen(false) setOpen(false)
const sets = JSON.parse(JSON.stringify(settings)) const sets = JSON.parse(JSON.stringify(settings))
sets.CacheSize *= 1024 * 1024 sets.CacheSize *= 1024 * 1024
sets.PreloadBufferSize *= 1024 * 1024
fetch(settingsHost(), { fetch(settingsHost(), {
method: 'post', method: 'post',
body: JSON.stringify({ action: 'set', sets }), body: JSON.stringify({ action: 'set', sets }),
@@ -51,8 +50,6 @@ export default function SettingsDialog() {
json => { json => {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
json.CacheSize /= 1024 * 1024 json.CacheSize /= 1024 * 1024
// eslint-disable-next-line no-param-reassign
json.PreloadBufferSize /= 1024 * 1024
setSets(json) setSets(json)
setShow(true) setShow(true)
}, },