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 { cacheHost } from 'utils/Hosts'
import { cacheHost, settingsHost } from 'utils/Hosts'
import axios from 'axios'
export const useUpdateCache = hash => {
@@ -71,3 +71,12 @@ export const useCreateCacheMap = cache => {
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 { NoImageIcon } from 'icons'
import { getPeerString, humanizeSize } from 'utils/Utils'
import { viewedHost } from 'utils/Hosts'
// import { viewedHost } from 'utils/Hosts'
import { CopyToClipboard } from 'react-copy-to-clipboard'
import { useEffect, useState } from 'react'
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 TorrentCache from './TorrentCache'
const DialogContentGrid = styled.div`
display: grid;
grid-template-rows: min-content min-content 80px min-content;
`
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);
}
`}
`}
`
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;
`
import {
DetailedTorrentCacheViewWrapper,
DialogContentGrid,
TorrentMainSection,
Poster,
TorrentData,
SectionTitle,
SectionSubName,
StatisticsWrapper,
ButtonSection,
LoadingProgress,
SectionHeader,
CacheSection,
ButtonSectionButton,
TorrentFilesSection,
} from './style'
import StatisticsField from './StatisticsField'
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 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(() => {
const torrentLoaded = torrent.stat_string !== 'Torrent in db' && torrent.stat_string !== 'Torrent getting info'
torrentLoaded && isLoading && setIsLoading(false)
}, [torrent, isLoading])
const cacheIsLoading = !Object.entries(cache).length
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 (
<>
@@ -156,6 +78,9 @@ export default function DialogTorrentDetailsContent({ closeDialog, torrent }) {
'loading'
) : isDetailedCacheView ? (
<DetailedTorrentCacheViewWrapper>
<div>PiecesCount: {PiecesCount}</div>
<div>PiecesLength: {humanizeSize(PiecesLength)}</div>
<div>status: {statString}</div>
<TorrentCache cache={cache} cacheMap={cacheMap} />
</DetailedTorrentCacheViewWrapper>
) : (
@@ -167,34 +92,62 @@ export default function DialogTorrentDetailsContent({ closeDialog, torrent }) {
<div>
{name && name !== title ? (
<>
<TorrentName>{shortenText(name, 50)}</TorrentName>
<TorrentSubName>{shortenText(title, 160)}</TorrentSubName>
<SectionTitle>{shortenText(name, 50)}</SectionTitle>
<SectionSubName>{shortenText(title, 160)}</SectionSubName>
</>
) : (
<TorrentName>{shortenText(title, 50)}</TorrentName>
<SectionTitle>{shortenText(title, 50)}</SectionTitle>
)}
</div>
<div>peers: {getPeerString(torrent)}</div>
<div>loaded: {getPreload(torrent)}</div>
<div>download speed: {humanizeSize(downloadSpeed)}</div>
<div>upload speed: {humanizeSize(uploadSpeed)}</div>
<div>status: {statString}</div>
<div>torrent size: {humanizeSize(torrentSize)}</div>
<StatisticsWrapper>
<StatisticsField
title='Download speed'
value={humanizeSize(downloadSpeed) || '0 B'}
iconBg='#118f00'
valueBg='#13a300'
icon={ArrowDownward}
/>
<div>Capacity: {humanizeSize(Capacity)}</div>
<div>PiecesCount: {PiecesCount}</div>
<div>PiecesLength: {humanizeSize(PiecesLength)}</div>
<StatisticsField
title='Upload speed'
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>
</TorrentMainSection>
<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} />
<Button
style={{ alignSelf: 'flex-end', marginTop: '30px' }}
style={{ marginTop: '30px' }}
variant='contained'
color='primary'
size='large'
@@ -216,131 +169,133 @@ export default function DialogTorrentDetailsContent({ closeDialog, torrent }) {
<ButtonSectionButton>remove views</ButtonSectionButton>
<ButtonSectionButton>drop torrent</ButtonSectionButton>
<ButtonSectionButton onClick={() => dropTorrent(hash)}>drop torrent</ButtonSectionButton>
<ButtonSectionButton>download playlist</ButtonSectionButton>
<ButtonSectionButton>download playlist after last view</ButtonSectionButton>
</ButtonSection>
<TorrentFilesSection />
<TorrentFilesSection>
<SectionTitle>Torrent Content</SectionTitle>
</TorrentFilesSection>
</DialogContentGrid>
)}
</>
)
}
function getPreload(torrent) {
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)
return `${humanizeSize(torrent.preloaded_bytes)} / ${humanizeSize(torrent.preload_size)} ${progress}%`
}
// function getPreload(torrent) {
// 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)
// 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) {
try {
if (hash)
fetch(viewedHost(), {
method: 'post',
body: JSON.stringify({ action: 'rem', hash, file_index: -1 }),
headers: {
Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/json',
},
})
} catch (e) {
console.error(e)
}
}
// function remViews(hash) {
// try {
// if (hash)
// fetch(viewedHost(), {
// method: 'post',
// body: JSON.stringify({ action: 'rem', hash, file_index: -1 }),
// headers: {
// Accept: 'application/json, text/plain, */*',
// 'Content-Type': 'application/json',
// },
// })
// } catch (e) {
// console.error(e)
// }
// }
function getViewed(hash, callback) {
try {
fetch(viewedHost(), {
method: 'post',
body: JSON.stringify({ action: 'list', hash }),
headers: {
Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/json',
},
})
.then(res => res.json())
.then(callback)
} catch (e) {
console.error(e)
}
}
// function getViewed(hash, callback) {
// try {
// fetch(viewedHost(), {
// method: 'post',
// body: JSON.stringify({ action: 'list', hash }),
// headers: {
// Accept: 'application/json, text/plain, */*',
// 'Content-Type': 'application/json',
// },
// })
// .then(res => res.json())
// .then(callback)
// } catch (e) {
// console.error(e)
// }
// }
function getPlayableFile(torrent) {
if (!torrent || !torrent.file_stats) return null
return torrent.file_stats.filter(file => extPlayable.includes(getExt(file.path)))
}
// function getPlayableFile(torrent) {
// if (!torrent || !torrent.file_stats) return null
// return torrent.file_stats.filter(file => extPlayable.includes(getExt(file.path)))
// }
function getExt(filename) {
const ext = filename.split('.').pop()
if (ext === filename) return ''
return ext.toLowerCase()
}
const extPlayable = [
// video
'3g2',
'3gp',
'aaf',
'asf',
'avchd',
'avi',
'drc',
'flv',
'iso',
'm2v',
'm2ts',
'm4p',
'm4v',
'mkv',
'mng',
'mov',
'mp2',
'mp4',
'mpe',
'mpeg',
'mpg',
'mpv',
'mxf',
'nsv',
'ogg',
'ogv',
'ts',
'qt',
'rm',
'rmvb',
'roq',
'svi',
'vob',
'webm',
'wmv',
'yuv',
// audio
'aac',
'aiff',
'ape',
'au',
'flac',
'gsm',
'it',
'm3u',
'm4a',
'mid',
'mod',
'mp3',
'mpa',
'pls',
'ra',
's3m',
'sid',
'wav',
'wma',
'xm',
]
// function getExt(filename) {
// const ext = filename.split('.').pop()
// if (ext === filename) return ''
// return ext.toLowerCase()
// }
// const extPlayable = [
// // video
// '3g2',
// '3gp',
// 'aaf',
// 'asf',
// 'avchd',
// 'avi',
// 'drc',
// 'flv',
// 'iso',
// 'm2v',
// 'm2ts',
// 'm4p',
// 'm4v',
// 'mkv',
// 'mng',
// 'mov',
// 'mp2',
// 'mp4',
// 'mpe',
// 'mpeg',
// 'mpg',
// 'mpv',
// 'mxf',
// 'nsv',
// 'ogg',
// 'ogv',
// 'ts',
// 'qt',
// 'rm',
// 'rmvb',
// 'roq',
// 'svi',
// 'vob',
// 'webm',
// 'wmv',
// 'yuv',
// // audio
// 'aac',
// 'aiff',
// 'ape',
// 'au',
// 'flac',
// 'gsm',
// 'it',
// 'm3u',
// 'm4a',
// 'mid',
// 'mod',
// 'mp3',
// 'mpa',
// 'pls',
// 'ra',
// 's3m',
// 'sid',
// 'wav',
// 'wma',
// '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)
const sets = JSON.parse(JSON.stringify(settings))
sets.CacheSize *= 1024 * 1024
sets.PreloadBufferSize *= 1024 * 1024
fetch(settingsHost(), {
method: 'post',
body: JSON.stringify({ action: 'set', sets }),
@@ -51,8 +50,6 @@ export default function SettingsDialog() {
json => {
// eslint-disable-next-line no-param-reassign
json.CacheSize /= 1024 * 1024
// eslint-disable-next-line no-param-reassign
json.PreloadBufferSize /= 1024 * 1024
setSets(json)
setShow(true)
},