From 35bcbe95689c90211ba256b4ee31bc6ea0a5f054 Mon Sep 17 00:00:00 2001 From: Feuerhamster Date: Tue, 29 Jun 2021 20:24:44 +0200 Subject: [PATCH] Typescript remake --- .gitignore | 3 + Dockerfile | 34 + README.md | 30 +- api.php | 55 -- docs.php | 59 -- downloader.html | 31 - favicon.ico | Bin 2573 -> 0 bytes home.html | 9 - index.js | 107 --- index.php | 49 - infos.html | 26 - package-lock.json | 1815 +++++++++++++++++++++++++++++++++++ package.json | 30 + public/logo.png | Bin 0 -> 20684 bytes public/style.css | 200 ++++ src/main.ts | 15 + src/routes/default.ts | 29 + src/services/youtube.ts | 56 ++ src/types/youtube.ts | 26 + style.css | 183 ---- tsconfig.json | 13 + views/_layout.pug | 12 + views/about.pug | 17 + views/error.pug | 4 + views/index.pug | 10 + views/partials/titlebox.pug | 8 + views/video.pug | 48 + 27 files changed, 2349 insertions(+), 520 deletions(-) create mode 100644 .gitignore create mode 100644 Dockerfile delete mode 100644 api.php delete mode 100644 docs.php delete mode 100644 downloader.html delete mode 100644 favicon.ico delete mode 100644 home.html delete mode 100644 index.js delete mode 100644 index.php delete mode 100644 infos.html create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 public/logo.png create mode 100644 public/style.css create mode 100644 src/main.ts create mode 100644 src/routes/default.ts create mode 100644 src/services/youtube.ts create mode 100644 src/types/youtube.ts delete mode 100644 style.css create mode 100644 tsconfig.json create mode 100644 views/_layout.pug create mode 100644 views/about.pug create mode 100644 views/error.pug create mode 100644 views/index.pug create mode 100644 views/partials/titlebox.pug create mode 100644 views/video.pug diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8bea256 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +node_modules +.idea +dist diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..1db0ac3 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,34 @@ +# Build stage +FROM node:lts-alpine AS builder + +RUN mkdir /app +WORKDIR /app + +# copy configs folder +COPY package*.json ./ +COPY tsconfig.json ./ +# copy source code to /app/src folder +COPY src src + +# install dependencies (https://docs.npmjs.com/cli/v7/commands/npm-ci) +RUN npm ci + +# build +RUN npm run build + +# Production stage +FROM node:lts-alpine +ENV NODE_ENV=production + +RUN mkdir /app +WORKDIR /app + +COPY package*.json ./ +COPY --from=builder /app/dist dist + +RUN mkdir targets + +# install production dependencies +RUN npm ci + +CMD ["npm", "start"] \ No newline at end of file diff --git a/README.md b/README.md index 38d4684..6ee7e31 100644 --- a/README.md +++ b/README.md @@ -1 +1,29 @@ -# web-youtube-downloader \ No newline at end of file +# Web YouTube Downloader +A simple express app which allows you to view all source urls of a YouTube video to directly download it from Google's servers. + +## 📦 Dependencies +- [Express](https://expressjs.com/) +- [Typescript](https://www.typescriptlang.org/) +- [Pug](https://pugjs.org/) +- [ytdl-core](https://www.npmjs.com/package/ytdl-core) + +## 💽 Installation +### Docker +```shell +git clone https://github.com/Feuerhamster/web-youtube-downloader.git +cd web-youtube-downloader +docker build -t Feuerhamster/web-youtube-downloader . +docker run Feuerhamster/web-youtube-downloader + -e PORT=3000 +``` + +### Manually +*Requires NodeJS 14 or higher* + +```shell +git clone https://github.com/Feuerhamster/web-youtube-downloader.git +cd web-youtube-downloader +npm install +npm run build +npm run start +``` \ No newline at end of file diff --git a/api.php b/api.php deleted file mode 100644 index 758e4ad..0000000 --- a/api.php +++ /dev/null @@ -1,55 +0,0 @@ -args->player_response; - - $ytdata = json_decode($ytdata); - - if($ytdata->videoDetails->useCipher == false){ - - $data = new stdClass(); - - $data->title = $ytdata->videoDetails->title; - $data->channel = $ytdata->videoDetails->author; - $data->videoId = $ytdata->videoDetails->videoId; - $data->length = $ytdata->videoDetails->lengthSeconds; - $data->views = $ytdata->videoDetails->viewCount; - - $data->sources = $ytdata->streamingData; - $data->thumbnails = $ytdata->videoDetails->thumbnail->thumbnails; - - $send = json_encode($data); - - echo $send; - - }else{ - $data = new stdClass(); - $data->error = "cipher_video"; - $send = json_encode($data); - echo $send; - } - -}else{ - $data = new stdClass(); - $data->error = "missing_video_id"; - $send = json_encode($data); - echo $send; -} -?> diff --git a/docs.php b/docs.php deleted file mode 100644 index e09934d..0000000 --- a/docs.php +++ /dev/null @@ -1,59 +0,0 @@ -

API for Developers

-

You can get the data of a video very easily by using our API.

- -

Web Request structure

-MethodGET -Urlhttps://feuerhamster.code-elite.net/web-youtube-downloader/api.php -Paramsvid={YOUTUBE VIDEO ID} -ReturnJSON - -

Return values

-

There are mulitple return values for that request. The return values are also in JSON format

-
Errors: - - error: missing_video_id //returns if you have not send the video Id in the query string - - error: cipher_video" //returns if the video is protected and can not be read by the api -
- -
Video Data JSON structure: - -- title -- channel -- length -- views - -- sources: - - - expiresInSeconds - - - formats: - ARRAY() - - - adaptiveFormats: - ARRAY() - -- thumbnails: - ARRAY() -
- - -

Examples

-

An example url for an api call

-
https://feuerhamster.code-elite.net/web-youtube-downloader/api.php?vid=nD6_aQIJgW0 -
- -

An example with Ajax in JavaScript

-
var videoId = "nD6_aQIJgW0"; - -$.ajax({ - type: 'GET', - url: 'https://feuerhamster.code-elite.net/web-youtube-downloader/api.php', - data: 'vid=' + videoId, - success: function(res){ - - if(!res.error){ - console.log(res); - } - - } -}); -
\ No newline at end of file diff --git a/downloader.html b/downloader.html deleted file mode 100644 index 14b0e58..0000000 --- a/downloader.html +++ /dev/null @@ -1,31 +0,0 @@ -
- - -
-

...

-

...

-

...

-

...

- -
- - -
- -

Main Sources

- -
- -
- -

Adaptive Sources

- -
- -
- -

Thumbnails

- -
- -
\ No newline at end of file diff --git a/favicon.ico b/favicon.ico deleted file mode 100644 index 58b2d1b43700f7594668643dfb611e0758f484d3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2573 zcmcJQ`BxL!5`e4Q7Mn%rmPHhW(0G&)1Vuy<(LfS1jBJDZV^xeRU<{(bs5FWY6o@Fe zk7V?@Fryfqr+^y`ilX4|7{D2c2!e)v5f~8O#rGGyALjPCr>g6#Q+03M4FE&mNW*{! zy}AHqNKXs!6OYxKsE5?C-roxYN9af=b&v>_U0jERuJrp=F#v}5M>>{cXJ~g zrE#ZP{;J&^ESbo4G&*|+6+DSPocYAiKG`=fTs{Bn=n2%>Cv~DNdPO}C7IBM8f9miG z__6&#u~O;Tu`clJC=a?|Z}eeyghV-SKQzVF7S`aMA=5(>xBSv~7wnzmcQGPgT7j!e;JJn;2C zbT2;@3n)7I!G1UY@`VQ>{=iMf!PX0)j0B}Q1|~MZt|1^G9bi8V{8|4nd4+p24Ksk>L&CP8_t(elA}87)zC)}M6TpY?TT zd>kAeKXWXOl-Xx1=R?G+SDis#k}N^-E!v zj$zBff=`@pVA^}somcwfU8MszO7dn-zm92CwRegg94i(zHcC#B^Uk_}t)uS}*ZHoi z`dl$O>u^Oyr(#7|j-YsOjnt`L1OY!(Pty?zPxpVeJ8iyAD1o8D7vg-ee195QxqZGY zcC|-lYxA**`mPrZxL;g&tW$)$UM zyZDp8!I2j{JjWVlw!VwOB~;QT3gQlsRbtT0VZz5_Z12PtmjS}w8pzVf3-_|v(FBxe zws8w^R!L#MldwlXR3bQzp1BuzD}~AtKqtu%c(^dBj)XJZ!lX4wlzifvka)SFpkW}U zvA*hZP`+3f$N1YOE?z9;O~YARI%y|z5D{O*KwW?E^3bK9-KH%OhOZ#t#b$>YSN%1* zBrHAFvTbe4b@kfm6~T%+Qyk`;IO=Ge^pJv!o`j_clzv^El2t(~4}Q1ZU>r2Pjx3Nw z?G8Pko#^a}vHyC~AnDKlIpv|-#oW*JYeNMlia3Ozd2%%En)!}+2?yklCK$aUw`}Se7IaYq&~s$feqP^ z1{iB<7ZZ~&w)GVdB&brWY!KMBHYkYcxv8CXi3fbctF6XJ_{}v(}?IQPGbz_jU6`?GBzem>i6XEDvAjwP}oD zq2)OfoXz^r&5%sI^>M--jRNKL@**tDU0l|-cfSg>FpBwZpX;1cHn`E+ue((P28SIs#tgAMwC9Vkdr`BuTXY=xQ`dgjyai*kjFw4kWyV60h-6n zBMU|B|F&LJ_MbxQ^)^MY$~FFFkBJQ`W6sz7oFdo8+4tAHCMh^@x|=gBxlDIs~b*p*GsTW*>Kef>vi#HN7&0H9kme&m|0PxoNMYt(>FJJTQ~P| zrg))`q~{MCriU{YGA7=>}= zD+fDxV6J;$kplrmSNlE){;%7-==#l&ca+Hlv~j7VLJHE;$@_ajNiozIoGq2}`$+h~ z8eeS#wi#sd0pLi6nu_R$6%`Z%JsRA z6yqHVEzdd!CB}-=xJNtQW!YTt4>~Sz!^0nCHJ;Z0`+Mck$CFM2U*0ZH6#w=%r!6$W zJ9@0nt)YQ#?UjnzR*8|ZIxQqCIaScwQnsZy)_u>Wf9_rLk-!bd(CkNLB6S33Gu+?3 zL~S!K>(bnl0=1xU=KqeZZqMvV6@l>tXbi7oh3@9%D=&XcFo@%6dqWhO^qM6=`;C&O zzPXo3H(-=CUb8WDkRkX&;ilZ3jQI4fH$CPTpAY8;XIVK0OWjjq2u;4TZ$n>ym+bRi zqhJMoApcI!k;u@S^$7-BC^q%q8$Txy%D_!wqpN)HgigZ)_Q8S_l5dQw^ck2za>f+4 zfe&B!1m%XSj2QM9%}$cT8WG4CTux)=7|o9)IXN5)AvCW)I21 z(+doEIBAN_OeT3kg5x1T!94^#!5)Fpmz!Xh|p-Ts4E9FqL7nPd+~HnOQZNW@jX}^;ixz6xVEMp5iTg-oPI*dZ(33 ee^I;fm`;l`FGcGe)fRUFHE)rhFyAwL&wl~Z!P`mz diff --git a/home.html b/home.html deleted file mode 100644 index 8f95954..0000000 --- a/home.html +++ /dev/null @@ -1,9 +0,0 @@ -
- -

Download YouTube videos from source!

- -

All Video and Audio Tracks + Thumbnails

- - - -
\ No newline at end of file diff --git a/index.js b/index.js deleted file mode 100644 index cc302de..0000000 --- a/index.js +++ /dev/null @@ -1,107 +0,0 @@ -//get query string -var urlQs = document.URL.split('?'); - -//check if any querystring is set -if(urlQs[1]){ - - //parse querytring args - var qsArgs = urlQs[1].split('='); - - if(qsArgs[0] == "vid"){ - - $('#content').load('./downloader.html'); - getVideoData(qsArgs[1]); - - }else if(qsArgs[0] == "page"){ - if(qsArgs[1] == "infos"){ - $('#content').load('./infos.html'); - }else if(qsArgs[1] == "documentation"){ - $('#content').load('./docs.php'); - }else{ - $('#content').html('

ERROR 404: Page not found!

'); - } - } - -}else{ - $('#content').load('./home.html'); -} - - -function parseMimeType(mimeType){ - var regex = /(\w+)\/(\w+)\;\ codecs\=\"(.+)\"/; - var result = regex.exec(mimeType); - return { type: result[1], format: result[2], codec: result[3] }; -} - -function secToMin(time) { - var hr = ~~(time / 3600); - var min = ~~((time % 3600) / 60); - var sec = time % 60; - var sec_min = ""; - if (hr > 0) { - sec_min += "" + hrs + ":" + (min < 10 ? "0" : ""); - } - sec_min += "" + min + ":" + (sec < 10 ? "0" : ""); - sec_min += "" + sec; - return sec_min+ " minutes"; - } - -function getVideoData(videoId){ - - $.ajax({ - type: "GET", - url: "./api.php", - data: "vid=" + videoId, - success: function(res){ - - console.log(res); - - if(!res.error){ - - $('#video-title').html(res.title); - $('#video-channel').html(res.channel); - $('#video-views').html(res.views.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,') + " views"); - $('#video-time').html(secToMin(res.length)); - $('#video-thumbnail').attr("src", res.thumbnails[3].url); - - $('#video-links').html('https://www.youtube.com/watch?v=' + res.videoId + ''); - - res.sources.formats.forEach(element => { - - var mainMime = parseMimeType(element.mimeType); - $('#video-main-source').append(''); - - }); - - res.sources.adaptiveFormats.forEach(element => { - var mime = parseMimeType(element.mimeType); - if(mime.type == "video"){ - $('#video-sources').append('
Type' + mime.type + 'Quality' + element.qualityLabel + 'Format' + mime.format + 'Codec' + mime.codec + '
'); - }else{ - $('#video-sources').append('
Type' + mime.type + 'Bitrate' + element.bitrate + 'Format' + mime.format + 'Codec' + mime.codec + '
'); - } - }); - - res.thumbnails.forEach(element => { - $('#video-thumbnails').append('
Size' + element.width + 'px*' + element.height + 'px
Download
') - }); - - }else{ - $('#content').html('

An error has occurred!

Please try another video or try again later

'); - } - - - } - }); - -} - -function loadVideoURL(source){ - - //parse soruce and get id - var ytidRegex = /(youtu\.be\/|youtube\.com\/(watch\?(.*&)?v=|(embed|v)\/))([^\?&"'>]+)/; - var videoId = ytidRegex.exec(source)[5]; - - window.location.href = window.location.protocol + "//" + window.location.hostname + window.location.pathname + "?vid=" + videoId; - -} \ No newline at end of file diff --git a/index.php b/index.php deleted file mode 100644 index 9b92e53..0000000 --- a/index.php +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - Web-YTDL - - - - - - - - - - - - - - - -
- -

Web-Youtube-Downloader

- -
- - - -
- -
- -
- - - - - - - \ No newline at end of file diff --git a/infos.html b/infos.html deleted file mode 100644 index 1d2c818..0000000 --- a/infos.html +++ /dev/null @@ -1,26 +0,0 @@ -

Disclaimer

-

This Website is not a part of youtube or google

- -

Infos

-

- Contact the owner:

- Email: myhamstermail@gmail.com
- GitHub: github.com/Feuerhamster
- -

- - Where do we have the data of the youtube videos?

- We use the official data from the youtube.com website. All URLs and metadata come from the respective page of the corresponding Youtube video.

- -

- - Is the downloading of youtube videos lawful?

- Everyone is allowed to download public Youtube videos for private use.

- -

- - Does this website violate laws and regulations such as once "convert2mp3"?

- No. On "convert2mp3" the videos were converted on the servers of the provider and made available for download.
- On our website, you download the videos directly from the sources on the google server. - -

\ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..3b4ad14 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1815 @@ +{ + "name": "web-youtube-downloader", + "version": "2.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "version": "2.0.0", + "license": "ISC", + "dependencies": { + "express": "^4.17.1", + "node-cache": "^5.1.2", + "pug": "^3.0.2", + "typescript": "^4.2.3", + "ytdl-core": "^4.8.2" + }, + "devDependencies": { + "@types/express": "^4.17.11" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.7.tgz", + "integrity": "sha512-X67Z5y+VBJuHB/RjwECp8kSl5uYi0BvRbNeWqkaJCVh+LiTPl19WBUfG627psSgp9rSf6ojuXghQM3ha6qHHdA==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.5.tgz", + "integrity": "sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.14.5", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.34", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz", + "integrity": "sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.12", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.12.tgz", + "integrity": "sha512-pTYas6FrP15B1Oa0bkN5tQMNqOcVXa9j4FTFtO8DWI9kppKib+6NJtfTOOLcwxuuYvcX2+dVG6et1SxW/Kc17Q==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.22", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.22.tgz", + "integrity": "sha512-WdqmrUsRS4ootGha6tVwk/IVHM1iorU8tGehftQD2NWiPniw/sm7xdJOIlXLwqdInL9wBw/p7oO8vaYEF3NDmA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "node_modules/@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "dev": true + }, + "node_modules/@types/node": { + "version": "15.12.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.5.tgz", + "integrity": "sha512-se3yX7UHv5Bscf8f1ERKvQOD6sTyycH3hdaoozvaLxgUiY5lIGEeH37AD0G0Qi9kPqihPn0HOfd2yaIEN9VwEg==", + "dev": true + }, + "node_modules/@types/qs": { + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.6.tgz", + "integrity": "sha512-0/HnwIfW4ki2D8L8c9GVcG5I72s9jP5GSLVF0VIXDW00kmIpA6O33G7a8n59Tmh7Nz0WUC3rSb7PTY/sdW2JzA==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", + "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==", + "dev": true + }, + "node_modules/@types/serve-static": { + "version": "1.13.9", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.9.tgz", + "integrity": "sha512-ZFqF6qa48XsPdjXV5Gsz0Zqmux2PerNd3a/ktL45mHpa19cuMi/cL8tcxdAx497yRh+QtYPuofjT9oWw9P7nkA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dependencies": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + }, + "node_modules/assert-never": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.2.1.tgz", + "integrity": "sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw==" + }, + "node_modules/babel-walk": { + "version": "3.0.0-canary-5", + "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz", + "integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==", + "dependencies": { + "@babel/types": "^7.9.6" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dependencies": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/character-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", + "integrity": "sha1-x84o821LzZdE5f/CxfzeHHMmH8A=", + "dependencies": { + "is-regex": "^1.0.3" + } + }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/constantinople": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz", + "integrity": "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==", + "dependencies": { + "@babel/parser": "^7.6.0", + "@babel/types": "^7.6.1" + } + }, + "node_modules/content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "node_modules/doctypes": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", + "integrity": "sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk=" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "dependencies": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-core-module": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", + "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-expression": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz", + "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==", + "dependencies": { + "acorn": "^7.1.1", + "object-assign": "^4.1.1" + } + }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" + }, + "node_modules/is-regex": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", + "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", + "dependencies": { + "call-bind": "^1.0.2", + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/js-stringify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", + "integrity": "sha1-Fzb939lyTyijaCrcYjCufk6Weds=" + }, + "node_modules/jstransformer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", + "integrity": "sha1-7Yvwkh4vPx7U1cGkT2hwntJHIsM=", + "dependencies": { + "is-promise": "^2.0.0", + "promise": "^7.0.1" + } + }, + "node_modules/m3u8stream": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/m3u8stream/-/m3u8stream-0.8.4.tgz", + "integrity": "sha512-sco80Db+30RvcaIOndenX6E6oQNgTiBKeJbFPc+yDXwPQIkryfboEbCvXPlBRq3mQTCVPQO93TDVlfRwqpD35w==", + "dependencies": { + "miniget": "^4.0.0", + "sax": "^1.2.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.48.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", + "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.31", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", + "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", + "dependencies": { + "mime-db": "1.48.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/miniget": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/miniget/-/miniget-4.2.1.tgz", + "integrity": "sha512-O/DduzDR6f+oDtVype9S/Qu5hhnx73EDYGyZKwU/qN82lehFZdfhoa4DT51SpsO+8epYrB3gcRmws56ROfTIoQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-cache": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz", + "integrity": "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==", + "dependencies": { + "clone": "2.x" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "node_modules/promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dependencies": { + "asap": "~2.0.3" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pug": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.2.tgz", + "integrity": "sha512-bp0I/hiK1D1vChHh6EfDxtndHji55XP/ZJKwsRqrz6lRia6ZC2OZbdAymlxdVFwd1L70ebrVJw4/eZ79skrIaw==", + "dependencies": { + "pug-code-gen": "^3.0.2", + "pug-filters": "^4.0.0", + "pug-lexer": "^5.0.1", + "pug-linker": "^4.0.0", + "pug-load": "^3.0.0", + "pug-parser": "^6.0.0", + "pug-runtime": "^3.0.1", + "pug-strip-comments": "^2.0.0" + } + }, + "node_modules/pug-attrs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz", + "integrity": "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==", + "dependencies": { + "constantinople": "^4.0.1", + "js-stringify": "^1.0.2", + "pug-runtime": "^3.0.0" + } + }, + "node_modules/pug-code-gen": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.2.tgz", + "integrity": "sha512-nJMhW16MbiGRiyR4miDTQMRWDgKplnHyeLvioEJYbk1RsPI3FuA3saEP8uwnTb2nTJEKBU90NFVWJBk4OU5qyg==", + "dependencies": { + "constantinople": "^4.0.1", + "doctypes": "^1.1.0", + "js-stringify": "^1.0.2", + "pug-attrs": "^3.0.0", + "pug-error": "^2.0.0", + "pug-runtime": "^3.0.0", + "void-elements": "^3.1.0", + "with": "^7.0.0" + } + }, + "node_modules/pug-error": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.0.0.tgz", + "integrity": "sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ==" + }, + "node_modules/pug-filters": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz", + "integrity": "sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==", + "dependencies": { + "constantinople": "^4.0.1", + "jstransformer": "1.0.0", + "pug-error": "^2.0.0", + "pug-walk": "^2.0.0", + "resolve": "^1.15.1" + } + }, + "node_modules/pug-lexer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz", + "integrity": "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==", + "dependencies": { + "character-parser": "^2.2.0", + "is-expression": "^4.0.0", + "pug-error": "^2.0.0" + } + }, + "node_modules/pug-linker": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz", + "integrity": "sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==", + "dependencies": { + "pug-error": "^2.0.0", + "pug-walk": "^2.0.0" + } + }, + "node_modules/pug-load": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz", + "integrity": "sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==", + "dependencies": { + "object-assign": "^4.1.1", + "pug-walk": "^2.0.0" + } + }, + "node_modules/pug-parser": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz", + "integrity": "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==", + "dependencies": { + "pug-error": "^2.0.0", + "token-stream": "1.0.0" + } + }, + "node_modules/pug-runtime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz", + "integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==" + }, + "node_modules/pug-strip-comments": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz", + "integrity": "sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==", + "dependencies": { + "pug-error": "^2.0.0" + } + }, + "node_modules/pug-walk": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz", + "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==" + }, + "node_modules/qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dependencies": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dependencies": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "node_modules/send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + }, + "node_modules/serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "engines": { + "node": ">=4" + } + }, + "node_modules/toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/token-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz", + "integrity": "sha1-zCAOqyYT9BZtJ/+a/HylbUnfbrQ=" + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.4.tgz", + "integrity": "sha512-uauPG7XZn9F/mo+7MrsRjyvbxFpzemRjKEZXS4AK83oP2KKOJPvb+9cO/gmnv8arWZvhnjVOXz7B49m1l0e9Ew==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha1-YU9/v42AHwu18GYfWy9XhXUOTwk=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/with": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz", + "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==", + "dependencies": { + "@babel/parser": "^7.9.6", + "@babel/types": "^7.9.6", + "assert-never": "^1.2.1", + "babel-walk": "3.0.0-canary-5" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/ytdl-core": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/ytdl-core/-/ytdl-core-4.8.3.tgz", + "integrity": "sha512-cWCBeX4FCgjcKmuVK384MT582RIAakpUSeMF/NPVmhO8cWiG+LeQLnBordvLolb0iXYzfUvalgmycYAE5Sy6Xw==", + "dependencies": { + "m3u8stream": "^0.8.3", + "miniget": "^4.0.0", + "sax": "^1.1.3" + }, + "engines": { + "node": ">=10" + } + } + }, + "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==" + }, + "@babel/parser": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.7.tgz", + "integrity": "sha512-X67Z5y+VBJuHB/RjwECp8kSl5uYi0BvRbNeWqkaJCVh+LiTPl19WBUfG627psSgp9rSf6ojuXghQM3ha6qHHdA==" + }, + "@babel/types": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.5.tgz", + "integrity": "sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==", + "requires": { + "@babel/helper-validator-identifier": "^7.14.5", + "to-fast-properties": "^2.0.0" + } + }, + "@types/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.34", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz", + "integrity": "sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/express": { + "version": "4.17.12", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.12.tgz", + "integrity": "sha512-pTYas6FrP15B1Oa0bkN5tQMNqOcVXa9j4FTFtO8DWI9kppKib+6NJtfTOOLcwxuuYvcX2+dVG6et1SxW/Kc17Q==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.22", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.22.tgz", + "integrity": "sha512-WdqmrUsRS4ootGha6tVwk/IVHM1iorU8tGehftQD2NWiPniw/sm7xdJOIlXLwqdInL9wBw/p7oO8vaYEF3NDmA==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "dev": true + }, + "@types/node": { + "version": "15.12.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.5.tgz", + "integrity": "sha512-se3yX7UHv5Bscf8f1ERKvQOD6sTyycH3hdaoozvaLxgUiY5lIGEeH37AD0G0Qi9kPqihPn0HOfd2yaIEN9VwEg==", + "dev": true + }, + "@types/qs": { + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.6.tgz", + "integrity": "sha512-0/HnwIfW4ki2D8L8c9GVcG5I72s9jP5GSLVF0VIXDW00kmIpA6O33G7a8n59Tmh7Nz0WUC3rSb7PTY/sdW2JzA==", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", + "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==", + "dev": true + }, + "@types/serve-static": { + "version": "1.13.9", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.9.tgz", + "integrity": "sha512-ZFqF6qa48XsPdjXV5Gsz0Zqmux2PerNd3a/ktL45mHpa19cuMi/cL8tcxdAx497yRh+QtYPuofjT9oWw9P7nkA==", + "dev": true, + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + }, + "assert-never": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.2.1.tgz", + "integrity": "sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw==" + }, + "babel-walk": { + "version": "3.0.0-canary-5", + "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz", + "integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==", + "requires": { + "@babel/types": "^7.9.6" + } + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + } + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "character-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", + "integrity": "sha1-x84o821LzZdE5f/CxfzeHHMmH8A=", + "requires": { + "is-regex": "^1.0.3" + } + }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=" + }, + "constantinople": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz", + "integrity": "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==", + "requires": { + "@babel/parser": "^7.6.0", + "@babel/types": "^7.6.1" + } + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "doctypes": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", + "integrity": "sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk=" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-core-module": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", + "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", + "requires": { + "has": "^1.0.3" + } + }, + "is-expression": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz", + "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==", + "requires": { + "acorn": "^7.1.1", + "object-assign": "^4.1.1" + } + }, + "is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" + }, + "is-regex": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", + "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", + "requires": { + "call-bind": "^1.0.2", + "has-symbols": "^1.0.2" + } + }, + "js-stringify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", + "integrity": "sha1-Fzb939lyTyijaCrcYjCufk6Weds=" + }, + "jstransformer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", + "integrity": "sha1-7Yvwkh4vPx7U1cGkT2hwntJHIsM=", + "requires": { + "is-promise": "^2.0.0", + "promise": "^7.0.1" + } + }, + "m3u8stream": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/m3u8stream/-/m3u8stream-0.8.4.tgz", + "integrity": "sha512-sco80Db+30RvcaIOndenX6E6oQNgTiBKeJbFPc+yDXwPQIkryfboEbCvXPlBRq3mQTCVPQO93TDVlfRwqpD35w==", + "requires": { + "miniget": "^4.0.0", + "sax": "^1.2.4" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.48.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", + "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==" + }, + "mime-types": { + "version": "2.1.31", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", + "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", + "requires": { + "mime-db": "1.48.0" + } + }, + "miniget": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/miniget/-/miniget-4.2.1.tgz", + "integrity": "sha512-O/DduzDR6f+oDtVype9S/Qu5hhnx73EDYGyZKwU/qN82lehFZdfhoa4DT51SpsO+8epYrB3gcRmws56ROfTIoQ==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "node-cache": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz", + "integrity": "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==", + "requires": { + "clone": "2.x" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "requires": { + "asap": "~2.0.3" + } + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "pug": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.2.tgz", + "integrity": "sha512-bp0I/hiK1D1vChHh6EfDxtndHji55XP/ZJKwsRqrz6lRia6ZC2OZbdAymlxdVFwd1L70ebrVJw4/eZ79skrIaw==", + "requires": { + "pug-code-gen": "^3.0.2", + "pug-filters": "^4.0.0", + "pug-lexer": "^5.0.1", + "pug-linker": "^4.0.0", + "pug-load": "^3.0.0", + "pug-parser": "^6.0.0", + "pug-runtime": "^3.0.1", + "pug-strip-comments": "^2.0.0" + } + }, + "pug-attrs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz", + "integrity": "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==", + "requires": { + "constantinople": "^4.0.1", + "js-stringify": "^1.0.2", + "pug-runtime": "^3.0.0" + } + }, + "pug-code-gen": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.2.tgz", + "integrity": "sha512-nJMhW16MbiGRiyR4miDTQMRWDgKplnHyeLvioEJYbk1RsPI3FuA3saEP8uwnTb2nTJEKBU90NFVWJBk4OU5qyg==", + "requires": { + "constantinople": "^4.0.1", + "doctypes": "^1.1.0", + "js-stringify": "^1.0.2", + "pug-attrs": "^3.0.0", + "pug-error": "^2.0.0", + "pug-runtime": "^3.0.0", + "void-elements": "^3.1.0", + "with": "^7.0.0" + } + }, + "pug-error": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.0.0.tgz", + "integrity": "sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ==" + }, + "pug-filters": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz", + "integrity": "sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==", + "requires": { + "constantinople": "^4.0.1", + "jstransformer": "1.0.0", + "pug-error": "^2.0.0", + "pug-walk": "^2.0.0", + "resolve": "^1.15.1" + } + }, + "pug-lexer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz", + "integrity": "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==", + "requires": { + "character-parser": "^2.2.0", + "is-expression": "^4.0.0", + "pug-error": "^2.0.0" + } + }, + "pug-linker": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz", + "integrity": "sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==", + "requires": { + "pug-error": "^2.0.0", + "pug-walk": "^2.0.0" + } + }, + "pug-load": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz", + "integrity": "sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==", + "requires": { + "object-assign": "^4.1.1", + "pug-walk": "^2.0.0" + } + }, + "pug-parser": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz", + "integrity": "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==", + "requires": { + "pug-error": "^2.0.0", + "token-stream": "1.0.0" + } + }, + "pug-runtime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz", + "integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==" + }, + "pug-strip-comments": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz", + "integrity": "sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==", + "requires": { + "pug-error": "^2.0.0" + } + }, + "pug-walk": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz", + "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==" + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "token-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz", + "integrity": "sha1-zCAOqyYT9BZtJ/+a/HylbUnfbrQ=" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typescript": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.4.tgz", + "integrity": "sha512-uauPG7XZn9F/mo+7MrsRjyvbxFpzemRjKEZXS4AK83oP2KKOJPvb+9cO/gmnv8arWZvhnjVOXz7B49m1l0e9Ew==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha1-YU9/v42AHwu18GYfWy9XhXUOTwk=" + }, + "with": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz", + "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==", + "requires": { + "@babel/parser": "^7.9.6", + "@babel/types": "^7.9.6", + "assert-never": "^1.2.1", + "babel-walk": "3.0.0-canary-5" + } + }, + "ytdl-core": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/ytdl-core/-/ytdl-core-4.8.3.tgz", + "integrity": "sha512-cWCBeX4FCgjcKmuVK384MT582RIAakpUSeMF/NPVmhO8cWiG+LeQLnBordvLolb0iXYzfUvalgmycYAE5Sy6Xw==", + "requires": { + "m3u8stream": "^0.8.3", + "miniget": "^4.0.0", + "sax": "^1.1.3" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..3ab6423 --- /dev/null +++ b/package.json @@ -0,0 +1,30 @@ +{ + "name": "web-youtube-downloader", + "version": "2.0.0", + "description": "Download YouTube videos from source", + "main": "dist/main.js", + "scripts": { + "start": "node dist/main.js", + "build": "tsc" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Feuerhamster/web-youtube-downloader.git" + }, + "author": "Feuerhamster", + "license": "ISC", + "bugs": { + "url": "https://github.com/Feuerhamster/web-youtube-downloader/issues" + }, + "homepage": "https://github.com/Feuerhamster/web-youtube-downloader#readme", + "dependencies": { + "express": "^4.17.1", + "node-cache": "^5.1.2", + "pug": "^3.0.2", + "typescript": "^4.2.3", + "ytdl-core": "^4.8.2" + }, + "devDependencies": { + "@types/express": "^4.17.11" + } +} diff --git a/public/logo.png b/public/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..56d6f759f65ca18821da31f559f523caa10e6247 GIT binary patch literal 20684 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%0Al11R3MT@;Q;mzbY&E48qhrl7-LVL})3`Gl6 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 N002ovPDHLkV1hOYs>1*P literal 0 HcmV?d00001 diff --git a/public/style.css b/public/style.css new file mode 100644 index 0000000..5193769 --- /dev/null +++ b/public/style.css @@ -0,0 +1,200 @@ +/* +* Main styles +*/ +* { + box-sizing: border-box; +} + +html, body { + min-height: 100%; + width: 100%; + margin: 0; + font-family: sans-serif; +} + +body { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + color: #222; + background-color: #fafafa; + padding: 20px; +} + +/* +* titlebox +*/ +.title-box { + display: flex; + align-items: center; + margin-bottom: 20px; +} + +.title-box > img { + max-height: 100px; + border-radius: 6px; + margin-right: 30px; + box-shadow: 1px 1px 12px rgba(0, 0, 0, 0.2); +} + +.title-box h1 { + font-size: 32px; + margin: 0 0 20px 0; +} + +.title-box a { + margin: 5px; + font-size: 18px; + color: #2481e6; + text-decoration: none; +} + +.title-box a:hover { + text-decoration: underline; +} + +/* +* responsive element +*/ +.responsive { + display: flex; + flex-direction: column; + flex-grow: 1; + justify-content: center; + align-items: stretch; + max-width: 720px; +} + +.responsive > h1 { + font-size: 32px; + margin: 20px 0; +} + +.responsive > h2 { + font-size: 24px; + margin: 20px 0; +} + +.responsive input { + border: 2px solid #ddd; + padding: 10px 14px; + border-radius: 6px; + font-size: 18px; + outline: 0; + margin-right: 10px; + background-color: white; +} + +button { + background-color: #eb6161; + cursor: pointer; + border: none; + color: white; + padding: 10px 14px; + border-radius: 6px; + font-size: 18px; + outline: 0; +} + +button:hover { + background-color: #c32e2e; +} + +.content { + display: flex; + flex-direction: column; + align-items: stretch; + max-width: 720px; +} + +.center { + display: flex; + flex-direction: column; + align-items: center; +} + +/* +* Table +*/ + +table { + width: 100%; + border-collapse: collapse; + overflow: auto; +} + +td, th { + border-bottom: 2px solid #ddd; + padding: 10px; + text-align: left; +} + +tr:last-child > td { + border: 0; +} + +tr:hover td { + background-color: rgba(0, 0, 0, 0.05); +} + +td a { + color: #3488ee; + text-decoration: none; +} + +td a:hover { + text-decoration: underline; +} + +td img { + max-height: 70px; +} + +/* +* Format label +*/ +.format { + color: white; + padding: 2px 5px; + border-radius: 3px; +} + +.format-0 { + background-color: #43c043; +} + +.format-1 { + background-color: #3488ee; +} + +.format-2 { + background-color: #EE6565; +} + +td.mp4 { + color: #f38a00; + font-weight: bold; +} + +td.webm { + color: #3488ee; + font-weight: bold; +} + +/* +* Iframe +*/ + +iframe { + height: 355px; +} + +@media only screen and (max-width: 720px) { + .responsive { + width: 100%; + } + table.formats th:nth-child(5), table.formats td:nth-child(5) { + display: none; + } +} \ No newline at end of file diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..f16f2db --- /dev/null +++ b/src/main.ts @@ -0,0 +1,15 @@ +import express, { Application } from "express"; +import defaultRoute from "./routes/default"; + +const app: Application = express(); +const port: number = parseInt(process.env.PORT) || 4131; + +app.set("views", "views"); +app.set("view engine", "pug"); + +app.use(express.static("public")); +app.use(defaultRoute); + +app.listen(port, () => { + console.log("App started on port: " + port); +}); \ No newline at end of file diff --git a/src/routes/default.ts b/src/routes/default.ts new file mode 100644 index 0000000..3bffa0d --- /dev/null +++ b/src/routes/default.ts @@ -0,0 +1,29 @@ +import {Request, Response, Router} from "express"; +import {VideoData} from "../types/youtube"; +import {YouTube} from "../services/youtube"; + +const router: Router = Router(); + +router.get("/", async (req: Request, res: Response) => { + + // No video searched -> startpage + if(!req.query.url) { + res.render("index"); + return; + } + + let video: VideoData = await YouTube.getVideoInfo(req.query.url); + + // Cant get video -> error page + if(!video) { + res.render("error"); + return; + } + + res.render("video", video); + +}); + +router.get("/about", (req, res) => res.render("about")); + +export default router; \ No newline at end of file diff --git a/src/services/youtube.ts b/src/services/youtube.ts new file mode 100644 index 0000000..8a75a6a --- /dev/null +++ b/src/services/youtube.ts @@ -0,0 +1,56 @@ +import ytdl, {videoInfo} from "ytdl-core"; +import {FormatType, VideoData} from "../types/youtube"; +import NodeCache from "node-cache"; + +export class YouTube { + + private static cache = new NodeCache({ stdTTL: 3600 }); + + static async getVideoInfo(url): Promise { + + if(this.cache.has(url)) { + return this.cache.get(url); + } + + let video: videoInfo = null; + let videoData: VideoData = {}; + + // Get video info + try { + video = await ytdl.getInfo(url.toString()); + } catch(e) { + return null; + } + + // format info data + videoData.id = video.videoDetails.videoId; + videoData.url = video.videoDetails.video_url; + videoData.title = video.videoDetails.title; + videoData.author = video.videoDetails.author.name; + + videoData.thumbnails = video.videoDetails.thumbnails.map((t) => ({ + url: t.url, + size: `${t.width}x${t.height}` + })); + + videoData.formats = video.formats.map((f) => ({ + type: f.hasVideo && f.hasAudio ? FormatType.main : f.hasVideo ? FormatType.video : FormatType.audio, + quality: f.qualityLabel, + container: f.container, + codecs: f.codecs, + url: f.url, + bitrate: f.bitrate.toString().replace(/\B(?=(\d{3})+(?!\d))/g, " ") + })); + + videoData.formats = videoData.formats.sort((a, b) => a.type < b.type ? -1 : a.type > b.type ? 1 : 0); + + // Save to cache + if(!this.cache.has(url)) { + this.cache.set(url, videoData); + } + + return videoData; + + } + +} \ No newline at end of file diff --git a/src/types/youtube.ts b/src/types/youtube.ts new file mode 100644 index 0000000..ec3c690 --- /dev/null +++ b/src/types/youtube.ts @@ -0,0 +1,26 @@ +export interface VideoData { + id: string; + title: string; + author: string; + url: string; + thumbnails: Thumbnail[]; + formats: Format[] +} + +export interface Thumbnail { + url: string; + size: string +} + +export interface Format { + type: FormatType + quality: string; + container: string; + codecs: string; + url: string; + bitrate: string +} + +export enum FormatType { + main, audio, video +} \ No newline at end of file diff --git a/style.css b/style.css deleted file mode 100644 index 31af639..0000000 --- a/style.css +++ /dev/null @@ -1,183 +0,0 @@ -body, html{ - margin: 0px; - height: 100%; - width: 100%; - font-family: 'Muli', sans-serif; -} - -*{ - box-sizing: border-box; -} - -h1, h2, h3, h4, h5, h6, p{ - color: rgb(50,50,50); -} - -@media (max-width:901px){ - .box-mobile{ - flex-direction: column!important; - align-items: center; - } - .box{ - flex-wrap: wrap; - } - #head-text{ - display: none; - } -} - -.pre{ - background-color: rgba(240,240,240); - border: 2px solid rgba(230,230,230); - border-radius: 2px; - padding: 10px; - font-family: 'Courier New', Courier, monospace; - color: rgb(50,50,50); - overflow-x: auto; - margin-top: 20px; - margin-bottom: 20px; - white-space: pre; -} - -#head-bar{ - display: flex; - align-items: flex-start; - background-color: #d63030; - padding: 5px; - box-shadow: 0px 0px 5px 1px rgba(0,0,0,0.3); - position: relative; -} - -#head-bar > h1{ - color: white; - margin: 0px; - font-family: 'Muli', sans-serif; - font-size: 28px; - padding: 2px; -} - -.spacer{ - flex-grow: 1; -} - -#head-bar > input{ - background-color: rgba(255,255,255,0.3); - border: 0; - padding: 8px; - margin: 2px; - font-size: 16px; - color: white; - font-family: 'Muli', sans-serif; - min-width: 300px; - border-radius: 2px; -} - -#head-bar > input:focus{ - box-shadow: 0px 0px 5px 1px rgba(70,70,70,0.2); -} - -#content{ - display: flex; - width: 100%; - min-height: calc(100% - 93px); - flex-direction: column; - background-color: rgb(250,250,250); - padding: 30px; -} - -#home-page{ - display: flex; - align-items: center; - justify-content: center; - height: 100%; - width: 100%; - flex-direction: column; -} - -#home-page > input{ - background-color: #f04f4f; - border: 0; - padding: 10px; - margin: 5px; - font-size: 18px; - font-family: 'Muli', sans-serif; - min-width: 400px; - border-radius: 2px; - color: white; -} -#home-page > input:focus{ - box-shadow: 0px 0px 2px 1px rgba(180,180,180,1); -} - -footer{ - padding: 10px; - display: flex; - justify-content: center; - background-color: rgb(250,250,250); -} -footer > a{ - font-size: 18px; - margin-left: 10px; - margin-right: 10px; - color: rgb(100, 100, 100); -} - -footer > a:hover{ - color: rgb(70, 70, 70); -} - -.box{ - background-color: white; - padding: 10px; - box-shadow: 0px 0px 4px 1px rgba(0,0,0,0.2); - display: flex; - margin: 10px 0px 10px 0px; - flex-direction: row; -} - -.label{ - display: inline-block; - margin: 5px; -} -.label > .label-name{ - background-color: rgb(120,120,120); - color: white; - padding: 2px 5px 2px 5px; - border-radius: 2px 0px 0px 2px; -} - -.label-value{ - color: white; - padding: 2px 5px 2px 5px; - border-radius: 0px 2px 2px 0px; -} -.label > .label-blue{ - background-color: #3498db; -} -.label > .label-red{ - background-color: #e74c3c; -} -.label > .label-green{ - background-color: #27ae60; -} -.label > .label-orange{ - background-color: #e49517; -} -.label > .label-purble{ - background-color: #8a52a0; -} - -.download-link-large{ - color: white; - font-size: 24px; - text-decoration: none; - background-color: #0984e3; - padding: 5px 10px 5px 10px; - border-radius: 2px; - box-shadow: 0px 0px 4px 1px rgba(0,0,0,0.2); - margin-top: 10px; - display: inline-block; -} -.download-link-large:hover{ - background-color: #0569b6; -} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..1a7af54 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es5", + "sourceMap": true, + "moduleResolution": "node", + "esModuleInterop": true, + "outDir": "dist" + }, + "exclude": [ + "node_modules" + ] +} \ No newline at end of file diff --git a/views/_layout.pug b/views/_layout.pug new file mode 100644 index 0000000..556064d --- /dev/null +++ b/views/_layout.pug @@ -0,0 +1,12 @@ +doctype html +html(lang="en") + head + title Web YouTube Downloader + meta(name="description" content="Download YouTube videos from source!") + meta(charset="utf-8") + meta(name="viewport" content="width=device-width, initial-scale=1.0") + link(rel="stylesheet" href="style.css") + body + div.responsive + include partials/titlebox + block content \ No newline at end of file diff --git a/views/about.pug b/views/about.pug new file mode 100644 index 0000000..61fe4b9 --- /dev/null +++ b/views/about.pug @@ -0,0 +1,17 @@ +extends _layout + +block content + h1 About + h2 Disclaimer + p This Website is not a part of YouTube or Google. + + h2 Where do we have the data of the youtube videos? + p We use the official data from the youtube.com website. All URLs and metadata come from the respective page of the corresponding Youtube video. + + h2 Is the downloading of youtube videos lawful? + p Everyone is allowed to download public Youtube videos for private use. + + h2 Does this website violate laws and regulations such as once "convert2mp3"? + p + | No. On "convert2mp3" the videos were converted on the servers of the provider and made available for download. + | On our website, you download the videos directly from the sources on the google server. \ No newline at end of file diff --git a/views/error.pug b/views/error.pug new file mode 100644 index 0000000..a237c85 --- /dev/null +++ b/views/error.pug @@ -0,0 +1,4 @@ +extends _layout + +block content + h1 Cannot fetch video \ No newline at end of file diff --git a/views/index.pug b/views/index.pug new file mode 100644 index 0000000..eeafc4f --- /dev/null +++ b/views/index.pug @@ -0,0 +1,10 @@ +extends _layout + +block content + div.center + h1 Download YouTube videos from source! + h2 All Video and Audio Tracks + Thumbnails + + form + input(type="url" placeholder="Paste a YouTube video url" name="url") + button Fetch \ No newline at end of file diff --git a/views/partials/titlebox.pug b/views/partials/titlebox.pug new file mode 100644 index 0000000..007909b --- /dev/null +++ b/views/partials/titlebox.pug @@ -0,0 +1,8 @@ +div.title-box + img(src="logo.png") + div + h1 Web YouTube Downloader + nav + a(href="/") Startpage + a(href="/about") About + a(href="https://github.com/Feuerhamster/web-youtube-downloader/" target="_blank" rel="noopener") GitHub \ No newline at end of file diff --git a/views/video.pug b/views/video.pug new file mode 100644 index 0000000..fb0c59f --- /dev/null +++ b/views/video.pug @@ -0,0 +1,48 @@ +extends _layout + +block content + h2 Video + iframe(src="https://www.youtube.com/embed/" + id frameborder="0" allow="autoplay; encrypted-media") + + h2 Formats + + table.formats + tr + th Format + th Quality + th Bitrate + th Container + th Codecs + th URL + each format in formats + tr + td + case format.type + when 0 + span.format.format-0 Video + when 1 + span.format.format-1 Audio + when 2 + span.format.format-2 Adaptive + + td= format.quality + td= format.bitrate + td(class=format.container)= format.container + td= format.codecs + td + a(href=format.url target="_blank" rel="noreferrer") Download + + h2 Thumbnails + table + tr + th Image + th Size + th Download + each thumbnail in thumbnails + tr + td + img(src=thumbnail.url) + + td= thumbnail.size + td + a(href=thumbnail.url target="_blank" rel="noreferrer") Download \ No newline at end of file