diff --git a/public/index.html b/public/index.html index a9b9f7d..1096980 100644 --- a/public/index.html +++ b/public/index.html @@ -3,7 +3,7 @@ - Page Title + Ben's YouTube Downloader @@ -21,7 +21,9 @@ -
+
+
+
diff --git a/public/index.js b/public/index.js index b311a23..14f337a 100644 --- a/public/index.js +++ b/public/index.js @@ -27,20 +27,20 @@ let VideoPreview = []; function renderPreview() { if (isDownloading) return; - document.getElementById('VideoPreview').innerText = ''; + document.getElementById('VideoBox').innerText = ''; for (const [key, value] of Object.entries(VideoPreview)) { if (document.getElementById(key) == null) { if (!value.found) { - document.getElementById('VideoPreview').innerHTML += `
${key}: Video not found
`; + document.getElementById('VideoBox').innerHTML += `
${key}: Video not found
`; } else { - document.getElementById('VideoPreview').innerHTML += `
${key}: ${value.title}
`; + document.getElementById('VideoBox').innerHTML += `
${key}: ${value.title}
`; } } } } function clearPreview() { - document.getElementById('VideoPreview').innerText = ''; + document.getElementById('VideoBox').innerText = ''; } socket.on('video-preview', async (data) => { @@ -56,10 +56,40 @@ socket.on('video-preview', async (data) => { document.getElementById('Download').addEventListener('click', async (event) => { if (isDownloading) return; socket.emit('download', document.getElementById('VideosToRecord').value.split('\n')); - document.getElementById('VideoPreview').innerText = '\nDownloading...'; - document.getElementById('VideosToRecord').value = null; + document.getElementById('VideoBox').innerText = 'Downloading...'; + // document.getElementById('VideosToRecord').value = null; isDownloading = true; console.log('Asked server for download...'); }); +let downloads = []; +let downloadCount = 0; +let completedDownloads = 0; +function renderDownloads() { + document.getElementById('VideoBox').innerText = ''; + for (const [key, value] of Object.entries(downloads)) { + document.getElementById('VideoBox').innerHTML += `
${value.title}: ${value.percent}
`; + } +} + +socket.on('download-count', async (data) => { + downloadCount = data.num; +}); + +socket.on('download-done', async(data) => { + completedDownloads++; + + downloads[data.video] = {title: data.title, percent: 'Complete!'}; + renderDownloads(); + if (completedDownloads == downloadCount) { + completedDownloads = 0; downloadCount = 0; + isDownloading = false; + downloads = []; + } +}); + +socket.on('download-progress', async (data) => { + downloads[data.video] = data; + renderDownloads(); +}); diff --git a/public/resources/YouTube Logo.png b/public/resources/YouTube Logo.png new file mode 100644 index 0000000..f88fdb2 Binary files /dev/null and b/public/resources/YouTube Logo.png differ diff --git a/public/style.css b/public/style.css index ad6d181..9133357 100644 --- a/public/style.css +++ b/public/style.css @@ -30,7 +30,12 @@ textarea { height: 100px; } -#VideoPreview { +.VideoContainer { + padding: 30px, 0px, 30px, 0px; +} + +#VideoBox { + padding-top: 10px; font-weight: lighter; } diff --git a/src/index.js b/src/index.js index 60ed9f1..c393c27 100644 --- a/src/index.js +++ b/src/index.js @@ -1,7 +1,7 @@ const server = require('./server'); let config = { - serverPort: 80, + serverPort: 8080, downloadLocation: './' }; diff --git a/src/server.js b/src/server.js index a9f476f..e2926c3 100644 --- a/src/server.js +++ b/src/server.js @@ -37,8 +37,9 @@ module.exports.listen = async () => { }); socket.on('download', async (data) => { - logger.log(`Socket id ${socket.id}' is requesting a download`); - youtube.downloadVideos(data, socket, {path: main.config.downloadLocation}); + logger.log(`Socket id '${socket.id}' is requesting a download`); + let toDownload = await youtube.resolveVideos(data); + youtube.downloadVideos(toDownload.data, socket, {path: main.config.downloadLocation}); }); }); } diff --git a/src/youtubehelper.js b/src/youtubehelper.js index a8559aa..55e743f 100644 --- a/src/youtubehelper.js +++ b/src/youtubehelper.js @@ -1,3 +1,6 @@ +const logger = require('./logger'); + +const fs = require('fs'); const ytdl = require('ytdl-core'); module.exports.resolveVideos = async (arr) => { @@ -29,6 +32,39 @@ module.exports.resolveVideos = async (arr) => { module.exports.downloadVideos = async (arr, socket, options) => { let path = options.path ? options.path : './' - + let numOfDownloads = 0; + for (const [key, value] of Object.entries(arr)) { + if (ytdl.validateURL(key)) { + try { + const stream = await ytdl(key, {quality: 'highest'}); + stream.pipe(fs.createWriteStream(`${path}/${value.title}.mp4`)); + + stream.on('response', (res) => { + let totalSize = res.headers['content-length']; + let dataRead = 0; + let lastPercent = 0; + res.on('data', (data) => { + dataRead += data.length; + let percent = Math.floor((dataRead / totalSize) * 100) + '%'; + if (percent != lastPercent) { + socket.emit('download-progress', {video: key, percent: percent, title: value.title}); + } + lastPercent = percent; + }); + res.on('end', () => { + logger.log(`Socket id '${socket.id}' finished downloading ${value.title}`) + socket.emit('download-done', {video: key, title: value.title}); + }); + }); + + logger.log(`Socket id '${socket.id}' is downloading ${value.title}`); + } catch (e) { + logger.log(`Socket id '${socket.id}' failed to download ${value.title}`); + socket.emit('download-done', {video: key, title: value.title}); + } + numOfDownloads++; + } + } + socket.emit('download-count', {num: numOfDownloads}); }