core rework
This commit is contained in:
@@ -13,6 +13,7 @@ import {
|
|||||||
} from "react-bootstrap";
|
} from "react-bootstrap";
|
||||||
import { validateDomain, validateIP } from "./utils";
|
import { validateDomain, validateIP } from "./utils";
|
||||||
import './App.css';
|
import './App.css';
|
||||||
|
import { IMessage } from "./interfaces";
|
||||||
|
|
||||||
const socket = io(`http://${localStorage.getItem('server-addr') || 'localhost'}:3022`)
|
const socket = io(`http://${localStorage.getItem('server-addr') || 'localhost'}:3022`)
|
||||||
|
|
||||||
@@ -34,20 +35,17 @@ export function App() {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
socket.on('progress', data => {
|
socket.on('progress', (data: IMessage) => {
|
||||||
setMessage(data.trim())
|
setMessage(`${data.status || 'starting'} | progress: ${data.progress || '?'} | size: ${data.size || '?'} | speed: ${data.dlSpeed || '?'}`)
|
||||||
if (data.trim() === 'Done!') {
|
if (data.status === 'Done!') {
|
||||||
setHalt(false)
|
setHalt(false)
|
||||||
|
setMessage('Done!')
|
||||||
setProgress(0)
|
setProgress(0)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
try {
|
setProgress(
|
||||||
const _progress = Math.ceil(data.split(" ")[2].replace('%', ''))
|
Math.ceil(Number(data.progress.replace('%', '')))
|
||||||
if (!isNaN(_progress)) {
|
)
|
||||||
setProgress(_progress)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.warn('finished or empty url or aborted')
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
@@ -63,11 +61,11 @@ export function App() {
|
|||||||
socket.emit('send-url', url)
|
socket.emit('send-url', url)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleUrlChange = (e) => {
|
const handleUrlChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
setUrl(e.target.value)
|
setUrl(e.target.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleAddrChange = (e) => {
|
const handleAddrChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const input = e.target.value;
|
const input = e.target.value;
|
||||||
if (validateIP(input)) {
|
if (validateIP(input)) {
|
||||||
setInvalidIP(false)
|
setInvalidIP(false)
|
||||||
11
frontend/src/interfaces.tsx
Normal file
11
frontend/src/interfaces.tsx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export interface IMessage {
|
||||||
|
status: string,
|
||||||
|
progress?: string,
|
||||||
|
size?: string,
|
||||||
|
dlSpeed?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IDLSpeed {
|
||||||
|
effective: number,
|
||||||
|
unit: string,
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
export function validateIP(ipAddr) {
|
export function validateIP(ipAddr: string): boolean {
|
||||||
let ipRegex = /^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}$/gm
|
let ipRegex = /^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}$/gm
|
||||||
return ipRegex.test(ipAddr)
|
return ipRegex.test(ipAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function validateDomain(domainName) {
|
export function validateDomain(domainName: string): boolean {
|
||||||
let domainRegex = /[^@ \t\r\n]+.[^@ \t\r\n]+\.[^@ \t\r\n]+/
|
let domainRegex = /[^@ \t\r\n]+.[^@ \t\r\n]+\.[^@ \t\r\n]+/
|
||||||
return domainRegex.test(domainName) || domainName === 'localhost'
|
return domainRegex.test(domainName) || domainName === 'localhost'
|
||||||
}
|
}
|
||||||
@@ -17,19 +17,24 @@ const download = (socket, url) => {
|
|||||||
const ytldp = spawn(`./lib/yt-dlp${isWindows ? '.exe' : ''}`,
|
const ytldp = spawn(`./lib/yt-dlp${isWindows ? '.exe' : ''}`,
|
||||||
['-o', `${settings.download_path || 'downloads/'}%(title)s.%(ext)s`, url]
|
['-o', `${settings.download_path || 'downloads/'}%(title)s.%(ext)s`, url]
|
||||||
)
|
)
|
||||||
ytldp.stdout.on('data', data => {
|
|
||||||
// reactive programming magic
|
from(ytldp.stdout) // stout as observable
|
||||||
from(Promise.resolve(data)) // stout as promise => Observable
|
|
||||||
.pipe(throttle(() => interval(500))) // discard events closer than 500ms
|
.pipe(throttle(() => interval(500))) // discard events closer than 500ms
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: () => {
|
next: (stdout) => {
|
||||||
socket.emit('progress', data.toString()) // finally, emit
|
let _stdout = String(stdout)
|
||||||
logger('download', `Fetching ${data.toString()}`)
|
socket.emit('progress', formatter(_stdout)) // finally, emit
|
||||||
|
//logger('download', `Fetching ${stdout}`)
|
||||||
|
console.log(formatter(_stdout))
|
||||||
|
},
|
||||||
|
complete: () => {
|
||||||
|
socket.emit('progress', { status: 'Done!' })
|
||||||
|
logger('download', 'Done!')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
|
||||||
ytldp.on('exit', () => {
|
ytldp.on('exit', () => {
|
||||||
socket.emit('progress', 'Done!')
|
socket.emit('progress', { status: 'Done!' })
|
||||||
logger('download', 'Done!')
|
logger('download', 'Done!')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -45,6 +50,30 @@ const abortDownload = (socket) => {
|
|||||||
logger('download', 'Aborted')
|
logger('download', 'Aborted')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const formatter = (stdout) => {
|
||||||
|
const cleanStdout = stdout
|
||||||
|
.replace(/\s\s+/g, ' ')
|
||||||
|
.split(' ')
|
||||||
|
const status = cleanStdout[0].replace(/\[|\]|\r/g, '')
|
||||||
|
switch (status) {
|
||||||
|
case 'download':
|
||||||
|
return {
|
||||||
|
status: cleanStdout[0].replace(/\[|\]|\r/g, ''),
|
||||||
|
progress: cleanStdout[1],
|
||||||
|
size: cleanStdout[3],
|
||||||
|
dlSpeed: cleanStdout[5],
|
||||||
|
}
|
||||||
|
case 'merger':
|
||||||
|
return {
|
||||||
|
status: 'merging',
|
||||||
|
progress: '100',
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return { progress: '0' }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
download: download,
|
download: download,
|
||||||
abortDownload: abortDownload
|
abortDownload: abortDownload
|
||||||
|
|||||||
Reference in New Issue
Block a user