Refactoring code and structure
This commit is contained in:
@@ -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
4
.gitignore
vendored
@@ -2,8 +2,8 @@
|
||||
dist
|
||||
package-lock.json
|
||||
node_modules
|
||||
lib/*.exe
|
||||
lib/yt-dlp
|
||||
server/*.exe
|
||||
server/yt-dlp
|
||||
.env
|
||||
*.mp4
|
||||
*.ytdl
|
||||
|
||||
@@ -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" ]
|
||||
|
||||
@@ -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"> Extract audio</label>
|
||||
|
||||
<input type="checkbox" name="-nomtime" defaultChecked={cliArgs.noMTime} ref={mtInput}
|
||||
onClick={setNoMTime} />
|
||||
<label htmlFor="-x"> Don't set file modification time</label>
|
||||
</div>
|
||||
</div> :
|
||||
null
|
||||
|
||||
49
frontend/src/classes.ts
Normal file
49
frontend/src/classes.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 || '?'}`;
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user