From 29d23144e7f153e9fba061c6e6cb5b3cc90187a2 Mon Sep 17 00:00:00 2001 From: marcobaobao Date: Tue, 30 Nov 2021 13:07:22 +0100 Subject: [PATCH] update 30 --- .dockerignore | 6 +++- .gitignore | 4 ++- README.md | 28 +++++++++++----- frontend/src/App.tsx | 44 ++++++++++++++++++++------ frontend/src/components/Statistics.tsx | 12 +++++++ frontend/src/interfaces.tsx | 9 +++++- frontend/src/utils.ts | 7 ++++ lib/downloader.js | 40 ++++++++++++++++------- lib/yt-dlpCaller.js | 24 -------------- package.json | 2 +- server.js | 10 +++--- 11 files changed, 124 insertions(+), 62 deletions(-) create mode 100644 frontend/src/components/Statistics.tsx delete mode 100644 lib/yt-dlpCaller.js diff --git a/.dockerignore b/.dockerignore index 1288e6e..457610c 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,4 +2,8 @@ node_modules dist package-lock.json .parcel-cache -.git \ No newline at end of file +.git +lib/*.exe +lib/yt-dlp +.env +*.mp4 \ No newline at end of file diff --git a/.gitignore b/.gitignore index cc1abb6..aa9ad5a 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,6 @@ dist package-lock.json node_modules lib/*.exe -.env \ No newline at end of file +lib/yt-dlp +.env +*.mp4 \ No newline at end of file diff --git a/README.md b/README.md index 701459a..c5473ab 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,26 @@ # yt-dlp Web UI A terrible web ui for yt-dlp. -Created for the only purpose of *cough cough* k-pop videos from my server/nas. +Created for the only purpose of *consume* videos from my server/nas. I will eventually make this better as soon as I can. Not in the immediate. -ytdlpwebui + -## Docker install +## Now with dark mode + + + +## Settings + +The avaible settings are currently only: +- Server address +- Switch theme + +Future releases will have: +- Exctract audio +- Format selection + +## Docker installation ``` docker pull marcobaobao/yt-dlp-webui:latest docker run -d -p 3022:3022 -v :/usr/src/yt-dlp-webui/downloads marcobaobao/yt-dlp-webui @@ -17,16 +31,14 @@ docker build -t yt-dlp-webui . docker run -d -p 3022:3022 -v :/usr/src/yt-dlp-webui/downloads yt-dlp-webui ``` -## Manual install +## Manual installation ``` -// download the yt-dl build and put it in the lib folder and make it executable - npm i npm run build npm run fetch // edit the settings.json specifying the download path or -// it will use the following folder +// it will default to the following created folder mkdir downloads @@ -34,5 +46,5 @@ node server.js ``` ## Todo list -- retrieve background task +- retrieve background tasks - better ui/ux diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 0819a10..b695b14 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -12,7 +12,7 @@ import { Toast, } from "react-bootstrap"; import { validateDomain, validateIP } from "./utils"; -import { IMessage } from "./interfaces"; +import { IDLInfo, IMessage } from "./interfaces"; import './App.css'; const socket = io(`http://${localStorage.getItem('server-addr') || 'localhost'}:3022`) @@ -28,11 +28,15 @@ export function App() { const [updatedBin, setUpdatedBin] = useState(false) const [showSettings, setShowSettings] = useState(false) const [darkMode, setDarkMode] = useState(localStorage.getItem('theme') === 'dark') + const [downloadInfo, setDownloadInfo] = useState() useEffect(() => { socket.on('connect', () => { setShowToast(true) }) + return () => { + socket.disconnect() + } }, []) useEffect(() => { @@ -41,9 +45,15 @@ export function App() { document.body.classList.remove('dark') }, [darkMode]) + useEffect(() => { + socket.on('info', (data: IDLInfo) => { + setDownloadInfo(data) + }) + }, []) + useEffect(() => { socket.on('progress', (data: IMessage) => { - setMessage(`${data.status || '...'} | progress: ${data.progress || '?'} | size: ${data.size || '?'} | speed: ${data.dlSpeed || '?'}`) + setMessage(`operation: ${data.status || '...'} \nprogress: ${data.progress || '?'} \nsize: ${data.size || '?'} \nspeed: ${data.dlSpeed || '?'}`) if (data.status === 'Done!') { setHalt(false) setMessage('Done!') @@ -86,6 +96,10 @@ export function App() { } const abort = () => { + setDownloadInfo({ + title: '', + thumbnail: '' + }) socket.emit('abort') setHalt(false) } @@ -123,13 +137,23 @@ export function App() {
-
Status
- {!message ?
Ready
: null} -
{message}
+ + {downloadInfo ?

{downloadInfo.title}

: null} + +
Status
+ {!message ?
Ready
: null} +
{message}
+ + +
+ + +
- - {' '} - {' '} + + + + {progress ? : null} @@ -161,14 +185,14 @@ export function App() { : null }
-
Once you close the page the download will continue in the background.
+
Once you close this page the download will continue in the background.
It won't be possible retriving the progress though.
Made with ❤️ by Marcobaobao diff --git a/frontend/src/components/Statistics.tsx b/frontend/src/components/Statistics.tsx new file mode 100644 index 0000000..8dc998c --- /dev/null +++ b/frontend/src/components/Statistics.tsx @@ -0,0 +1,12 @@ +import React, { useState } from "react"; +import { IDLSpeed } from "../interfaces"; + +export function Statistics(props: any) { + const [dataset, setDataset] = useState>() + + return ( +
+ +
+ ) +} \ No newline at end of file diff --git a/frontend/src/interfaces.tsx b/frontend/src/interfaces.tsx index acad891..9b28602 100644 --- a/frontend/src/interfaces.tsx +++ b/frontend/src/interfaces.tsx @@ -2,7 +2,14 @@ export interface IMessage { status: string, progress?: string, size?: string, - dlSpeed?: string + dlSpeed?: string | IDLSpeed +} + +export interface IDLInfo { + title: string, + thumbnail: string, + upload_date?: string | Date, + duration?: number } export interface IDLSpeed { diff --git a/frontend/src/utils.ts b/frontend/src/utils.ts index 7b99e3c..dc368b6 100644 --- a/frontend/src/utils.ts +++ b/frontend/src/utils.ts @@ -6,4 +6,11 @@ export function validateIP(ipAddr: string): boolean { export function validateDomain(domainName: string): boolean { let domainRegex = /[^@ \t\r\n]+.[^@ \t\r\n]+\.[^@ \t\r\n]+/ return domainRegex.test(domainName) || domainName === 'localhost' +} + +export function ellipsis(str: string, lim: number): string { + if (str) { + return str.length > lim ? `${str.substr(0, lim)}...` : str + } + return '' } \ No newline at end of file diff --git a/lib/downloader.js b/lib/downloader.js index 287c91a..0b47392 100644 --- a/lib/downloader.js +++ b/lib/downloader.js @@ -14,22 +14,27 @@ catch (e) { const isWindows = process.platform === 'win32' const download = (socket, url) => { + if (url === '' || url === null) { + socket.emit('progress', { status: 'Done!' }) + return + } + + getDownloadInfo(socket, url) + const ytldp = spawn(`./lib/yt-dlp${isWindows ? '.exe' : ''}`, ['-o', `${settings.download_path || 'downloads/'}%(title)s.%(ext)s`, url] ) - from(ytldp.stdout) // stout as observable + from(ytldp.stdout) // stdout as observable .pipe(throttle(() => interval(500))) // discard events closer than 500ms .subscribe({ next: (stdout) => { - let _stdout = String(stdout) - socket.emit('progress', formatter(_stdout)) // finally, emit + //let _stdout = String(stdout) + socket.emit('progress', formatter(String(stdout))) // finally, emit //logger('download', `Fetching ${stdout}`) - console.log(formatter(_stdout)) }, complete: () => { socket.emit('progress', { status: 'Done!' }) - logger('download', 'Done!') } }) @@ -39,15 +44,29 @@ const download = (socket, url) => { }) } +const getDownloadInfo = (socket, url) => { + let stdoutChunks = []; + const ytdlpInfo = spawn(`./lib/yt-dlp${isWindows ? '.exe' : ''}`, ['-s', '-j', url]); + + ytdlpInfo.stdout.on('data', (data) => { + stdoutChunks.push(data) + }) + + ytdlpInfo.on('exit', () => { + const buffer = Buffer.concat(stdoutChunks) + const json = JSON.parse(buffer.toString()) + socket.emit('info', json) + }) +} + const abortDownload = (socket) => { const res = process.platform === 'win32' ? spawn('taskkill', ['/IM', 'yt-dlp.exe', '/F', '/T']) : spawn('killall', ['yt-dlp']) - res.stdout.on('data', data => { + res.on('exit', () => { socket.emit('progress', 'Aborted!') - logger('download', `Aborting ${data.toString()}`) + logger('download', 'Aborting downloads') }) - logger('download', 'Aborted') } const formatter = (stdout) => { @@ -71,10 +90,9 @@ const formatter = (stdout) => { default: return { progress: '0' } } - } module.exports = { download: download, - abortDownload: abortDownload -} \ No newline at end of file + abortDownload: abortDownload, +} diff --git a/lib/yt-dlpCaller.js b/lib/yt-dlpCaller.js deleted file mode 100644 index 3c45198..0000000 --- a/lib/yt-dlpCaller.js +++ /dev/null @@ -1,24 +0,0 @@ -const Readable = require('stream').Readable; - -class Subscription extends Readable{ - constructor(options) { - super(); - if (!(this instanceof Subscription)) - return new Subscription(options); - - options = options || {}; - Readable.call(this, options); - - this.value = 0; - } - _read() { - while(this.value <= 100){ - this.push(String(this.value++)); - } - } -} - - -exports.subscribe = function(event, options){ - return new Subscription(options); -} \ No newline at end of file diff --git a/package.json b/package.json index 57edcf4..6251779 100644 --- a/package.json +++ b/package.json @@ -25,4 +25,4 @@ "devDependencies": { "parcel": "^2.0.1" } -} +} \ No newline at end of file diff --git a/server.js b/server.js index 4bfa675..54a0f61 100644 --- a/server.js +++ b/server.js @@ -18,8 +18,8 @@ const io = new Server(server, { }) io.on('connection', socket => { - logger('ws', 'connesso') - + logger('ws', `${socket.handshake.address} connected!`) + // message listeners socket.on('send-url', args => { logger('ws', args) download(socket, args) @@ -32,14 +32,14 @@ io.on('connection', socket => { }) }) -io.on('disconnect', () => { - logger('ws', 'disconnesso') +io.on('disconnect', (socket) => { + logger('ws', `${socket.handshake.address} disconnected`) }) app .use(cors()) .use(serve(path.join(__dirname, 'dist'))) -console.log('[koa] Server started port', process.env.PORT || 3022) +logger('koa', `Server started on port ${process.env.PORT || 3022}`) server.listen(process.env.PORT || 3022) \ No newline at end of file