diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index c13b0fb..9515fb1 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -9,7 +9,7 @@ import {
Button,
ButtonGroup,
} from "react-bootstrap";
-import { X } from "react-bootstrap-icons";
+import { X, HddFill } from "react-bootstrap-icons";
import { buildMessage, updateInStateMap, validateDomain, validateIP } from "./utils";
import { IDLInfo, IDLInfoBase, IMessage } from "./interfaces";
import { MessageToast } from "./components/MessageToast";
@@ -31,6 +31,7 @@ export function App() {
const [invalidIP, setInvalidIP] = useState(false);
const [updatedBin, setUpdatedBin] = useState(false);
const [showSettings, setShowSettings] = useState(false);
+ const [freeDiskSpace, setFreeDiskSpace] = useState('');
const [darkMode, setDarkMode] = useState(localStorage.getItem('theme') === 'dark');
const xaInput = useRef(null);
@@ -53,6 +54,7 @@ export function App() {
socket.on('connect', () => {
setShowToast(true)
socket.emit('fetch-jobs')
+ socket.emit('disk-space')
})
return () => {
socket.disconnect()
@@ -80,6 +82,7 @@ export function App() {
setHalt(false);
updateInStateMap(data.pid, 'Done!', messageMap, setMessageMap);
updateInStateMap(data.pid, 0, progressMap, setProgressMap);
+ socket.emit('disk-space')
return;
}
updateInStateMap(data.pid, buildMessage(data), messageMap, setMessageMap);
@@ -104,6 +107,13 @@ export function App() {
document.body.classList.remove('dark');
}, [darkMode])
+ /* Get disk free space */
+ useEffect(() => {
+ socket.on('free-space', (res: string) => {
+ setFreeDiskSpace(res)
+ })
+ }, [])
+
/* -------------------- component functions -------------------- */
/**
@@ -282,6 +292,10 @@ export function App() {
+
+ {' '}
+ {freeDiskSpace ? freeDiskSpace : '-'}
+
@@ -304,21 +318,22 @@ export function App() {
/>
:3022
- {' '}
-
+
+ {' '}
+
:
null
}
diff --git a/package.json b/package.json
index ee2d031..d585019 100644
--- a/package.json
+++ b/package.json
@@ -3,8 +3,8 @@
"version": "1.1.0",
"description": "A terrible webUI for yt-dlp, all-in-one solution.",
"scripts": {
- "start": "node server.js",
- "dev": "nodemon app.js",
+ "start": "node dist/main.js",
+ "dev": "tsc --build -w",
"build": "parcel build ./frontend/index.html --dist-dir ./dist/frontend",
"build-server": "tsc --build",
"build-all": "tsc --build && npm run build && npm run fetch",
diff --git a/server/src/core/Process.ts b/server/src/core/Process.ts
index 27b1130..59ce29d 100644
--- a/server/src/core/Process.ts
+++ b/server/src/core/Process.ts
@@ -52,7 +52,14 @@ class Process {
log.info('proc', `Spawned a new process, pid: ${this.pid}`)
- await insertDownload(this.url, this.info?.title, this.info?.thumbnail, null, this.pid);
+ await insertDownload(
+ this.url,
+ this.info?.title,
+ this.info?.thumbnail,
+ null,
+ this.params.reduce((prev, next) => `${prev} ${next}`),
+ this.pid
+ );
return this;
}
diff --git a/server/src/core/downloader.ts b/server/src/core/downloader.ts
index 13c6268..1515cdc 100644
--- a/server/src/core/downloader.ts
+++ b/server/src/core/downloader.ts
@@ -95,7 +95,9 @@ export async function retriveDownload(socket: Socket) {
if (coldRestart) {
coldRestart = false;
let downloads = await pruneDownloads();
- downloads = [... new Set(downloads)];
+ console.log(downloads)
+ // sanitize
+ downloads = [... new Set(downloads.filter(el => el !== undefined))];
log.info('dl', `Cold restart, retrieving ${downloads.length} jobs`)
for (const entry of downloads) {
if (entry) {
@@ -180,7 +182,7 @@ const formatter = (stdout: string, pid: number) => {
switch (status) {
case 'download':
return {
- status: cleanStdout[0].replace(/\[|\]|\r/g, ''),
+ status: 'download',
progress: cleanStdout[1],
size: cleanStdout[3],
dlSpeed: cleanStdout[5],
diff --git a/server/src/db/db.ts b/server/src/db/db.ts
index 9c33f2d..9d0be96 100644
--- a/server/src/db/db.ts
+++ b/server/src/db/db.ts
@@ -1,5 +1,6 @@
import { v1 } from 'uuid';
import { existsInProc } from '../utils/procUtils';
+import { IRecord } from '../interfaces/IRecord';
import Logger from '../utils/BetterLogger';
const db = require('better-sqlite3')('downloads.db');
@@ -17,7 +18,8 @@ export async function init() {
thumbnail text,
created date,
size text,
- process_pid int NOT NULL,
+ params text,
+ pid int NOT NULL,
PRIMARY KEY (uid)
)`)
} catch (e) {
@@ -39,21 +41,22 @@ export async function get_db(): Promise {
* @param {string} title the title fetched by the info process
* @param {string} thumbnail the thumbnail url fetched by the info process
* @param {string} size optional - the download size
+ * @param {string} params optional - the download parameters, cli arguments
* @param {number} PID the pid of the downloader
* @returns {Promise} the download UUID
*/
-export async function insertDownload(url: string, title: string, thumbnail: string, size: string, PID: number): Promise {
+export async function insertDownload(url: string, title: string, thumbnail: string, size: string, params: string, PID: number): Promise {
const uid = v1()
try {
db
.prepare(`
INSERT INTO downloads
- (uid, url, title, thumbnail, size, process_pid)
- VALUES (?, ?, ?, ?, ?, ?)`
+ (uid, url, title, thumbnail, size, params, pid)
+ VALUES (?, ?, ?, ?, ?, ?, ?)`
)
- .run(uid, url, title, thumbnail, size, PID)
+ .run(uid, url, title, thumbnail, size, params, PID)
} catch (error) {
- log.err('db', 'some error occourred')
+ log.err('db', error)
}
return uid
@@ -63,7 +66,7 @@ export async function insertDownload(url: string, title: string, thumbnail: stri
* Retrieve all downloads from the database
* @returns {ArrayLike} a collection of results
*/
-export async function retrieveAll(): Promise {
+export async function retrieveAll(): Promise> {
return db
.prepare('SELECT * FROM downloads')
.all()
@@ -81,20 +84,20 @@ export async function deleteDownloadById(uid: string) {
* Delete a download by its pid
* @param {string} pid the to-be-deleted download pid
*/
-export async function deleteDownloadByPID(PID) {
- db.prepare(`DELETE FROM downloads WHERE process_pid=${PID}`).run()
+export async function deleteDownloadByPID(pid: number) {
+ db.prepare(`DELETE FROM downloads WHERE pid=${pid}`).run()
}
/**
* Deletes the downloads that aren't active anymore
* @returns {Promise}
*/
-export async function pruneDownloads(): Promise {
+export async function pruneDownloads(): Promise> {
const all = await retrieveAll()
return all.map(job => {
- if (existsInProc(job.process_pid)) {
+ if (existsInProc(job.pid)) {
return job
}
- deleteDownloadByPID(job.process_pid)
+ deleteDownloadByPID(job.pid)
})
}
\ No newline at end of file
diff --git a/server/src/interfaces/IPayload.ts b/server/src/interfaces/IPayload.ts
index 25f1e04..f3cf324 100644
--- a/server/src/interfaces/IPayload.ts
+++ b/server/src/interfaces/IPayload.ts
@@ -1,3 +1,7 @@
+/**
+ * Represent a download payload sent by the frontend
+ */
+
export interface IPayload {
url: string
params: Array | string,
diff --git a/server/src/interfaces/IRecord.ts b/server/src/interfaces/IRecord.ts
index e69de29..e4e6109 100644
--- a/server/src/interfaces/IRecord.ts
+++ b/server/src/interfaces/IRecord.ts
@@ -0,0 +1,14 @@
+/**
+ * Represent a download db record
+ */
+
+export interface IRecord {
+ uid: string,
+ url: string,
+ title: string,
+ thumbnail: string,
+ created: Date,
+ size: string,
+ pid: number,
+ params: string,
+}
\ No newline at end of file
diff --git a/server/src/main.ts b/server/src/main.ts
index 511f8c2..79f54e9 100644
--- a/server/src/main.ts
+++ b/server/src/main.ts
@@ -9,6 +9,7 @@ import { ytdlpUpdater } from './utils/updater';
import { download, abortDownload, retriveDownload, abortAllDownloads } from './core/downloader';
import Logger from './utils/BetterLogger';
import { retrieveAll, init } from './db/db';
+import { getFreeDiskSpace } from './utils/procUtils';
const app = new Koa()
const log = new Logger()
@@ -45,6 +46,9 @@ io.on('connection', socket => {
socket.on('retrieve-jobs', () => {
retriveDownload(socket)
})
+ socket.on('disk-space', () => {
+ getFreeDiskSpace(socket)
+ })
})
io.on('disconnect', (socket) => {
diff --git a/server/src/utils/BetterLogger.ts b/server/src/utils/BetterLogger.ts
index 02902d9..678fabb 100644
--- a/server/src/utils/BetterLogger.ts
+++ b/server/src/utils/BetterLogger.ts
@@ -12,9 +12,9 @@ class Logger {
* @param {string} proto the context/protocol/section outputting the message
* @param {string} args the acutal message
*/
- info(proto: string, args: string) {
+ public info(proto: string, args: string) {
process.stdout.write(
- this.#__formatter(proto, args)
+ this.formatter(proto, args)
)
}
/**
@@ -22,9 +22,9 @@ class Logger {
* @param {string} proto the context/protocol/section outputting the message
* @param {string} args the acutal message
*/
- warn(proto: string, args: string) {
+ public warn(proto: string, args: string) {
process.stdout.write(
- `${ansi.yellow}${this.#__formatter(proto, args)}${ansi.reset}`
+ `${ansi.yellow}${this.formatter(proto, args)}${ansi.reset}`
)
}
/**
@@ -32,13 +32,13 @@ class Logger {
* @param {string} proto the context/protocol/section outputting the message
* @param {string} args the acutal message
*/
- err(proto: string, args: string) {
+ public err(proto: string, args: string) {
process.stdout.write(
- `${ansi.red}${this.#__formatter(proto, args)}${ansi.reset}`
+ `${ansi.red}${this.formatter(proto, args)}${ansi.reset}`
)
}
- #__formatter(proto: any, args: any) {
+ private formatter(proto: any, args: any) {
return `[${proto}]\t${args}\n`
}
}
diff --git a/server/src/utils/procUtils.ts b/server/src/utils/procUtils.ts
index 4a77582..a085ad0 100644
--- a/server/src/utils/procUtils.ts
+++ b/server/src/utils/procUtils.ts
@@ -1,6 +1,6 @@
-import { spawn } from 'child_process';
+import { exec, spawn } from 'child_process';
import fs = require('fs');
-import net = require('net');
+// import net = require('net');
import { logger } from './logger';
/**
@@ -39,3 +39,11 @@ export async function killProcess(pid: number) {
logger('proc', `Successfully killed yt-dlp process, pid: ${pid}`)
})
}
+
+export function getFreeDiskSpace(socket: any) {
+ let buffer: string = '';
+ let message: string = 'free-space';
+ exec("df -h / | tail -1 | awk '{print $4}'", (_, stdout) => {
+ socket.emit(message, stdout)
+ })
+}
\ No newline at end of file