-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
25 changed files
with
3,533 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
node_modules | ||
.env | ||
*.mp4 | ||
*.mp3 | ||
ffmpeg | ||
RYTDL-win32-x64* |
Large diffs are not rendered by default.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<!doctype html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<link rel="icon" type="image/svg+xml" href="/vite.svg" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<title>Youtube Downloader</title> | ||
<script type="module" crossorigin src="assets/index-Ccy0lpz4.js"></script> | ||
<link rel="stylesheet" crossorigin href="assets/index-Cp3wgTPn.css"> | ||
</head> | ||
<body> | ||
<div id="root"></div> | ||
</body> | ||
</html> |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
require('dotenv').config(); | ||
const express = require('express'); | ||
const ytdl = require("@distube/ytdl-core"); | ||
const path = require('path'); | ||
|
||
const { mergeVideoAudio, downloadYtVideo, cleanUp } = require('./util.js'); | ||
|
||
|
||
const app = express(); | ||
|
||
app.use(express.json()); | ||
app.use(express.static('public')); | ||
|
||
const PORT = process.env.PORT || 8080; | ||
|
||
app.listen(PORT, () => { | ||
console.log("Server listening on PORT:", PORT); | ||
}); | ||
|
||
|
||
// GET request to get available resolutions for a video | ||
// returns an object with qualities (1080p, 720p, etc) as keys | ||
// and itags as values | ||
app.get('/api/resolutions', async (req, res) => { | ||
const url = req.query.url; | ||
|
||
if (!url) { | ||
return res.status(400).json({error: "Invalid URL"}); | ||
} | ||
|
||
try { | ||
const info = await ytdl.getInfo(url); | ||
// console.log(info); | ||
|
||
const resolutions = new Map( | ||
info.formats | ||
.filter(format => format.hasVideo) | ||
// .map(format => [format.qualityLabel, format.qualityLabel]) | ||
.map(format => [format.qualityLabel, format.itag]) | ||
); | ||
|
||
console.log(resolutions); | ||
|
||
const mapToObject = Object.fromEntries(resolutions); | ||
|
||
return res.json(mapToObject); | ||
|
||
} | ||
catch (err) { | ||
return res.status(500).json({error: `Error getting resolutions: ${err}`}); | ||
} | ||
|
||
}) | ||
|
||
// POST request to download a video to a specified location on system | ||
app.post('/api/download', async (req, res) => { | ||
const url = req.body.url; | ||
const iTag = req.body.itag; | ||
|
||
if (!url) { | ||
return res.status(400).json({error: "Invalid URL"}); | ||
} | ||
|
||
try { | ||
|
||
// const vidId = ytdl.getURLVideoID(url); | ||
const info = await ytdl.getInfo(url); | ||
const videoTitle = info.videoDetails.title.replace(/[<>:"/\\|?*]/g, ' '); | ||
console.log(videoTitle); | ||
|
||
// we want av01 video codec btw, they all start with 39* | ||
const videoFormat = ytdl.chooseFormat(info.formats, { quality: iTag }); | ||
const audioFormat = ytdl.chooseFormat(info.formats, { quality: '140' }); | ||
|
||
// Download both streams concurrently | ||
await Promise.all([ | ||
downloadYtVideo(url, videoFormat, "video.mp4"), | ||
downloadYtVideo(url, audioFormat, "audio.mp3") | ||
]); | ||
|
||
console.log("Both streams downloaded. Starting ffmpeg..."); | ||
|
||
// const testFileName = path.join(__dirname, `${videoTitle}.mp4`); | ||
const outputFileName = path.join(__dirname, `${videoTitle}.mp4`) | ||
|
||
console.log("Outputting to: ", outputFileName); | ||
// console.log("Test output:", testFileName); | ||
await mergeVideoAudio("video.mp4", "audio.mp3", outputFileName); | ||
|
||
console.log("Cleaning up files..."); | ||
|
||
return res.status(200).json({ message: "Sucessfully downloaded!" }); | ||
|
||
} | ||
catch (err) { | ||
return res.status(500).json({error: `Error processing request ${err}`}); | ||
} | ||
finally { | ||
cleanUp(); | ||
} | ||
|
||
|
||
}); | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
const { app, BrowserWindow } = require('electron'); | ||
const path = require('path'); | ||
const { spawn, fork } = require('child_process'); | ||
const fs = require('fs'); | ||
|
||
|
||
let mainWindow; | ||
let backendProcess; | ||
|
||
// function startBackend() { | ||
// const indexPath = path.join(__dirname, 'index.js'); | ||
// backendProcess = spawn('node', [indexPath]); | ||
|
||
// backendProcess.stdout.on('data', (data) => { | ||
// console.log(`stdout: ${data}`); | ||
// }); | ||
|
||
// backendProcess.stderr.on('data', (data) => { | ||
// console.error(`stderr: ${data}`); | ||
// }); | ||
|
||
// backendProcess.on('close', (code) => { | ||
// console.log(`Backend process exited with code ${code}`); | ||
// }); | ||
// } | ||
|
||
function startBackend() { | ||
// console.log("DIRNAME:", __dirname) | ||
backendProcess = fork(path.join(app.getAppPath(), 'index.js')); | ||
|
||
backendProcess.on('message', (message) => { | ||
console.log('Backend message:', message); | ||
}); | ||
|
||
backendProcess.on('error', (error) => { | ||
console.error('Backend process error:', error); | ||
}); | ||
|
||
backendProcess.on('exit', (code) => { | ||
console.log(`Backend process exited with code ${code}`); | ||
}); | ||
} | ||
|
||
function quitApp() { | ||
if (backendProcess) { | ||
backendProcess.kill(); // Kill the backend process | ||
console.log('Attempted to kill backend process'); | ||
|
||
// Wait for a few seconds before checking if the process is still running | ||
setTimeout(() => { | ||
if (!backendProcess.killed) { | ||
console.log('Backend process is still running'); | ||
} else { | ||
console.log('Backend process was killed'); | ||
} | ||
|
||
app.quit(); // Quit Electron app after the delay | ||
}, 5000); // Wait for 5 seconds before checking | ||
|
||
} | ||
else { | ||
app.quit(); // Quit immediately if backendProcess is not defined | ||
} | ||
} | ||
|
||
|
||
function createWindow() { | ||
mainWindow = new BrowserWindow({ | ||
width: 1000, | ||
height: 800, | ||
webPreferences: { | ||
nodeIntegration: true, | ||
}, | ||
}); | ||
|
||
mainWindow.loadFile('./dist/index.html'); | ||
mainWindow.on('closed', () => (mainWindow = null)); | ||
} | ||
|
||
app.on('ready', () => { | ||
startBackend(); | ||
createWindow(); | ||
}); | ||
|
||
app.on('window-all-closed', () => { | ||
if (process.platform !== 'darwin') { | ||
quitApp(); | ||
} | ||
}); | ||
|
||
app.on('activate', () => { | ||
if (mainWindow === null) { | ||
createWindow(); | ||
} | ||
}); | ||
|
||
app.on('before-quit', () => { | ||
quitApp(); | ||
}); |
Oops, something went wrong.