converted dir tree
This commit is contained in:
@@ -23,18 +23,16 @@ import {
|
||||
BrowserRouter as Router, Link, Route,
|
||||
Routes
|
||||
} from 'react-router-dom';
|
||||
import { io } from "socket.io-client";
|
||||
import ArchivedDownloads from "./Archived";
|
||||
import { AppBar } from "./components/AppBar";
|
||||
import { Drawer } from "./components/Drawer";
|
||||
import Home from "./Home";
|
||||
import Settings from "./Settings";
|
||||
import { RootState, store } from './stores/store';
|
||||
import { getWebSocketEndpoint } from "./utils";
|
||||
import { formatGiB, getWebSocketEndpoint } from "./utils";
|
||||
|
||||
function AppContent() {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [freeDiskSpace, setFreeDiskSpace] = useState('');
|
||||
|
||||
const settings = useSelector((state: RootState) => state.settings)
|
||||
const status = useSelector((state: RootState) => state.status)
|
||||
@@ -58,11 +56,6 @@ function AppContent() {
|
||||
setOpen(!open);
|
||||
};
|
||||
|
||||
/* Get disk free space */
|
||||
useEffect(() => {
|
||||
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={theme}>
|
||||
<Router>
|
||||
@@ -96,14 +89,14 @@ function AppContent() {
|
||||
yt-dlp WebUI
|
||||
</Typography>
|
||||
{
|
||||
freeDiskSpace ?
|
||||
status.freeSpace ?
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
flexWrap: 'wrap',
|
||||
}}>
|
||||
<Storage />
|
||||
<span> {freeDiskSpace} </span>
|
||||
<span> {formatGiB(status.freeSpace)} </span>
|
||||
</div>
|
||||
: null
|
||||
}
|
||||
@@ -145,20 +138,6 @@ function AppContent() {
|
||||
<ListItemText primary="Home" />
|
||||
</ListItemButton>
|
||||
</Link>
|
||||
{/* Next release: list downloaded files */}
|
||||
{/* <Link to={'/downloaded'} style={
|
||||
{
|
||||
textDecoration: 'none',
|
||||
color: mode === 'dark' ? '#ffffff' : '#000000DE'
|
||||
}
|
||||
}>
|
||||
<ListItemButton disabled={status.downloading}>
|
||||
<ListItemIcon>
|
||||
<Download />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Downloaded" />
|
||||
</ListItemButton>
|
||||
</Link> */}
|
||||
<Link to={'/settings'} style={
|
||||
{
|
||||
textDecoration: 'none',
|
||||
|
||||
@@ -24,7 +24,7 @@ import { useDispatch, useSelector } from "react-redux";
|
||||
import { CliArguments } from "./classes";
|
||||
import { StackableResult } from "./components/StackableResult";
|
||||
import { serverStates } from "./events";
|
||||
import { connected } from "./features/status/statusSlice";
|
||||
import { connected, setFreeSpace } from "./features/status/statusSlice";
|
||||
import { I18nBuilder } from "./i18n";
|
||||
import { IDLMetadata, IMessage } from "./interfaces";
|
||||
import { RPCClient } from "./rpcClient";
|
||||
@@ -73,10 +73,6 @@ export default function Home({ socket }: Props) {
|
||||
useEffect(() => {
|
||||
socket.onopen = () => {
|
||||
dispatch(connected())
|
||||
console.log('oke')
|
||||
socket.send('fetch-jobs')
|
||||
socket.send('disk-space')
|
||||
socket.send('retrieve-jobs')
|
||||
}
|
||||
}, [])
|
||||
|
||||
@@ -85,6 +81,11 @@ export default function Home({ socket }: Props) {
|
||||
return () => clearInterval(interval)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
client.freeSpace()
|
||||
.then(bytes => dispatch(setFreeSpace(bytes.result)))
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
socket.onmessage = (event) => {
|
||||
const res = client.decode(event.data)
|
||||
@@ -106,10 +107,9 @@ export default function Home({ socket }: Props) {
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
fetch(`${window.location.protocol}//${settings.serverAddr}:${settings.serverPort}/tree`)
|
||||
.then(res => res.json())
|
||||
client.directoryTree()
|
||||
.then(data => {
|
||||
setAvailableDownloadPaths(data.flat)
|
||||
setAvailableDownloadPaths(data.result)
|
||||
})
|
||||
}, [])
|
||||
|
||||
@@ -150,10 +150,15 @@ export default function Home({ socket }: Props) {
|
||||
setPickedVideoFormat('')
|
||||
setPickedBestFormat('')
|
||||
|
||||
setTimeout(() => {
|
||||
resetInput()
|
||||
setShowBackdrop(true)
|
||||
}, 250)
|
||||
setShowBackdrop(true)
|
||||
|
||||
client.formats(url)
|
||||
?.then(formats => {
|
||||
console.log(formats)
|
||||
setDownloadFormats(formats.result)
|
||||
setShowBackdrop(false)
|
||||
resetInput()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,73 +4,73 @@ import { IMessage } from "../interfaces";
|
||||
import { ellipsis } from "../utils";
|
||||
|
||||
type Props = {
|
||||
title: string,
|
||||
thumbnail: string,
|
||||
resolution: string
|
||||
percentage: string,
|
||||
size: number,
|
||||
speed: number,
|
||||
stopCallback: VoidFunction,
|
||||
title: string,
|
||||
thumbnail: string,
|
||||
resolution: string
|
||||
percentage: string,
|
||||
size: number,
|
||||
speed: number,
|
||||
stopCallback: VoidFunction,
|
||||
}
|
||||
|
||||
export function StackableResult({
|
||||
title,
|
||||
thumbnail,
|
||||
resolution,
|
||||
percentage,
|
||||
speed,
|
||||
size,
|
||||
stopCallback
|
||||
title,
|
||||
thumbnail,
|
||||
resolution,
|
||||
percentage,
|
||||
speed,
|
||||
size,
|
||||
stopCallback
|
||||
}: Props) {
|
||||
const guessResolution = (xByY: string): any => {
|
||||
if (!xByY) return null;
|
||||
if (xByY.includes('4320')) return (<EightK color="primary" />);
|
||||
if (xByY.includes('2160')) return (<FourK color="primary" />);
|
||||
if (xByY.includes('1080')) return (<Hd color="primary" />);
|
||||
if (xByY.includes('720')) return (<Sd color="primary" />);
|
||||
return null;
|
||||
}
|
||||
const guessResolution = (xByY: string): any => {
|
||||
if (!xByY) return null;
|
||||
if (xByY.includes('4320')) return (<EightK color="primary" />);
|
||||
if (xByY.includes('2160')) return (<FourK color="primary" />);
|
||||
if (xByY.includes('1080')) return (<Hd color="primary" />);
|
||||
if (xByY.includes('720')) return (<Sd color="primary" />);
|
||||
return null;
|
||||
}
|
||||
|
||||
const percentageToNumber = () => Number(percentage.replace('%', ''))
|
||||
const percentageToNumber = () => Number(percentage.replace('%', ''))
|
||||
|
||||
const roundMB = (bytes: number) => `${(bytes / 1_000_000).toFixed(2)}MiB`
|
||||
const roundMB = (bytes: number) => `${(bytes / 1_000_000).toFixed(2)}MiB`
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardActionArea>
|
||||
{thumbnail !== '' ?
|
||||
<CardMedia
|
||||
component="img"
|
||||
height={180}
|
||||
image={thumbnail}
|
||||
/> :
|
||||
<Skeleton variant="rectangular" height={180} />
|
||||
}
|
||||
<CardContent>
|
||||
{title !== '' ?
|
||||
<Typography gutterBottom variant="h6" component="div">
|
||||
{ellipsis(title, 54)}
|
||||
</Typography> :
|
||||
<Skeleton />
|
||||
}
|
||||
<Stack direction="row" spacing={1} py={2}>
|
||||
<Chip label={'Downloading'} color="primary" />
|
||||
<Typography>{percentage}</Typography>
|
||||
<Typography>{speed}</Typography>
|
||||
<Typography>{roundMB(size ?? 0)}</Typography>
|
||||
{guessResolution(resolution)}
|
||||
</Stack>
|
||||
{percentage ?
|
||||
<LinearProgress variant="determinate" value={percentageToNumber()} /> :
|
||||
null
|
||||
}
|
||||
</CardContent>
|
||||
</CardActionArea>
|
||||
<CardActions>
|
||||
<Button variant="contained" size="small" color="primary" onClick={stopCallback}>
|
||||
Stop
|
||||
</Button>
|
||||
</CardActions>
|
||||
</Card>
|
||||
)
|
||||
return (
|
||||
<Card>
|
||||
<CardActionArea>
|
||||
{thumbnail !== '' ?
|
||||
<CardMedia
|
||||
component="img"
|
||||
height={180}
|
||||
image={thumbnail}
|
||||
/> :
|
||||
<Skeleton variant="rectangular" height={180} />
|
||||
}
|
||||
<CardContent>
|
||||
{title !== '' ?
|
||||
<Typography gutterBottom variant="h6" component="div">
|
||||
{ellipsis(title, 54)}
|
||||
</Typography> :
|
||||
<Skeleton />
|
||||
}
|
||||
<Stack direction="row" spacing={1} py={2}>
|
||||
<Chip label={'Downloading'} color="primary" />
|
||||
<Typography>{percentage}</Typography>
|
||||
<Typography>{speed}</Typography>
|
||||
<Typography>{roundMB(size ?? 0)}</Typography>
|
||||
{guessResolution(resolution)}
|
||||
</Stack>
|
||||
{percentage ?
|
||||
<LinearProgress variant="determinate" value={percentageToNumber()} /> :
|
||||
null
|
||||
}
|
||||
</CardContent>
|
||||
</CardActionArea>
|
||||
<CardActions>
|
||||
<Button variant="contained" size="small" color="primary" onClick={stopCallback}>
|
||||
Stop
|
||||
</Button>
|
||||
</CardActions>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -1,30 +1,47 @@
|
||||
import { createSlice } from "@reduxjs/toolkit"
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit"
|
||||
|
||||
export interface StatusState {
|
||||
connected: boolean,
|
||||
updated: boolean,
|
||||
downloading: boolean,
|
||||
freeSpace: number,
|
||||
}
|
||||
|
||||
const initialState: StatusState = {
|
||||
connected: false,
|
||||
updated: false,
|
||||
downloading: false,
|
||||
freeSpace: 0,
|
||||
}
|
||||
|
||||
export const statusSlice = createSlice({
|
||||
name: 'status',
|
||||
initialState,
|
||||
reducers: {
|
||||
connected: (state) => { state.connected = true },
|
||||
disconnected: (state) => { state.connected = false },
|
||||
updated: (state) => { state.updated = true },
|
||||
alreadyUpdated: (state) => { state.updated = false },
|
||||
downloading: (state) => { state.downloading = true },
|
||||
finished: (state) => { state.downloading = false },
|
||||
connected: (state) => {
|
||||
state.connected = true
|
||||
},
|
||||
disconnected: (state) => {
|
||||
state.connected = false
|
||||
},
|
||||
updated: (state) => {
|
||||
state.updated = true
|
||||
},
|
||||
alreadyUpdated: (state) => {
|
||||
state.updated = false
|
||||
},
|
||||
downloading: (state) => {
|
||||
state.downloading = true
|
||||
},
|
||||
finished: (state) => {
|
||||
state.downloading = false
|
||||
},
|
||||
setFreeSpace: (state, action: PayloadAction<number>) => {
|
||||
state.freeSpace = action.payload
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export const { connected, disconnected, updated, alreadyUpdated, downloading, finished } = statusSlice.actions
|
||||
export const { connected, disconnected, updated, alreadyUpdated, downloading, finished, setFreeSpace } = statusSlice.actions
|
||||
|
||||
export default statusSlice.reducer
|
||||
@@ -1,6 +1,8 @@
|
||||
import type { RPCRequest, RPCResponse } from "./types"
|
||||
import type { IDLMetadata } from './interfaces'
|
||||
|
||||
import { getHttpRPCEndpoint } from './utils'
|
||||
|
||||
export class RPCClient {
|
||||
private socket: WebSocket
|
||||
private seq: number
|
||||
@@ -20,7 +22,7 @@ export class RPCClient {
|
||||
|
||||
private sendHTTP<T>(req: RPCRequest) {
|
||||
return new Promise<RPCResponse<T>>((resolve, reject) => {
|
||||
fetch('/rpc-http', {
|
||||
fetch(getHttpRPCEndpoint(), {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(req)
|
||||
})
|
||||
@@ -75,6 +77,20 @@ export class RPCClient {
|
||||
})
|
||||
}
|
||||
|
||||
public freeSpace() {
|
||||
return this.sendHTTP<number>({
|
||||
method: 'Service.FreeSpace',
|
||||
params: [],
|
||||
})
|
||||
}
|
||||
|
||||
public directoryTree() {
|
||||
return this.sendHTTP<string[]>({
|
||||
method: 'Service.DirectoryTree',
|
||||
params: [],
|
||||
})
|
||||
}
|
||||
|
||||
public decode(data: any): RPCResponse<any> {
|
||||
return JSON.parse(data)
|
||||
}
|
||||
|
||||
1
frontend/src/types.d.ts
vendored
1
frontend/src/types.d.ts
vendored
@@ -5,6 +5,7 @@ export type RPCMethods =
|
||||
| "Service.KillAll"
|
||||
| "Service.FreeSpace"
|
||||
| "Service.Formats"
|
||||
| "Service.DirectoryTree"
|
||||
|
||||
export type RPCRequest = {
|
||||
method: RPCMethods,
|
||||
|
||||
@@ -111,4 +111,8 @@ export function getWebSocketEndpoint() {
|
||||
|
||||
export function getHttpRPCEndpoint() {
|
||||
return `${window.location.protocol}//${localStorage.getItem('server-addr') || window.location.hostname}:${localStorage.getItem('server-port') || window.location.port}/http-rpc`
|
||||
}
|
||||
|
||||
export function formatGiB(bytes: number) {
|
||||
return `${(bytes / 1_000_000_000).toFixed(0)}GiB`
|
||||
}
|
||||
Reference in New Issue
Block a user