[
  {
    "path": ".gitignore",
    "content": "node_modules\n"
  },
  {
    "path": "Contributors.md",
    "content": "Balaji S github URL: https://github.com/balajinikhil\n"
  },
  {
    "path": "README.md",
    "content": "# Youtube Downloader\n\nThis is a repository that has sample code for my [Medium Article](https://blog.usejournal.com/how-i-made-my-own-youtube-downloader-using-javascript-and-node-js-160b172f6e10)\n\n## Getting Started\n\nIf there is any issues please open a new issue.\n\n1. You need to clone this repository\n```\ngit clone https://github.com/mooradal/youtubeDownloader\n```\n\n2. After you clone the repo you will have to navigate to the Server folder\n```\ncd Server\n```\n\n3. Then you will have to install all the packages and dependencies\n```\nnpm install \n```\n\n4. Finally you need to run it\n```\nnode index.js\n```\n\n5. If you want to use nodemon (nodemon is a package that will auto restart the server when files are changed) you can run **(Optional)**\n\n```\nnpm run dev\n```\nor\n```\nnodemon index.js\n```\n\n## Info\n\nIf there is any issues please open a new issue. You are welcome to add pull requests at anytime\n\nThank you so much for supporting me and thank you for almost 2,000 claps. I really appreciate that. I will try to post more articles and I'm thinking of turning this project from a sample code to an actual functional public website for everyone to use!\n"
  },
  {
    "path": "Server/index.js",
    "content": "const express = require('express');\nconst cors = require('cors');\nconst ytdl = require('ytdl-core');\nconst app = express();\nconst PORT = 4000;\n\napp.use(cors());\n\napp.listen(PORT, () => {\n\tconsole.log(`Server Works !!! At port ${PORT}`);\n});\n\napp.get('/downloadmp3', async (req, res, next) => {\n\ttry {\n\t\tvar url = req.query.url;\n\t\tif(!ytdl.validateURL(url)) {\n\t\t\treturn res.sendStatus(400);\n\t\t}\n\t\tlet title = 'audio';\n\n\t\tawait ytdl.getBasicInfo(url, {\n\t\t\tformat: 'mp4'\n\t\t}, (err, info) => {\n\t\t\tif (err) throw err;\n\t\t\ttitle = info.player_response.videoDetails.title.replace(/[^\\x00-\\x7F]/g, \"\");\n\t\t});\n\n\t\tres.header('Content-Disposition', `attachment; filename=\"${title}.mp3\"`);\n\t\tytdl(url, {\n\t\t\tformat: 'mp3',\n\t\t\tfilter: 'audioonly',\n\t\t}).pipe(res);\n\n\t} catch (err) {\n\t\tconsole.error(err);\n\t}\n});\n\napp.get('/downloadmp4', async (req, res, next) => {\n\ttry {\n\t\tlet url = req.query.url;\n\t\tif(!ytdl.validateURL(url)) {\n\t\t\treturn res.sendStatus(400);\n\t\t}\n\t\tlet title = 'video';\n\n\t\tawait ytdl.getBasicInfo(url, {\n\t\t\tformat: 'mp4'\n\t\t}, (err, info) => {\n\t\t\ttitle = info.player_response.videoDetails.title.replace(/[^\\x00-\\x7F]/g, \"\");\n\t\t});\n\n\t\tres.header('Content-Disposition', `attachment; filename=\"${title}.mp4\"`);\n\t\tytdl(url, {\n\t\t\tformat: 'mp4',\n\t\t}).pipe(res);\n\n\t} catch (err) {\n\t\tconsole.error(err);\n\t}\n});"
  },
  {
    "path": "Server/package.json",
    "content": "{\n  \"name\": \"server\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"dev\": \"nodemon index.js\",\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  },\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"dependencies\": {\n    \"cors\": \"^2.8.5\",\n    \"express\": \"^4.16.4\",\n    \"ytdl-core\": \"^3.1.2\"\n  },\n  \"devDependencies\": {\n    \"nodemon\": \"^1.18.10\"\n  }\n}\n"
  },
  {
    "path": "index.html",
    "content": "<!DOCTYPE html>\n<html lang='en'>\n\n<head>\n\t<link rel='stylesheet' href='./style.css' />\n\t<title>Youtube Downloader</title>\n</head>\n\n<body>\n\t<h1 class='heading'>Paste YouTube URL</h1>\n\t<input class='URL-input' placeholder='https://www.youtube.com/watch?v=MtN1YnoL46Q' />\n\t<select class='opt'>\n\t\t<option value='mp3'>mp3</option>\n\t\t<option value='mp4'>mp4</option>\n\t</select>\n\n\t<button class='convert-button' id='btn'>Convert</button>\n\t<script src='./script.js'></script>\n</body>\n\n</html>"
  },
  {
    "path": "script.js",
    "content": "let Btn = document.getElementById('btn');\nlet URLinput = document.querySelector('.URL-input');\nlet select = document.querySelector('.opt');\nlet serverURL = 'http://localhost:4000';\n\nBtn.addEventListener('click', () => {\n\tif (!URLinput.value) {\n\t\talert('Enter YouTube URL');\n\t} else {\n\t\tif (select.value == 'mp3') {\n\t\t\tdownloadMp3(URLinput.value);\n\t\t} else if (select.value == 'mp4') {\n\t\t\tdownloadMp4(URLinput.value);\n\t\t}\n\t}\n});\n\nasync function downloadMp3(query) {\n\tconst res = await fetch(`${serverURL}/downloadmp3?url=${query}`);\n\tif(res.status == 200) {\n\t\tvar a = document.createElement('a');\n  \t\ta.href = `${serverURL}/downloadmp3?url=${query}`;\n  \t\ta.setAttribute('download', '');\n\t\ta.click();\n\t} else if(res.status == 400) {\n\t\talert(\"Invalid url\");\n\t}\n}\n\nasync function downloadMp4(query) {\n\tconst res = await fetch(`${serverURL}/downloadmp4?url=${query}`);\n\tif(res.status == 200) {\n\t\tvar a = document.createElement('a');\n  \t\ta.href = `${serverURL}/downloadmp4?url=${query}`;\n  \t\ta.setAttribute('download', '');\n\t\ta.click();\n\t} else if(res.status == 400) {\n\t\talert('Invalid url');\n\t}\n}"
  },
  {
    "path": "style.css",
    "content": "* {\n\ttext-align: center;\n}\n\nbody {\n\tdisplay: grid;\n\tgrid-template-columns: auto;\n}\n\n.heading {\n\tfont-family: Arial;\n\tmargin-top: 40vh;\n}\n\n.URL-input,\n.convert-button {\n\tfont-size: 1.3em;\n\tpadding: 5px 10px;\n}\n\n.URL-input {\n\tmargin: auto;\n\tborder-radius: 4px 0px 0px 4px;\n\twidth: 30em;\n\ttext-align: left;\n\tborder: 2px solid #eeeeee;\n\tbackground: #eeeeee;\n\toutline: none;\n}\n\n.URL-input:focus {\n\tborder: 2px solid #0485ff;\n}\n\n.convert-button {\n\tmargin: 2% auto;\n\tborder: 2px solid #0485ff;\n\tbackground: #0485ff;\n\tcolor: white;\n\ttransition: 0.15s;\n}\n\n.convert-button:hover {\n\tbackground: #016acc;\n\tborder-color: #016acc;\n}\n\n@media only screen and (max-width: 600px) {\n\tbody {\n\t\tdisplay: grid;\n\t\tgrid-template-columns: auto;\n\t\tjustify-content: center;\n\t}\n\n\t.URL-input {\n\t\tmargin: auto;\n\t\twidth: 100%;\n\t}\n\n\t.convert-button {\n\t\tmargin: 7% auto;\n\t\twidth: 100%;\n\t}\n}\n\n.opt {\n\twidth: 30vw;\n\tmargin: 2% auto;\n\tpadding: 4px;\n\tborder-radius: 7%;\n}"
  }
]