code and layout refactoring

This commit is contained in:
2024-03-26 10:10:27 +01:00
parent 82ccb68a56
commit c6e48f4baa
11 changed files with 143 additions and 147 deletions

View File

@@ -4,10 +4,10 @@ import { loadingDownloadsState } from '../atoms/downloads'
import { listViewState } from '../atoms/settings' import { listViewState } from '../atoms/settings'
import { loadingAtom } from '../atoms/ui' import { loadingAtom } from '../atoms/ui'
import DownloadsCardView from './DownloadsCardView' import DownloadsCardView from './DownloadsCardView'
import DownloadsListView from './DownloadsTableView' import DownloadsTableView from './DownloadsTableView'
const Downloads: React.FC = () => { const Downloads: React.FC = () => {
const listView = useRecoilValue(listViewState) const tableView = useRecoilValue(listViewState)
const loadingDownloads = useRecoilValue(loadingDownloadsState) const loadingDownloads = useRecoilValue(loadingDownloadsState)
const [isLoading, setIsLoading] = useRecoilState(loadingAtom) const [isLoading, setIsLoading] = useRecoilState(loadingAtom)
@@ -20,15 +20,9 @@ const Downloads: React.FC = () => {
setIsLoading(false) setIsLoading(false)
}, [loadingDownloads, isLoading]) }, [loadingDownloads, isLoading])
if (listView) { if (tableView) return <DownloadsTableView />
return (
<DownloadsListView />
)
}
return ( return <DownloadsCardView />
<DownloadsCardView />
)
} }
export default Downloads export default Downloads

View File

@@ -16,10 +16,10 @@ const DownloadsCardView: React.FC = () => {
const abort = (id: string) => client.kill(id) const abort = (id: string) => client.kill(id)
return ( return (
<Grid container spacing={{ xs: 2, md: 2 }} columns={{ xs: 4, sm: 8, md: 12 }} pt={2}> <Grid container spacing={{ xs: 2, md: 2 }} columns={{ xs: 4, sm: 8, md: 12, xl: 12 }} pt={2}>
{ {
downloads.map(download => ( downloads.map(download => (
<Grid item xs={4} sm={8} md={6} key={download.id}> <Grid item xs={4} sm={8} md={6} xl={4} key={download.id}>
<DownloadCard <DownloadCard
download={download} download={download}
onStop={() => abort(download.id)} onStop={() => abort(download.id)}

View File

@@ -45,12 +45,8 @@ const DownloadsTableView: React.FC = () => {
const abort = (id: string) => client.kill(id) const abort = (id: string) => client.kill(id)
return ( return (
<Grid container spacing={{ xs: 2, md: 2 }} columns={{ xs: 4, sm: 8, md: 12 }} pt={2}>
<Grid item xs={12}>
<TableContainer <TableContainer
component={Paper} sx={{ minHeight: '80vh', mt: 4 }}
sx={{ minHeight: '80vh' }}
elevation={2}
hidden={downloads.length === 0} hidden={downloads.length === 0}
> >
<Table size="small"> <Table size="small">
@@ -126,8 +122,6 @@ const DownloadsTableView: React.FC = () => {
</TableBody> </TableBody>
</Table> </Table>
</TableContainer> </TableContainer>
</Grid>
</Grid>
) )
} }

View File

@@ -1,4 +1,3 @@
import { Box, Container, Paper, Typography } from '@mui/material'
import { useEffect, useMemo, useRef, useState } from 'react' import { useEffect, useMemo, useRef, useState } from 'react'
import { useRecoilValue } from 'recoil' import { useRecoilValue } from 'recoil'
import { serverURL } from '../atoms/settings' import { serverURL } from '../atoms/settings'
@@ -7,14 +6,15 @@ import { useI18n } from '../hooks/useI18n'
const token = localStorage.getItem('token') const token = localStorage.getItem('token')
const LogTerminal: React.FC = () => { const LogTerminal: React.FC = () => {
const [logBuffer, setLogBuffer] = useState<string[]>([])
const [isConnecting, setIsConnecting] = useState(true)
const boxRef = useRef<HTMLDivElement>(null)
const serverAddr = useRecoilValue(serverURL) const serverAddr = useRecoilValue(serverURL)
const { i18n } = useI18n() const { i18n } = useI18n()
const [logBuffer, setLogBuffer] = useState<string[]>([])
const boxRef = useRef<HTMLDivElement>(null)
const eventSource = useMemo( const eventSource = useMemo(
() => new EventSource(`${serverAddr}/log/sse?token=${token}`), () => new EventSource(`${serverAddr}/log/sse?token=${token}`),
[serverAddr] [serverAddr]
@@ -23,7 +23,7 @@ const LogTerminal: React.FC = () => {
useEffect(() => { useEffect(() => {
eventSource.addEventListener('log', event => { eventSource.addEventListener('log', event => {
const msg: string[] = JSON.parse(event.data) const msg: string[] = JSON.parse(event.data)
setLogBuffer(buff => [...buff, ...msg].slice(-100)) setLogBuffer(buff => [...buff, ...msg].slice(-500))
boxRef.current?.scrollTo(0, boxRef.current.scrollHeight) boxRef.current?.scrollTo(0, boxRef.current.scrollHeight)
}) })
@@ -32,6 +32,10 @@ const LogTerminal: React.FC = () => {
return () => eventSource.close() return () => eventSource.close()
}, [eventSource]) }, [eventSource])
useEffect(() => {
eventSource.onopen = () => setIsConnecting(false)
}, [eventSource])
const logEntryStyle = (data: string) => { const logEntryStyle = (data: string) => {
const sx = {} const sx = {}
@@ -46,20 +50,10 @@ const LogTerminal: React.FC = () => {
} }
return ( return (
<Container maxWidth="lg" sx={{ mt: 4, mb: 4 }}>
<Paper <div
sx={{
p: 2.5,
display: 'flex',
flexDirection: 'column',
}}
>
<Typography py={1} variant="h5" color="primary">
{i18n.t('logsTitle')}
</Typography>
<Box
ref={boxRef} ref={boxRef}
sx={{ style={{
fontFamily: 'Roboto Mono', fontFamily: 'Roboto Mono',
height: '70.5vh', height: '70.5vh',
overflowY: 'auto', overflowY: 'auto',
@@ -72,15 +66,17 @@ const LogTerminal: React.FC = () => {
borderRadius: '0.25rem' borderRadius: '0.25rem'
}} }}
> >
{logBuffer.length === 0 && <Box >{i18n.t('awaitingLogs')}</Box>} {isConnecting ? <div>{'Connecting...'}</div> : <div>{'Connected!'}</div>}
{logBuffer.length === 0 && <div>{i18n.t('awaitingLogs')}</div>}
{logBuffer.map((log, idx) => ( {logBuffer.map((log, idx) => (
<Box key={idx} sx={logEntryStyle(log)}> <div key={idx} style={logEntryStyle(log)}>
{log} {log}
</Box> </div>
))} ))}
</Box> </div>
</Paper>
</Container >
) )
} }

View File

@@ -182,7 +182,7 @@ export default function Downloaded() {
return ( return (
<Container <Container
maxWidth="lg" maxWidth="xl"
sx={{ mt: 4, mb: 4, height: '100%' }} sx={{ mt: 4, mb: 4, height: '100%' }}
onClick={() => setShowMenu(false)} onClick={() => setShowMenu(false)}
> >

View File

@@ -8,7 +8,7 @@ import Splash from '../components/Splash'
export default function Home() { export default function Home() {
return ( return (
<Container maxWidth="lg" sx={{ mt: 2, mb: 8 }}> <Container maxWidth="xl" sx={{ mt: 2, mb: 8 }}>
<LoadingBackdrop /> <LoadingBackdrop />
<Splash /> <Splash />
<Downloads /> <Downloads />

View File

@@ -134,12 +134,12 @@ export default function Settings() {
} }
return ( return (
<Container maxWidth="lg" sx={{ mt: 4, mb: 8 }}> <Container maxWidth="xl" sx={{ mt: 4, mb: 8 }}>
<Grid container spacing={3}> <Grid container spacing={3}>
<Grid item xs={12} md={12} lg={12}> <Grid item xs={12} md={12} lg={12}>
<Paper <Paper
sx={{ sx={{
p: 2, p: 2.5,
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
minHeight: 240, minHeight: 240,

View File

@@ -1,8 +1,25 @@
import { Container, Paper, Typography } from '@mui/material'
import LogTerminal from '../components/LogTerminal' import LogTerminal from '../components/LogTerminal'
import { useI18n } from '../hooks/useI18n'
const Terminal: React.FC = () => { const Terminal: React.FC = () => {
const { i18n } = useI18n()
return ( return (
<Container maxWidth="xl" sx={{ mt: 4, mb: 4 }}>
<Paper
sx={{
p: 2.5,
display: 'flex',
flexDirection: 'column',
}}
>
<Typography pb={2} variant="h5" color="primary">
{i18n.t('logsTitle')}
</Typography>
<LogTerminal /> <LogTerminal />
</Paper>
</Container >
) )
} }

View File

@@ -105,8 +105,10 @@ func RunBlocking(cfg *RunConfig) {
go gracefulShutdown(srv, &mdb) go gracefulShutdown(srv, &mdb)
go autoPersist(time.Minute*5, &mdb, logger) go autoPersist(time.Minute*5, &mdb, logger)
network := "tcp" var (
address := fmt.Sprintf("%s:%d", cfg.Host, cfg.Port) network = "tcp"
address = fmt.Sprintf("%s:%d", cfg.Host, cfg.Port)
)
if strings.HasPrefix(cfg.Host, "/") { if strings.HasPrefix(cfg.Host, "/") {
network = "unix" network = "unix"
@@ -120,6 +122,7 @@ func RunBlocking(cfg *RunConfig) {
} }
logger.Info("yt-dlp-webui started", slog.String("address", address)) logger.Info("yt-dlp-webui started", slog.String("address", address))
if err := srv.Serve(listener); err != nil { if err := srv.Serve(listener); err != nil {
logger.Warn("http server stopped", slog.String("err", err.Error())) logger.Warn("http server stopped", slog.String("err", err.Error()))
} }

View File

@@ -1,8 +1,6 @@
package utils package utils
import ( import (
"crypto/sha256"
"encoding/hex"
"io/fs" "io/fs"
"regexp" "regexp"
"strings" "strings"
@@ -21,9 +19,3 @@ func IsValidEntry(d fs.DirEntry) bool {
!strings.HasSuffix(d.Name(), ".part") && !strings.HasSuffix(d.Name(), ".part") &&
!strings.HasSuffix(d.Name(), ".ytdl") !strings.HasSuffix(d.Name(), ".ytdl")
} }
func ShaSumString(path string) string {
h := sha256.New()
h.Write([]byte(path))
return hex.EncodeToString(h.Sum(nil))
}