Refactoring code and structure

This commit is contained in:
2022-01-29 14:48:58 +01:00
parent 416ccab7ef
commit 4d54ea04b9
16 changed files with 132 additions and 44 deletions

View File

@@ -3,8 +3,8 @@ dist
package-lock.json
.parcel-cache
.git
lib/*.exe
lib/yt-dlp
server/*.exe
server/yt-dlp
.env
*.mp4
*.ytdl

4
.gitignore vendored
View File

@@ -2,8 +2,8 @@
dist
package-lock.json
node_modules
lib/*.exe
lib/yt-dlp
server/*.exe
server/yt-dlp
.env
*.mp4
*.ytdl

View File

@@ -9,8 +9,8 @@ RUN apt-get install psmisc
RUN npm install
COPY . .
RUN npm run build
RUN chmod +x ./lib/fetch-yt-dlp.sh
RUN ./lib/fetch-yt-dlp.sh && mv yt-dlp ./lib
RUN chmod +x ./server/fetch-yt-dlp.sh
RUN ./server/fetch-yt-dlp.sh && mv yt-dlp ./server
RUN rm -rf .parcel-cache
EXPOSE 3022
CMD [ "node" , "./server.js" ]

View File

@@ -1,10 +1,9 @@
import { io } from "socket.io-client";
import React, { useState, useEffect, Fragment } from "react";
import React, { useState, useEffect, useRef, Fragment } from "react";
import {
Container,
Row,
Col,
ProgressBar,
InputGroup,
FormControl,
Button,
@@ -15,6 +14,7 @@ import { buildMessage, updateInStateMap, validateDomain, validateIP } from "./ut
import { IDLInfo, IDLInfoBase, IMessage } from "./interfaces";
import { MessageToast } from "./components/MessageToast";
import { StackableResult } from "./components/StackableResult";
import { CliArguments } from "./classes";
import './App.css';
const socket = io(`http://${localStorage.getItem('server-addr') || 'localhost'}:3022`)
@@ -32,7 +32,19 @@ export function App() {
const [updatedBin, setUpdatedBin] = useState(false);
const [showSettings, setShowSettings] = useState(false);
const [darkMode, setDarkMode] = useState(localStorage.getItem('theme') === 'dark');
const [extractAudio, setExtractAudio] = useState(localStorage.getItem('-x') === 'true');
const xaInput = useRef(null);
const mtInput = useRef(null);
/* -------------------- Init ----------------------- */
const cliArgs = new CliArguments();
if (!localStorage.getItem('cliArgs')) {
localStorage.setItem('cliArgs', '')
}
cliArgs.fromString(localStorage.getItem('cliArgs'))
/* -------------------- Effects -------------------- */
@@ -101,9 +113,7 @@ export function App() {
setHalt(true)
socket.emit('send-url', {
url: url,
params: {
xa: extractAudio
},
params: cliArgs.toString(),
})
setUrl('')
const input = document.getElementById('urlInput') as HTMLInputElement;
@@ -112,7 +122,7 @@ export function App() {
/**
* Update the url state whenever the input value changes
* @param {React.ChangeEvent<HTMLInputElement>} e Input change event
* @param e Input change event
*/
const handleUrlChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setUrl(e.target.value)
@@ -121,7 +131,7 @@ export function App() {
/**
* Update the server ip address state and localstorage whenever the input value changes.
* Validate the ip-addr then set.
* @param {React.ChangeEvent<HTMLInputElement>} e Input change event
* @param e Input change event
*/
const handleAddrChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const input = e.target.value;
@@ -138,7 +148,7 @@ export function App() {
/**
* Abort a specific download if id's provided, other wise abort all running ones.
* @param {number} id The download id / pid
* @param id The download id / pid
* @returns void
*/
const abort = (id?: number) => {
@@ -175,13 +185,38 @@ export function App() {
/**
* Handle extract audio checkbox
*/
const toggleExtractAudio = () => {
if (extractAudio) {
localStorage.setItem('-x', 'false')
setExtractAudio(false)
const setExtractAudio = () => {
if (cliArgs.extractAudio) {
xaInput.current.checked = false;
cliArgs.extractAudio = false;
const lStorageItem = localStorage.getItem('cliArgs');
localStorage.setItem('cliArgs', lStorageItem.replace('-x ', ''));
} else {
localStorage.setItem('-x', 'true')
setExtractAudio(true)
xaInput.current.checked = true;
cliArgs.extractAudio = true;
const lStorageItem = localStorage.getItem('cliArgs');
localStorage.setItem('cliArgs', lStorageItem.concat('-x ', ''));
}
}
/**
* Handle no modified time header checkbox
*/
const setNoMTime = () => {
if (cliArgs.noMTime) {
mtInput.current.checked = false;
cliArgs.noMTime = false;
const lStorageItem = localStorage.getItem('cliArgs');
localStorage.setItem('cliArgs', lStorageItem.replace('--no-mtime ', ''));
} else {
mtInput.current.checked = true;
cliArgs.noMTime = true;
const lStorageItem = localStorage.getItem('cliArgs');
localStorage.setItem('cliArgs', lStorageItem.concat('--no-mtime ', ''));
}
}
@@ -276,9 +311,13 @@ export function App() {
{darkMode ? 'Light theme' : 'Dark theme'}
</Button>
<div className="pt-2">
<input type="checkbox" name="-x" id="-x"
onClick={() => toggleExtractAudio()} checked={extractAudio} />
<input type="checkbox" name="-x" defaultChecked={cliArgs.extractAudio} ref={xaInput}
onClick={setExtractAudio} />
<label htmlFor="-x">&nbsp;Extract audio</label>
&nbsp;&nbsp;
<input type="checkbox" name="-nomtime" defaultChecked={cliArgs.noMTime} ref={mtInput}
onClick={setNoMTime} />
<label htmlFor="-x">&nbsp;Don't set file modification time</label>
</div>
</div> :
null

49
frontend/src/classes.ts Normal file
View File

@@ -0,0 +1,49 @@
export class CliArguments {
private _extractAudio: boolean;
private _noMTime: boolean;
constructor() {
this._extractAudio = false;
this._noMTime = false;
}
public get extractAudio(): boolean {
return this._extractAudio;
}
public set extractAudio(v: boolean) {
this._extractAudio = v;
}
public get noMTime(): boolean {
return this._noMTime;
}
public set noMTime(v: boolean) {
this._noMTime = v;
}
public toString(): string {
let args = '';
if (this._extractAudio) {
args += '-x '
}
if (this._noMTime) {
args += '--no-mtime '
}
return args.trim();
}
public fromString(str: string): void {
if (str.includes('-x')) {
this._extractAudio = true;
}
if (str.includes('--no-mtime')) {
this._noMTime = true;
}
}
}

View File

@@ -51,11 +51,11 @@ export function detectSpeed(str: string): number {
/**
* Update a map stored in React State, in this specific impl. all maps have integer keys
* @param {num} k Map key
* @param {*} v Map value
* @param {Map<number, any>} target The target map saved in-state
* @param {Function} callback calls React's StateAction function with the newly created Map
* @param {boolean} remove -optional- is it an update or a deletion operation?
* @param k Map key
* @param v Map value
* @param target The target map saved in-state
* @param callback calls React's StateAction function with the newly created Map
* @param remove -optional- is it an update or a deletion operation?
*/
export const updateInStateMap = (k: number, v: any, target: Map<number, any>, callback: Function, remove: boolean = false) => {
if (remove) {
@@ -69,7 +69,7 @@ export const updateInStateMap = (k: number, v: any, target: Map<number, any>, ca
/**
* Pre like function
* @param data
* @returns
* @returns formatted server message
*/
export function buildMessage(data: IMessage) {
return `operation: ${data.status || '...'} \nprogress: ${data.progress || '?'} \nsize: ${data.size || '?'} \nspeed: ${data.dlSpeed || '?'}`;

View File

@@ -7,7 +7,7 @@
"dev": "nodemon app.js",
"build": "parcel build ./frontend/index.html",
"fe": "parcel ./frontend/index.html --open",
"fetch": "./lib/fetch-yt-dlp.sh && mv yt-dlp ./lib"
"fetch": "./server/fetch-yt-dlp.sh && mv yt-dlp ./server"
},
"author": "marcobaobao",
"license": "ISC",

View File

@@ -1,18 +1,18 @@
const Koa = require('koa'),
serve = require('koa-static'),
cors = require('@koa/cors'),
{ logger, splash } = require('./lib/logger'),
{ logger, splash } = require('./server/logger'),
{ join } = require('path'),
{ Server } = require('socket.io'),
{ createServer } = require('http'),
{ ytdlpUpdater } = require('./lib/updater'),
{ ytdlpUpdater } = require('./server/updater'),
{
download,
abortDownload,
retriveDownload,
abortAllDownloads,
} = require('./lib/downloader'),
db = require('./lib/db');
} = require('./server/downloader'),
db = require('./server/db');
const app = new Koa()
const server = createServer(app.callback())

View File

@@ -6,7 +6,7 @@ const { logger } = require('./logger');
* Represents a download process that spawns yt-dlp.
* @constructor
* @param {string} url - The downlaod url.
* @param {string} params - The cli arguments passed by the frontend.
* @param {Array<String>} params - The cli arguments passed by the frontend.
* @param {*} settings - The download settings passed by the frontend.
*/
@@ -28,12 +28,10 @@ class Process {
async start(callback) {
await this.#__internalGetInfo();
const ytldp = spawn('./lib/yt-dlp',
[
'-o', `${this.settings?.download_path || 'downloads/'}%(title)s.%(ext)s`,
this.params,
this.url
]
const ytldp = spawn('./server/yt-dlp',
['-o', `${this.settings?.download_path || 'downloads/'}%(title)s.%(ext)s`]
.concat(this.params)
.concat([this.url])
);
this.pid = ytldp.pid;
@@ -54,7 +52,7 @@ class Process {
async #__internalGetInfo() {
let lock = true;
let stdoutChunks = [];
const ytdlpInfo = spawn('./lib/yt-dlp', ['-s', '-j', this.url]);
const ytdlpInfo = spawn('./server/yt-dlp', ['-s', '-j', this.url]);
ytdlpInfo.stdout.on('data', (data) => {
stdoutChunks.push(data);

View File

@@ -34,8 +34,10 @@ async function download(socket, payload) {
return;
}
const url = payload.url
const params = payload.params?.xa ? '-x' : '';
const url = payload.url;
const params = payload.params.split(' ');
console.log(params)
const p = new Process(url, params, settings);