server migration to TypeScript
This commit is contained in:
@@ -1,10 +1,11 @@
|
|||||||
node_modules
|
node_modules
|
||||||
dist
|
dist
|
||||||
package-lock.json
|
package-lock.json
|
||||||
|
pnpm-lock.yaml
|
||||||
.parcel-cache
|
.parcel-cache
|
||||||
.git
|
.git
|
||||||
server/*.exe
|
src/server/core/*.exe
|
||||||
server/yt-dlp
|
src/server/core/yt-dlp
|
||||||
.env
|
.env
|
||||||
*.mp4
|
*.mp4
|
||||||
*.ytdl
|
*.ytdl
|
||||||
|
|||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,9 +1,10 @@
|
|||||||
.parcel-cache
|
.parcel-cache
|
||||||
dist
|
dist
|
||||||
package-lock.json
|
package-lock.json
|
||||||
|
pnpm-lock.yaml
|
||||||
node_modules
|
node_modules
|
||||||
server/*.exe
|
src/server/core/*.exe
|
||||||
server/yt-dlp
|
src/server/core/yt-dlp
|
||||||
.env
|
.env
|
||||||
*.mp4
|
*.mp4
|
||||||
*.ytdl
|
*.ytdl
|
||||||
|
|||||||
@@ -8,9 +8,8 @@ RUN apt-get install curl ffmpeg -y
|
|||||||
RUN apt-get install psmisc
|
RUN apt-get install psmisc
|
||||||
RUN npm install
|
RUN npm install
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN npm run build
|
RUN chmod +x ./fetch-yt-dlp.sh
|
||||||
RUN chmod +x ./server/fetch-yt-dlp.sh
|
RUN npm run build-all
|
||||||
RUN ./server/fetch-yt-dlp.sh && mv yt-dlp ./server
|
|
||||||
RUN rm -rf .parcel-cache
|
RUN rm -rf .parcel-cache
|
||||||
EXPOSE 3022
|
EXPOSE 3022
|
||||||
CMD [ "node" , "./server.js" ]
|
CMD [ "node" , "./dist/main.js" ]
|
||||||
|
|||||||
19
package.json
19
package.json
@@ -1,18 +1,29 @@
|
|||||||
{
|
{
|
||||||
"name": "youtube-dlp-web",
|
"name": "yt-dlp-webui",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"description": "A terrible webUI for yt-dlp, all-in-one solution.",
|
"description": "A terrible webUI for yt-dlp, all-in-one solution.",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node server.js",
|
"start": "node server.js",
|
||||||
"dev": "nodemon app.js",
|
"dev": "nodemon app.js",
|
||||||
"build": "parcel build ./frontend/index.html",
|
"build": "parcel build ./frontend/index.html --dist-dir ./dist/frontend",
|
||||||
|
"build-server": "tsc --build",
|
||||||
|
"build-all": "tsc --build && npm run build && npm run fetch",
|
||||||
|
"clean": "tsc --build --clean",
|
||||||
|
"clean-all": "rm -r dist",
|
||||||
"fe": "parcel ./frontend/index.html --open",
|
"fe": "parcel ./frontend/index.html --open",
|
||||||
"fetch": "./server/fetch-yt-dlp.sh && mv yt-dlp ./server"
|
"fetch-dev": "./fetch-yt-dlp.sh && mv yt-dlp ./server/core",
|
||||||
|
"fetch": "./fetch-yt-dlp.sh && mv yt-dlp ./dist/core"
|
||||||
},
|
},
|
||||||
"author": "marcobaobao",
|
"author": "marcobaobao",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@koa/cors": "^3.1.0",
|
"@koa/cors": "^3.1.0",
|
||||||
|
"@types/better-sqlite3": "^7.4.2",
|
||||||
|
"@types/koa": "^2.13.4",
|
||||||
|
"@types/koa-static": "^4.0.2",
|
||||||
|
"@types/koa__cors": "^3.1.1",
|
||||||
|
"@types/node": "^17.0.13",
|
||||||
|
"@types/uuid": "^8.3.4",
|
||||||
"better-sqlite3": "^7.4.5",
|
"better-sqlite3": "^7.4.5",
|
||||||
"chart.js": "^3.6.0",
|
"chart.js": "^3.6.0",
|
||||||
"koa": "^2.13.4",
|
"koa": "^2.13.4",
|
||||||
|
|||||||
148
pnpm-lock.yaml
generated
148
pnpm-lock.yaml
generated
@@ -2,6 +2,12 @@ lockfileVersion: 5.3
|
|||||||
|
|
||||||
specifiers:
|
specifiers:
|
||||||
'@koa/cors': ^3.1.0
|
'@koa/cors': ^3.1.0
|
||||||
|
'@types/better-sqlite3': ^7.4.2
|
||||||
|
'@types/koa': ^2.13.4
|
||||||
|
'@types/koa-static': ^4.0.2
|
||||||
|
'@types/koa__cors': ^3.1.1
|
||||||
|
'@types/node': ^17.0.13
|
||||||
|
'@types/uuid': ^8.3.4
|
||||||
better-sqlite3: ^7.4.5
|
better-sqlite3: ^7.4.5
|
||||||
chart.js: ^3.6.0
|
chart.js: ^3.6.0
|
||||||
koa: ^2.13.4
|
koa: ^2.13.4
|
||||||
@@ -22,6 +28,12 @@ specifiers:
|
|||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
'@koa/cors': 3.1.0
|
'@koa/cors': 3.1.0
|
||||||
|
'@types/better-sqlite3': 7.4.2
|
||||||
|
'@types/koa': 2.13.4
|
||||||
|
'@types/koa-static': 4.0.2
|
||||||
|
'@types/koa__cors': 3.1.1
|
||||||
|
'@types/node': 17.0.13
|
||||||
|
'@types/uuid': 8.3.4
|
||||||
better-sqlite3: 7.5.0
|
better-sqlite3: 7.5.0
|
||||||
chart.js: 3.7.0
|
chart.js: 3.7.0
|
||||||
koa: 2.13.4
|
koa: 2.13.4
|
||||||
@@ -1162,30 +1174,139 @@ packages:
|
|||||||
engines: {node: '>=10.13.0'}
|
engines: {node: '>=10.13.0'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@types/accepts/1.3.5:
|
||||||
|
resolution: {integrity: sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ==}
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 17.0.13
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/better-sqlite3/7.4.2:
|
||||||
|
resolution: {integrity: sha512-HUXWMOmRgOrXJ0SKt6kxqUaZtGkr0HCuaEt/76LojT6bkTu0lb0uhr3K1su9T09mskDKyQwNMvT7WithFN10PQ==}
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 17.0.13
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/body-parser/1.19.2:
|
||||||
|
resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==}
|
||||||
|
dependencies:
|
||||||
|
'@types/connect': 3.4.35
|
||||||
|
'@types/node': 17.0.13
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/component-emitter/1.2.11:
|
/@types/component-emitter/1.2.11:
|
||||||
resolution: {integrity: sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ==}
|
resolution: {integrity: sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@types/connect/3.4.35:
|
||||||
|
resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==}
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 17.0.13
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/content-disposition/0.5.4:
|
||||||
|
resolution: {integrity: sha512-0mPF08jn9zYI0n0Q/Pnz7C4kThdSt+6LD4amsrYDDpgBfrVWa3TcCOxKX1zkGgYniGagRv8heN2cbh+CAn+uuQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/cookie/0.4.1:
|
/@types/cookie/0.4.1:
|
||||||
resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==}
|
resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@types/cookies/0.7.7:
|
||||||
|
resolution: {integrity: sha512-h7BcvPUogWbKCzBR2lY4oqaZbO3jXZksexYJVFvkrFeLgbZjQkU4x8pRq6eg2MHXQhY0McQdqmmsxRWlVAHooA==}
|
||||||
|
dependencies:
|
||||||
|
'@types/connect': 3.4.35
|
||||||
|
'@types/express': 4.17.13
|
||||||
|
'@types/keygrip': 1.0.2
|
||||||
|
'@types/node': 17.0.13
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/cors/2.8.12:
|
/@types/cors/2.8.12:
|
||||||
resolution: {integrity: sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==}
|
resolution: {integrity: sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@types/express-serve-static-core/4.17.28:
|
||||||
|
resolution: {integrity: sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==}
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 17.0.13
|
||||||
|
'@types/qs': 6.9.7
|
||||||
|
'@types/range-parser': 1.2.4
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/express/4.17.13:
|
||||||
|
resolution: {integrity: sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==}
|
||||||
|
dependencies:
|
||||||
|
'@types/body-parser': 1.19.2
|
||||||
|
'@types/express-serve-static-core': 4.17.28
|
||||||
|
'@types/qs': 6.9.7
|
||||||
|
'@types/serve-static': 1.13.10
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/http-assert/1.5.3:
|
||||||
|
resolution: {integrity: sha512-FyAOrDuQmBi8/or3ns4rwPno7/9tJTijVW6aQQjK02+kOQ8zmoNg2XJtAuQhvQcy1ASJq38wirX5//9J1EqoUA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/http-errors/1.8.2:
|
||||||
|
resolution: {integrity: sha512-EqX+YQxINb+MeXaIqYDASb6U6FCHbWjkj4a1CKDBks3d/QiB2+PqBLyO72vLDgAO1wUI4O+9gweRcQK11bTL/w==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/http-proxy/1.17.8:
|
/@types/http-proxy/1.17.8:
|
||||||
resolution: {integrity: sha512-5kPLG5BKpWYkw/LVOGWpiq3nEVqxiN32rTgI53Sk12/xHFQ2rG3ehI9IO+O3W2QoKeyB92dJkoka8SUm6BX1pA==}
|
resolution: {integrity: sha512-5kPLG5BKpWYkw/LVOGWpiq3nEVqxiN32rTgI53Sk12/xHFQ2rG3ehI9IO+O3W2QoKeyB92dJkoka8SUm6BX1pA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 17.0.12
|
'@types/node': 17.0.13
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@types/invariant/2.2.35:
|
/@types/invariant/2.2.35:
|
||||||
resolution: {integrity: sha512-DxX1V9P8zdJPYQat1gHyY0xj3efl8gnMVjiM9iCY6y27lj+PoQWkgjt8jDqmovPqULkKVpKRg8J36iQiA+EtEg==}
|
resolution: {integrity: sha512-DxX1V9P8zdJPYQat1gHyY0xj3efl8gnMVjiM9iCY6y27lj+PoQWkgjt8jDqmovPqULkKVpKRg8J36iQiA+EtEg==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@types/node/17.0.12:
|
/@types/keygrip/1.0.2:
|
||||||
resolution: {integrity: sha512-4YpbAsnJXWYK/fpTVFlMIcUIho2AYCi4wg5aNPrG1ng7fn/1/RZfCIpRCiBX+12RVa34RluilnvCqD+g3KiSiA==}
|
resolution: {integrity: sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/koa-compose/3.2.5:
|
||||||
|
resolution: {integrity: sha512-B8nG/OoE1ORZqCkBVsup/AKcvjdgoHnfi4pZMn5UwAPCbhk/96xyv284eBYW8JlQbQ7zDmnpFr68I/40mFoIBQ==}
|
||||||
|
dependencies:
|
||||||
|
'@types/koa': 2.13.4
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/koa-send/4.1.3:
|
||||||
|
resolution: {integrity: sha512-daaTqPZlgjIJycSTNjKpHYuKhXYP30atFc1pBcy6HHqB9+vcymDgYTguPdx9tO4HMOqNyz6bz/zqpxt5eLR+VA==}
|
||||||
|
dependencies:
|
||||||
|
'@types/koa': 2.13.4
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/koa-static/4.0.2:
|
||||||
|
resolution: {integrity: sha512-ns/zHg+K6XVPMuohjpOlpkR1WLa4VJ9czgUP9bxkCDn0JZBtUWbD/wKDZzPGDclkQK1bpAEScufCHOy8cbfL0w==}
|
||||||
|
dependencies:
|
||||||
|
'@types/koa': 2.13.4
|
||||||
|
'@types/koa-send': 4.1.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/koa/2.13.4:
|
||||||
|
resolution: {integrity: sha512-dfHYMfU+z/vKtQB7NUrthdAEiSvnLebvBjwHtfFmpZmB7em2N3WVQdHgnFq+xvyVgxW5jKDmjWfLD3lw4g4uTw==}
|
||||||
|
dependencies:
|
||||||
|
'@types/accepts': 1.3.5
|
||||||
|
'@types/content-disposition': 0.5.4
|
||||||
|
'@types/cookies': 0.7.7
|
||||||
|
'@types/http-assert': 1.5.3
|
||||||
|
'@types/http-errors': 1.8.2
|
||||||
|
'@types/keygrip': 1.0.2
|
||||||
|
'@types/koa-compose': 3.2.5
|
||||||
|
'@types/node': 17.0.13
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/koa__cors/3.1.1:
|
||||||
|
resolution: {integrity: sha512-O7MBkCocnLrpEvkMrYAp17arUDS+KuS5bXMG/Z4aPSbrO7vrYB6YrqcsTD3Dp2OnAL3j4WME2k/x2kOcyzwNUw==}
|
||||||
|
dependencies:
|
||||||
|
'@types/koa': 2.13.4
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/mime/1.3.2:
|
||||||
|
resolution: {integrity: sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/node/17.0.13:
|
||||||
|
resolution: {integrity: sha512-Y86MAxASe25hNzlDbsviXl8jQHb0RDvKt4c40ZJQ1Don0AAL0STLZSs4N+6gLEO55pedy7r2cLwS+ZDxPm/2Bw==}
|
||||||
|
|
||||||
/@types/parse-json/4.0.0:
|
/@types/parse-json/4.0.0:
|
||||||
resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==}
|
resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==}
|
||||||
@@ -1195,6 +1316,14 @@ packages:
|
|||||||
resolution: {integrity: sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==}
|
resolution: {integrity: sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@types/qs/6.9.7:
|
||||||
|
resolution: {integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/range-parser/1.2.4:
|
||||||
|
resolution: {integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/react-transition-group/4.4.4:
|
/@types/react-transition-group/4.4.4:
|
||||||
resolution: {integrity: sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug==}
|
resolution: {integrity: sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -1213,6 +1342,17 @@ packages:
|
|||||||
resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==}
|
resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@types/serve-static/1.13.10:
|
||||||
|
resolution: {integrity: sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==}
|
||||||
|
dependencies:
|
||||||
|
'@types/mime': 1.3.2
|
||||||
|
'@types/node': 17.0.13
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/uuid/8.3.4:
|
||||||
|
resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/warning/3.0.0:
|
/@types/warning/3.0.0:
|
||||||
resolution: {integrity: sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI=}
|
resolution: {integrity: sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI=}
|
||||||
dev: false
|
dev: false
|
||||||
@@ -2101,7 +2241,7 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@types/cookie': 0.4.1
|
'@types/cookie': 0.4.1
|
||||||
'@types/cors': 2.8.12
|
'@types/cors': 2.8.12
|
||||||
'@types/node': 17.0.12
|
'@types/node': 17.0.13
|
||||||
accepts: 1.3.7
|
accepts: 1.3.7
|
||||||
base64id: 2.0.0
|
base64id: 2.0.0
|
||||||
cookie: 0.4.1
|
cookie: 0.4.1
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
const { spawn } = require('child_process');
|
import { spawn } from 'child_process';
|
||||||
const { deleteDownloadByPID, insertDownload } = require('./db');
|
import { join } from 'path';
|
||||||
const { logger } = require('./logger');
|
import { Readable } from 'stream';
|
||||||
|
import { deleteDownloadByPID, insertDownload } from '../db/db';
|
||||||
|
import Logger from '../utils/BetterLogger';
|
||||||
|
|
||||||
|
const log = new Logger();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a download process that spawns yt-dlp.
|
* Represents a download process that spawns yt-dlp.
|
||||||
@@ -11,9 +15,18 @@ const { logger } = require('./logger');
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class Process {
|
class Process {
|
||||||
constructor(url, params, settings) {
|
private url: string;
|
||||||
|
private params: Array<string>;
|
||||||
|
private settings: any;
|
||||||
|
private stdout: Readable;
|
||||||
|
private pid: number;
|
||||||
|
private info: any;
|
||||||
|
private lock: boolean;
|
||||||
|
private exePath = join(__dirname, 'yt-dlp');
|
||||||
|
|
||||||
|
constructor(url: string, params: Array<string>, settings: any) {
|
||||||
this.url = url;
|
this.url = url;
|
||||||
this.params = params || ' ';
|
this.params = params || [];
|
||||||
this.settings = settings
|
this.settings = settings
|
||||||
this.stdout = undefined;
|
this.stdout = undefined;
|
||||||
this.pid = undefined;
|
this.pid = undefined;
|
||||||
@@ -25,10 +38,10 @@ class Process {
|
|||||||
* @param {Function} callback not yet implemented
|
* @param {Function} callback not yet implemented
|
||||||
* @returns {Promise<this>} the process instance
|
* @returns {Promise<this>} the process instance
|
||||||
*/
|
*/
|
||||||
async start(callback) {
|
async start(callback?: Function): Promise<this> {
|
||||||
await this.#__internalGetInfo();
|
await this.#__internalGetInfo();
|
||||||
|
|
||||||
const ytldp = spawn('./server/yt-dlp',
|
const ytldp = spawn(this.exePath,
|
||||||
['-o', `${this.settings?.download_path || 'downloads/'}%(title)s.%(ext)s`]
|
['-o', `${this.settings?.download_path || 'downloads/'}%(title)s.%(ext)s`]
|
||||||
.concat(this.params)
|
.concat(this.params)
|
||||||
.concat([this.url])
|
.concat([this.url])
|
||||||
@@ -37,9 +50,9 @@ class Process {
|
|||||||
this.pid = ytldp.pid;
|
this.pid = ytldp.pid;
|
||||||
this.stdout = ytldp.stdout;
|
this.stdout = ytldp.stdout;
|
||||||
|
|
||||||
logger('proc', `Spawned a new process, pid: ${this.pid}`)
|
log.info('proc', `Spawned a new process, pid: ${this.pid}`)
|
||||||
|
|
||||||
await insertDownload(this.url, null, null, null, this.pid);
|
await insertDownload(this.url, this.info?.title, this.info?.thumbnail, null, this.pid);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -52,7 +65,7 @@ class Process {
|
|||||||
async #__internalGetInfo() {
|
async #__internalGetInfo() {
|
||||||
let lock = true;
|
let lock = true;
|
||||||
let stdoutChunks = [];
|
let stdoutChunks = [];
|
||||||
const ytdlpInfo = spawn('./server/yt-dlp', ['-s', '-j', this.url]);
|
const ytdlpInfo = spawn(this.exePath, ['-s', '-j', this.url]);
|
||||||
|
|
||||||
ytdlpInfo.stdout.on('data', (data) => {
|
ytdlpInfo.stdout.on('data', (data) => {
|
||||||
stdoutChunks.push(data);
|
stdoutChunks.push(data);
|
||||||
@@ -82,9 +95,9 @@ class Process {
|
|||||||
* function that kills the current process
|
* function that kills the current process
|
||||||
*/
|
*/
|
||||||
async kill() {
|
async kill() {
|
||||||
spawn('kill', [this.pid]).on('exit', () => {
|
spawn('kill', [String(this.pid)]).on('exit', () => {
|
||||||
deleteDownloadByPID(this.pid).then(() => {
|
deleteDownloadByPID(this.pid).then(() => {
|
||||||
logger('db', `Deleted ${this.pid} because SIGKILL`)
|
log.info('db', `Deleted ${this.pid} because SIGKILL`)
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -93,7 +106,7 @@ class Process {
|
|||||||
* pid getter function
|
* pid getter function
|
||||||
* @returns {number} pid
|
* @returns {number} pid
|
||||||
*/
|
*/
|
||||||
getPid() {
|
getPid(): number {
|
||||||
if (!this.pid) {
|
if (!this.pid) {
|
||||||
throw "Process isn't started"
|
throw "Process isn't started"
|
||||||
}
|
}
|
||||||
@@ -102,9 +115,9 @@ class Process {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* stdout getter function
|
* stdout getter function
|
||||||
* @returns {ReadableStream} stdout as stream
|
* @returns {Readable} stdout as stream
|
||||||
*/
|
*/
|
||||||
getStdout() {
|
getStdout(): Readable {
|
||||||
return this.stdout
|
return this.stdout
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,9 +125,9 @@ class Process {
|
|||||||
* download info getter function
|
* download info getter function
|
||||||
* @returns {object}
|
* @returns {object}
|
||||||
*/
|
*/
|
||||||
getInfo() {
|
getInfo(): object {
|
||||||
return this.info
|
return this.info
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Process;
|
export default Process;
|
||||||
@@ -3,7 +3,12 @@
|
|||||||
* Represents a download process that spawns yt-dlp.
|
* Represents a download process that spawns yt-dlp.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import Process from "./Process";
|
||||||
|
|
||||||
class ProcessPool {
|
class ProcessPool {
|
||||||
|
private _pool: Map<number, Process>;
|
||||||
|
private _size: number;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this._pool = new Map();
|
this._pool = new Map();
|
||||||
this._size = 0;
|
this._size = 0;
|
||||||
@@ -13,7 +18,7 @@ class ProcessPool {
|
|||||||
* Pool size getter
|
* Pool size getter
|
||||||
* @returns {number} pool's size
|
* @returns {number} pool's size
|
||||||
*/
|
*/
|
||||||
size() {
|
size(): number {
|
||||||
return this._size;
|
return this._size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,7 +26,7 @@ class ProcessPool {
|
|||||||
* Add a process to the pool
|
* Add a process to the pool
|
||||||
* @param {Process} process
|
* @param {Process} process
|
||||||
*/
|
*/
|
||||||
add(process) {
|
add(process: Process) {
|
||||||
this._pool.set(process.getPid(), process)
|
this._pool.set(process.getPid(), process)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,7 +34,7 @@ class ProcessPool {
|
|||||||
* Delete a process from the pool
|
* Delete a process from the pool
|
||||||
* @param {Process} process
|
* @param {Process} process
|
||||||
*/
|
*/
|
||||||
remove(process) {
|
remove(process: Process) {
|
||||||
this._pool.delete(process.getPid())
|
this._pool.delete(process.getPid())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,7 +42,7 @@ class ProcessPool {
|
|||||||
* Delete a process from the pool by its pid
|
* Delete a process from the pool by its pid
|
||||||
* @param {number} pid
|
* @param {number} pid
|
||||||
*/
|
*/
|
||||||
removeByPid(pid) {
|
removeByPid(pid: number) {
|
||||||
this._pool.delete(pid)
|
this._pool.delete(pid)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +50,7 @@ class ProcessPool {
|
|||||||
* get an iterator for the pool
|
* get an iterator for the pool
|
||||||
* @returns {IterableIterator} iterator
|
* @returns {IterableIterator} iterator
|
||||||
*/
|
*/
|
||||||
iterator() {
|
iterator(): IterableIterator<[number, Process]> {
|
||||||
return this._pool.entries()
|
return this._pool.entries()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,9 +59,9 @@ class ProcessPool {
|
|||||||
* @param {number} pid
|
* @param {number} pid
|
||||||
* @returns {Process}
|
* @returns {Process}
|
||||||
*/
|
*/
|
||||||
getByPid(pid) {
|
getByPid(pid: number): Process {
|
||||||
return this._pool.get(pid)
|
return this._pool.get(pid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = ProcessPool;
|
export default ProcessPool;
|
||||||
@@ -1,16 +1,18 @@
|
|||||||
const { spawn } = require('child_process');
|
import { spawn } from 'child_process';
|
||||||
const { from, interval } = require('rxjs');
|
import { from, interval } from 'rxjs';
|
||||||
const { throttle } = require('rxjs/operators');
|
import { throttle } from 'rxjs/operators';
|
||||||
const { Socket } = require('socket.io');
|
import { pruneDownloads } from '../db/db';
|
||||||
const { pruneDownloads } = require('./db');
|
import { killProcess } from '../utils/procUtils';
|
||||||
const { logger } = require('./logger');
|
import Logger from '../utils/BetterLogger';
|
||||||
const Process = require('./Process');
|
import Process from './Process';
|
||||||
const ProcessPool = require('./ProcessPool');
|
import ProcessPool from './ProcessPool';
|
||||||
const { killProcess } = require('./procUtils');
|
import { Socket } from 'socket.io';
|
||||||
|
import { IPayload } from '../interfaces/IPayload';
|
||||||
|
|
||||||
// settings read from settings.json
|
// settings read from settings.json
|
||||||
let settings;
|
let settings;
|
||||||
let coldRestart = true;
|
let coldRestart = true;
|
||||||
|
const log = new Logger();
|
||||||
|
|
||||||
const pool = new ProcessPool();
|
const pool = new ProcessPool();
|
||||||
|
|
||||||
@@ -28,7 +30,7 @@ catch (e) {
|
|||||||
* @param {object} payload frontend download payload
|
* @param {object} payload frontend download payload
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async function download(socket, payload) {
|
export async function download(socket: Socket, payload: IPayload) {
|
||||||
if (!payload || payload.url === '' || payload.url === null) {
|
if (!payload || payload.url === '' || payload.url === null) {
|
||||||
socket.emit('progress', { status: 'Done!' });
|
socket.emit('progress', { status: 'Done!' });
|
||||||
return;
|
return;
|
||||||
@@ -87,14 +89,14 @@ async function download(socket, payload) {
|
|||||||
* @param {Socket} socket current connection socket
|
* @param {Socket} socket current connection socket
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async function retriveDownload(socket) {
|
export async function retriveDownload(socket: Socket) {
|
||||||
// it's a cold restart: the server has just been started with pending
|
// it's a cold restart: the server has just been started with pending
|
||||||
// downloads, so fetch them from the database and resume.
|
// downloads, so fetch them from the database and resume.
|
||||||
if (coldRestart) {
|
if (coldRestart) {
|
||||||
coldRestart = false;
|
coldRestart = false;
|
||||||
let downloads = await pruneDownloads();
|
let downloads = await pruneDownloads();
|
||||||
downloads = [... new Set(downloads)];
|
downloads = [... new Set(downloads)];
|
||||||
logger('dl', `Cold restart, retrieving ${downloads.length} jobs`)
|
log.info('dl', `Cold restart, retrieving ${downloads.length} jobs`)
|
||||||
for (const entry of downloads) {
|
for (const entry of downloads) {
|
||||||
if (entry) {
|
if (entry) {
|
||||||
await download(socket, entry);
|
await download(socket, entry);
|
||||||
@@ -105,10 +107,10 @@ async function retriveDownload(socket) {
|
|||||||
|
|
||||||
// it's an hot-reload the server it's running and the frontend ask for
|
// it's an hot-reload the server it's running and the frontend ask for
|
||||||
// the pending job: retrieve them from the "in-memory database" (ProcessPool)
|
// the pending job: retrieve them from the "in-memory database" (ProcessPool)
|
||||||
logger('dl', `Retrieving jobs ${pool.size()} from pool`)
|
log.info('dl', `Retrieving ${pool.size()} jobs from pool`)
|
||||||
|
|
||||||
const it = pool.iterator();
|
const it = pool.iterator();
|
||||||
tempWorkQueue = new Array();
|
const tempWorkQueue = new Array();
|
||||||
|
|
||||||
// sanitize
|
// sanitize
|
||||||
for (const entry of it) {
|
for (const entry of it) {
|
||||||
@@ -135,7 +137,7 @@ async function retriveDownload(socket) {
|
|||||||
* @param {*} args args sent by the frontend. MUST contain the PID.
|
* @param {*} args args sent by the frontend. MUST contain the PID.
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
function abortDownload(socket, args) {
|
export function abortDownload(socket: Socket, args: any) {
|
||||||
if (!args) {
|
if (!args) {
|
||||||
abortAllDownloads(socket);
|
abortAllDownloads(socket);
|
||||||
return;
|
return;
|
||||||
@@ -148,7 +150,7 @@ function abortDownload(socket, args) {
|
|||||||
status: 'Aborted',
|
status: 'Aborted',
|
||||||
process: pid,
|
process: pid,
|
||||||
});
|
});
|
||||||
logger('dl', `Aborting download ${pid}`);
|
log.warn('dl', `Aborting download ${pid}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,11 +158,11 @@ function abortDownload(socket, args) {
|
|||||||
* Unconditionally kills all yt-dlp process.
|
* Unconditionally kills all yt-dlp process.
|
||||||
* @param {Socket} socket currenct connection socket
|
* @param {Socket} socket currenct connection socket
|
||||||
*/
|
*/
|
||||||
function abortAllDownloads(socket) {
|
export function abortAllDownloads(socket: Socket) {
|
||||||
spawn('killall', ['yt-dlp'])
|
spawn('killall', ['yt-dlp'])
|
||||||
.on('exit', () => {
|
.on('exit', () => {
|
||||||
socket.emit('progress', { status: 'Aborted' });
|
socket.emit('progress', { status: 'Aborted' });
|
||||||
logger('dl', 'Aborting downloads');
|
log.info('dl', 'Aborting downloads');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,7 +172,7 @@ function abortAllDownloads(socket) {
|
|||||||
* @param {number} pid current process id relative to stdout
|
* @param {number} pid current process id relative to stdout
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const formatter = (stdout, pid) => {
|
const formatter = (stdout: string, pid: number) => {
|
||||||
const cleanStdout = stdout
|
const cleanStdout = stdout
|
||||||
.replace(/\s\s+/g, ' ')
|
.replace(/\s\s+/g, ' ')
|
||||||
.split(' ');
|
.split(' ');
|
||||||
@@ -193,10 +195,3 @@ const formatter = (stdout, pid) => {
|
|||||||
return { progress: '0' }
|
return { progress: '0' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
download: download,
|
|
||||||
abortDownload: abortDownload,
|
|
||||||
abortAllDownloads: abortAllDownloads,
|
|
||||||
retriveDownload: retriveDownload,
|
|
||||||
}
|
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
const uuid = require('uuid')
|
import { v1 } from 'uuid';
|
||||||
const { logger } = require('./logger')
|
import { existsInProc } from '../utils/procUtils';
|
||||||
const { existsInProc } = require('./procUtils')
|
import Logger from '../utils/BetterLogger';
|
||||||
|
const db = require('better-sqlite3')('downloads.db');
|
||||||
|
|
||||||
const db = require('better-sqlite3')('downloads.db')
|
const log = new Logger();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inits the repository, the tables.
|
* Inits the repository, the tables.
|
||||||
*/
|
*/
|
||||||
async function init() {
|
export async function init() {
|
||||||
try {
|
try {
|
||||||
db.exec(`CREATE TABLE downloads (
|
db.exec(`CREATE TABLE downloads (
|
||||||
uid varchar(36) NOT NULL,
|
uid varchar(36) NOT NULL,
|
||||||
@@ -20,7 +21,7 @@ async function init() {
|
|||||||
PRIMARY KEY (uid)
|
PRIMARY KEY (uid)
|
||||||
)`)
|
)`)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger('db', 'Table already created, ignoring')
|
log.warn('db', 'Table already created, ignoring')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,7 +29,7 @@ async function init() {
|
|||||||
* Get an instance of the db.
|
* Get an instance of the db.
|
||||||
* @returns {BetterSqlite3.Database} Current database instance
|
* @returns {BetterSqlite3.Database} Current database instance
|
||||||
*/
|
*/
|
||||||
async function get_db() {
|
export async function get_db(): Promise<any> {
|
||||||
return db
|
return db
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,8 +42,8 @@ async function get_db() {
|
|||||||
* @param {number} PID the pid of the downloader
|
* @param {number} PID the pid of the downloader
|
||||||
* @returns {Promise<string>} the download UUID
|
* @returns {Promise<string>} the download UUID
|
||||||
*/
|
*/
|
||||||
async function insertDownload(url, title, thumbnail, size, PID) {
|
export async function insertDownload(url: string, title: string, thumbnail: string, size: string, PID: number): Promise<string> {
|
||||||
const uid = uuid.v1()
|
const uid = v1()
|
||||||
try {
|
try {
|
||||||
db
|
db
|
||||||
.prepare(`
|
.prepare(`
|
||||||
@@ -52,7 +53,7 @@ async function insertDownload(url, title, thumbnail, size, PID) {
|
|||||||
)
|
)
|
||||||
.run(uid, url, title, thumbnail, size, PID)
|
.run(uid, url, title, thumbnail, size, PID)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger('db', 'some error occourred')
|
log.err('db', 'some error occourred')
|
||||||
}
|
}
|
||||||
|
|
||||||
return uid
|
return uid
|
||||||
@@ -62,7 +63,7 @@ async function insertDownload(url, title, thumbnail, size, PID) {
|
|||||||
* Retrieve all downloads from the database
|
* Retrieve all downloads from the database
|
||||||
* @returns {ArrayLike} a collection of results
|
* @returns {ArrayLike} a collection of results
|
||||||
*/
|
*/
|
||||||
async function retrieveAll() {
|
export async function retrieveAll(): Promise<any> {
|
||||||
return db
|
return db
|
||||||
.prepare('SELECT * FROM downloads')
|
.prepare('SELECT * FROM downloads')
|
||||||
.all()
|
.all()
|
||||||
@@ -72,7 +73,7 @@ async function retrieveAll() {
|
|||||||
* Delete a download by its uuid
|
* Delete a download by its uuid
|
||||||
* @param {string} uid the to-be-deleted download uuid
|
* @param {string} uid the to-be-deleted download uuid
|
||||||
*/
|
*/
|
||||||
async function deleteDownloadById(uid) {
|
export async function deleteDownloadById(uid: string) {
|
||||||
db.prepare(`DELETE FROM downloads WHERE uid=${uid}`).run()
|
db.prepare(`DELETE FROM downloads WHERE uid=${uid}`).run()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +81,7 @@ async function deleteDownloadById(uid) {
|
|||||||
* Delete a download by its pid
|
* Delete a download by its pid
|
||||||
* @param {string} pid the to-be-deleted download pid
|
* @param {string} pid the to-be-deleted download pid
|
||||||
*/
|
*/
|
||||||
async function deleteDownloadByPID(PID) {
|
export async function deleteDownloadByPID(PID) {
|
||||||
db.prepare(`DELETE FROM downloads WHERE process_pid=${PID}`).run()
|
db.prepare(`DELETE FROM downloads WHERE process_pid=${PID}`).run()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +89,7 @@ async function deleteDownloadByPID(PID) {
|
|||||||
* Deletes the downloads that aren't active anymore
|
* Deletes the downloads that aren't active anymore
|
||||||
* @returns {Promise<ArrayLike>}
|
* @returns {Promise<ArrayLike>}
|
||||||
*/
|
*/
|
||||||
async function pruneDownloads() {
|
export async function pruneDownloads(): Promise<any> {
|
||||||
const all = await retrieveAll()
|
const all = await retrieveAll()
|
||||||
return all.map(job => {
|
return all.map(job => {
|
||||||
if (existsInProc(job.process_pid)) {
|
if (existsInProc(job.process_pid)) {
|
||||||
@@ -96,14 +97,4 @@ async function pruneDownloads() {
|
|||||||
}
|
}
|
||||||
deleteDownloadByPID(job.process_pid)
|
deleteDownloadByPID(job.process_pid)
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
init: init,
|
|
||||||
getDB: get_db,
|
|
||||||
insertDownload: insertDownload,
|
|
||||||
retrieveAll: retrieveAll,
|
|
||||||
deleteDownloadById: deleteDownloadById,
|
|
||||||
deleteDownloadByPID: deleteDownloadByPID,
|
|
||||||
pruneDownloads: pruneDownloads,
|
|
||||||
}
|
}
|
||||||
7
server/src/interfaces/IPayload.ts
Normal file
7
server/src/interfaces/IPayload.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export interface IPayload {
|
||||||
|
url: string
|
||||||
|
params: Array<string> | string,
|
||||||
|
title?: string,
|
||||||
|
thumbnail?: string,
|
||||||
|
size?: string,
|
||||||
|
}
|
||||||
0
server/src/interfaces/IRecord.ts
Normal file
0
server/src/interfaces/IRecord.ts
Normal file
@@ -1,20 +1,17 @@
|
|||||||
const Koa = require('koa'),
|
import Koa from 'koa';
|
||||||
serve = require('koa-static'),
|
import serve from 'koa-static';
|
||||||
cors = require('@koa/cors'),
|
import cors from '@koa/cors';
|
||||||
{ logger, splash } = require('./server/logger'),
|
import { logger, splash } from './utils/logger';
|
||||||
{ join } = require('path'),
|
import { join } from 'path';
|
||||||
{ Server } = require('socket.io'),
|
import { Server } from 'socket.io';
|
||||||
{ createServer } = require('http'),
|
import { createServer } from 'http';
|
||||||
{ ytdlpUpdater } = require('./server/updater'),
|
import { ytdlpUpdater } from './utils/updater';
|
||||||
{
|
import { download, abortDownload, retriveDownload, abortAllDownloads } from './core/downloader';
|
||||||
download,
|
import Logger from './utils/BetterLogger';
|
||||||
abortDownload,
|
import { retrieveAll, init } from './db/db';
|
||||||
retriveDownload,
|
|
||||||
abortAllDownloads,
|
|
||||||
} = require('./server/downloader'),
|
|
||||||
db = require('./server/db');
|
|
||||||
|
|
||||||
const app = new Koa()
|
const app = new Koa()
|
||||||
|
const log = new Logger()
|
||||||
const server = createServer(app.callback())
|
const server = createServer(app.callback())
|
||||||
const io = new Server(server, {
|
const io = new Server(server, {
|
||||||
cors: {
|
cors: {
|
||||||
@@ -43,7 +40,7 @@ io.on('connection', socket => {
|
|||||||
ytdlpUpdater(socket)
|
ytdlpUpdater(socket)
|
||||||
})
|
})
|
||||||
socket.on('fetch-jobs', () => {
|
socket.on('fetch-jobs', () => {
|
||||||
socket.emit('pending-jobs', db.retrieveAll())
|
socket.emit('pending-jobs', retrieveAll())
|
||||||
})
|
})
|
||||||
socket.on('retrieve-jobs', () => {
|
socket.on('retrieve-jobs', () => {
|
||||||
retriveDownload(socket)
|
retriveDownload(socket)
|
||||||
@@ -56,10 +53,11 @@ io.on('disconnect', (socket) => {
|
|||||||
|
|
||||||
app
|
app
|
||||||
.use(cors())
|
.use(cors())
|
||||||
.use(serve(join(__dirname, 'dist')))
|
.use(serve(join(__dirname, 'frontend')))
|
||||||
|
|
||||||
splash()
|
splash()
|
||||||
logger('koa', `Server started on port ${process.env.PORT || 3022}`)
|
log.info('koa', `Server started on port ${process.env.PORT || 3022}`)
|
||||||
|
|
||||||
db.init()
|
init()
|
||||||
.then(() => server.listen(process.env.PORT || 3022))
|
.then(() => server.listen(process.env.PORT || 3022))
|
||||||
|
.catch(err => log.err('db', err))
|
||||||
46
server/src/utils/BetterLogger.ts
Normal file
46
server/src/utils/BetterLogger.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
const ansi = {
|
||||||
|
reset: '\u001b[0m',
|
||||||
|
red: '\u001b[31m',
|
||||||
|
cyan: '\u001b[36m',
|
||||||
|
green: '\u001b[32m',
|
||||||
|
yellow: '\u001b[93m',
|
||||||
|
}
|
||||||
|
|
||||||
|
class Logger {
|
||||||
|
/**
|
||||||
|
* Print a standard info message
|
||||||
|
* @param {string} proto the context/protocol/section outputting the message
|
||||||
|
* @param {string} args the acutal message
|
||||||
|
*/
|
||||||
|
info(proto: string, args: string) {
|
||||||
|
process.stdout.write(
|
||||||
|
this.#__formatter(proto, args)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Print a warn message
|
||||||
|
* @param {string} proto the context/protocol/section outputting the message
|
||||||
|
* @param {string} args the acutal message
|
||||||
|
*/
|
||||||
|
warn(proto: string, args: string) {
|
||||||
|
process.stdout.write(
|
||||||
|
`${ansi.yellow}${this.#__formatter(proto, args)}${ansi.reset}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Print an error message
|
||||||
|
* @param {string} proto the context/protocol/section outputting the message
|
||||||
|
* @param {string} args the acutal message
|
||||||
|
*/
|
||||||
|
err(proto: string, args: string) {
|
||||||
|
process.stdout.write(
|
||||||
|
`${ansi.red}${this.#__formatter(proto, args)}${ansi.reset}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#__formatter(proto: any, args: any) {
|
||||||
|
return `[${proto}]\t${args}\n`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Logger;
|
||||||
@@ -4,20 +4,15 @@
|
|||||||
* @param {string} proto protocol
|
* @param {string} proto protocol
|
||||||
* @param {string} args message
|
* @param {string} args message
|
||||||
*/
|
*/
|
||||||
const logger = (proto, args) => {
|
export const logger = (proto: string, args: string) => {
|
||||||
console.log(`[${proto}]\t${args}`)
|
console.log(`[${proto}]\t${args}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CLI splash
|
* CLI splash
|
||||||
*/
|
*/
|
||||||
const splash = () => {
|
export const splash = () => {
|
||||||
console.log("-------------------------------------------------")
|
console.log("-------------------------------------------------")
|
||||||
console.log("yt-dlp-webUI - A web-ui for yt-dlp, simply enough")
|
console.log("yt-dlp-webUI - A web-ui for yt-dlp, simply enough")
|
||||||
console.log("-------------------------------------------------")
|
console.log("-------------------------------------------------")
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
logger: logger,
|
|
||||||
splash: splash,
|
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
const { spawn } = require('child_process');
|
import { spawn } from 'child_process';
|
||||||
const fs = require('fs');
|
import fs = require('fs');
|
||||||
const net = require('net');
|
import net = require('net');
|
||||||
const { logger } = require('./logger');
|
import { logger } from './logger';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Browse /proc in order to find the specific pid
|
* Browse /proc in order to find the specific pid
|
||||||
* @param {number} pid
|
* @param {number} pid
|
||||||
* @returns {*} process stats if any
|
* @returns {*} process stats if any
|
||||||
*/
|
*/
|
||||||
function existsInProc(pid) {
|
export function existsInProc(pid: number): any {
|
||||||
try {
|
try {
|
||||||
return fs.statSync(`/proc/${pid}`)
|
return fs.statSync(`/proc/${pid}`)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -33,15 +33,9 @@ function retriveStdoutFromProcFd(pid) {
|
|||||||
* Kills a process with a sys-call
|
* Kills a process with a sys-call
|
||||||
* @param {number} pid the killed process pid
|
* @param {number} pid the killed process pid
|
||||||
*/
|
*/
|
||||||
async function killProcess(pid) {
|
export async function killProcess(pid: number) {
|
||||||
const res = spawn('kill', [pid])
|
const res = spawn('kill', [String(pid)])
|
||||||
res.on('exit', () => {
|
res.on('exit', () => {
|
||||||
logger('proc', `Successfully killed yt-dlp process, pid: ${pid}`)
|
logger('proc', `Successfully killed yt-dlp process, pid: ${pid}`)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
existsInProc: existsInProc,
|
|
||||||
//retriveStdoutFromProcFd: retriveStdoutFromProcFd,
|
|
||||||
killProcess: killProcess,
|
|
||||||
}
|
|
||||||
@@ -37,7 +37,7 @@ function buildDonwloadOptions(release) {
|
|||||||
async function update() {
|
async function update() {
|
||||||
// ensure that the binary has been removed
|
// ensure that the binary has been removed
|
||||||
try {
|
try {
|
||||||
fs.rmSync(path.join(__dirname, 'yt-dlp'))
|
fs.rmSync(path.join(__dirname, '..', 'core', 'yt-dlp'))
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
console.log('file not found!')
|
console.log('file not found!')
|
||||||
@@ -70,11 +70,11 @@ function downloadBinary(url) {
|
|||||||
if (res.statusCode === 301 || res.statusCode === 302) {
|
if (res.statusCode === 301 || res.statusCode === 302) {
|
||||||
return downloadBinary(res.headers.location)
|
return downloadBinary(res.headers.location)
|
||||||
}
|
}
|
||||||
let bin = fs.createWriteStream(path.join(__dirname, 'yt-dlp'))
|
let bin = fs.createWriteStream(path.join(__dirname, '..', 'core', 'yt-dlp'))
|
||||||
res.pipe(bin)
|
res.pipe(bin)
|
||||||
// once the connection has ended make the file executable
|
// once the connection has ended make the file executable
|
||||||
res.on('end', () => {
|
res.on('end', () => {
|
||||||
fs.chmod(path.join(__dirname, 'yt-dlp'), 0o775, err => {
|
fs.chmod(path.join(__dirname, '..', 'core', 'yt-dlp'), 0o775, err => {
|
||||||
err ? console.error('failed updating!') : console.log('done!')
|
err ? console.error('failed updating!') : console.log('done!')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
17
tsconfig.json
Normal file
17
tsconfig.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./dist",
|
||||||
|
"allowJs": true,
|
||||||
|
"target": "ES2018",
|
||||||
|
"module": "commonjs",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"strict": false,
|
||||||
|
"noEmit": false
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"./server/src/**/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user