조인천

ver3

Showing 121 changed files with 9300 additions and 4 deletions
var request = require('request');
var optionParams = {
q:"kakao",
q:"저라뎃",
part:"snippet",
key:"AIzaSyCgGa6aM7taXs4bajtYukbc_EQAKTLVTNc",
maxResult2:5
type:"video",
maxResult2:5,
regionCode:"KR",
videoDuration:"short"
};
optionParams.q = encodeURI(optionParams.q);
var url = "https://www.googleapis.com/youtube/v3/search?";
for (var option in optionParams)
{
......@@ -14,6 +19,33 @@ for (var option in optionParams)
url = url.substr(0,url.length-1);
var VideoIds = new Array();
var idx = 0;
request(url, function(err,res,body){
console.log(body)
});
\ No newline at end of file
//console.log(body)
var data = JSON.parse(body).items;
for(var content in data)
{
VideoIds[idx]=(data[content].id.videoId);
idx++;
}
console.log(VideoIds.length);
console.log(VideoIds[0]);
console.log(typeof(VideoIds[1]));
//다운로드 부분
var fs = require('fs');
var youtubedl = require('youtube-dl');
var video = youtubedl('http://www.youtube.com/watch?v='.concat(VideoIds[1]));
video.on('info',function(info)
{
console.log('Download started');
console.log('filename : '+ info.filename);
console.log('size : '+info.size);
});
video.pipe(fs.createWriteStream('justlikethat.mp4'));
});
......
This file is too large to display.
This file is too large to display.
This file is too large to display.
This file is too large to display.
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../mkdirp/bin/cmd.js" "$@"
ret=$?
else
node "$basedir/../mkdirp/bin/cmd.js" "$@"
ret=$?
fi
exit $ret
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\mkdirp\bin\cmd.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\mkdirp\bin\cmd.js" %*
)
\ No newline at end of file
<a name="2.0.0"></a>
# 2.0.0 (2019-05-22)
* build: be possible setup downloader for windows ([8111957](https://github.com/przemyslawpluta/node-youtube-dl/commit/8111957))
* build: improve workflow ([5ce37dd](https://github.com/przemyslawpluta/node-youtube-dl/commit/5ce37dd))
* build: improve workflow ([9ff909e](https://github.com/przemyslawpluta/node-youtube-dl/commit/9ff909e))
* build: setup node version ([41f0a80](https://github.com/przemyslawpluta/node-youtube-dl/commit/41f0a80))
* build: setup properly release message ([8f7a11b](https://github.com/przemyslawpluta/node-youtube-dl/commit/8f7a11b))
* build: take end on consideration ([66e1324](https://github.com/przemyslawpluta/node-youtube-dl/commit/66e1324))
* refactor: remove dead code ([1a74f06](https://github.com/przemyslawpluta/node-youtube-dl/commit/1a74f06))
<a name="1.13.5"></a>
## 1.13.5 (2019-05-22)
* Fix non-json outputs ([cfff104](https://github.com/przemyslawpluta/node-youtube-dl/commit/cfff104))
* Fix typo in comments ([e968072](https://github.com/przemyslawpluta/node-youtube-dl/commit/e968072))
* New has() method that replaces arr.indexOf where applicable ([5ec1f87](https://github.com/przemyslawpluta/node-youtube-dl/commit/5ec1f87))
* Removed package-lock.json ([56cbc63](https://github.com/przemyslawpluta/node-youtube-dl/commit/56cbc63))
* Replace typeof === "string" with util.isString globally ([e3f4a9d](https://github.com/przemyslawpluta/node-youtube-dl/commit/e3f4a9d))
* Fix: Checking if we have args before testing them ([113ed2a](https://github.com/przemyslawpluta/node-youtube-dl/commit/113ed2a))
<a name="1.13.4"></a>
## 1.13.4 (2019-05-18)
* ci: update builds ([3977c65](https://github.com/przemyslawpluta/node-youtube-dl/commit/3977c65))
* Update youtube-dl.js ([bfc0a1d](https://github.com/przemyslawpluta/node-youtube-dl/commit/bfc0a1d))
<a name="1.13.3"></a>
## 1.13.3 (2019-05-16)
* test: update ([fd31af8](https://github.com/przemyslawpluta/node-youtube-dl/commit/fd31af8))
* fix: fix a regression caused by previous refactorings ([dfed31a](https://github.com/przemyslawpluta/node-youtube-dl/commit/dfed31a)), closes [#230](https://github.com/przemyslawpluta/node-youtube-dl/issues/230)
* Enable option to select subtitle formats ([4bc1caa](https://github.com/przemyslawpluta/node-youtube-dl/commit/4bc1caa))
<a name="1.13.2"></a>
## 1.13.2 (2019-03-29)
* Send header because gets 403 if cookie is needed ([91f3f69](https://github.com/przemyslawpluta/node-youtube-dl/commit/91f3f69))
<a name="1.13.1"></a>
## 1.13.1 (2019-02-04)
* Fixed typo & removed redundant line ([156bbd5](https://github.com/przemyslawpluta/node-youtube-dl/commit/156bbd5))
<a name="1.13.0"></a>
# 1.13.0 (2019-01-25)
* build: add release process ([8cc1b05](https://github.com/przemyslawpluta/node-youtube-dl/commit/8cc1b05))
* test: update snapshots ([65fb75e](https://github.com/przemyslawpluta/node-youtube-dl/commit/65fb75e))
* add editorconfig ([8a92f0b](https://github.com/przemyslawpluta/node-youtube-dl/commit/8a92f0b))
* add hms to duration, twitch test ([9ea3ff1](https://github.com/przemyslawpluta/node-youtube-dl/commit/9ea3ff1))
* add sensible `execFile` good defaults ([2524d75](https://github.com/przemyslawpluta/node-youtube-dl/commit/2524d75)), closes [#173](https://github.com/przemyslawpluta/node-youtube-dl/issues/173)
* Adding dashes before the video ID ([da8f4dd](https://github.com/przemyslawpluta/node-youtube-dl/commit/da8f4dd))
* changed to _filename in line 33 readme ([87d3891](https://github.com/przemyslawpluta/node-youtube-dl/commit/87d3891))
* Consider copyright videos as not available in order to continue on error ([e19d8d1](https://github.com/przemyslawpluta/node-youtube-dl/commit/e19d8d1))
* Consider not made available videos as not available in order to continue on error ([ae7ea3b](https://github.com/przemyslawpluta/node-youtube-dl/commit/ae7ea3b))
* Correct extension in playlist.js ([5d77436](https://github.com/przemyslawpluta/node-youtube-dl/commit/5d77436))
* Correct test with correct video info ([0ee2609](https://github.com/przemyslawpluta/node-youtube-dl/commit/0ee2609))
* Disable non-functional test ([ca1aa42](https://github.com/przemyslawpluta/node-youtube-dl/commit/ca1aa42))
* download best and combine is ffmpeg available ([2193220](https://github.com/przemyslawpluta/node-youtube-dl/commit/2193220))
* Download correct binary for windows systems ([3874a88](https://github.com/przemyslawpluta/node-youtube-dl/commit/3874a88))
* drop tests for 4,5 and version bump ([3634c67](https://github.com/przemyslawpluta/node-youtube-dl/commit/3634c67))
* Fix encoding issue on windows ([d65114d](https://github.com/przemyslawpluta/node-youtube-dl/commit/d65114d))
* Get and set path from youtube-dl ([161ed2a](https://github.com/przemyslawpluta/node-youtube-dl/commit/161ed2a))
* handle thumbnails download ([a0832dc](https://github.com/przemyslawpluta/node-youtube-dl/commit/a0832dc))
* hms and raw duration ([eb0e9de](https://github.com/przemyslawpluta/node-youtube-dl/commit/eb0e9de))
* meta tweaks ([f685ad7](https://github.com/przemyslawpluta/node-youtube-dl/commit/f685ad7))
* minor typo ([429b1f7](https://github.com/przemyslawpluta/node-youtube-dl/commit/429b1f7))
* missing ; ([05f8f62](https://github.com/przemyslawpluta/node-youtube-dl/commit/05f8f62))
* remove dead code ([4b1ba39](https://github.com/przemyslawpluta/node-youtube-dl/commit/4b1ba39))
* remove deprecated badge ([19a7b33](https://github.com/przemyslawpluta/node-youtube-dl/commit/19a7b33))
* remove lock ([0131daf](https://github.com/przemyslawpluta/node-youtube-dl/commit/0131daf))
* Remove size from download test, not relevant ([e22ee14](https://github.com/przemyslawpluta/node-youtube-dl/commit/e22ee14))
* remove vimeo tests ([1f717cc](https://github.com/przemyslawpluta/node-youtube-dl/commit/1f717cc))
* update dependencies ([bf28967](https://github.com/przemyslawpluta/node-youtube-dl/commit/bf28967))
* update snapshot ([70ec50a](https://github.com/przemyslawpluta/node-youtube-dl/commit/70ec50a))
* Update test about twitch (twitch id are not anymore the video title) ([b9f0317](https://github.com/przemyslawpluta/node-youtube-dl/commit/b9f0317))
* update travis builds ([efe313c](https://github.com/przemyslawpluta/node-youtube-dl/commit/efe313c))
* Updated test case since video title changed on twitch's end ([7c22361](https://github.com/przemyslawpluta/node-youtube-dl/commit/7c22361))
* use const over var ([6ed5a1c](https://github.com/przemyslawpluta/node-youtube-dl/commit/6ed5a1c))
<a name="1.12.1"></a>
## 1.12.1 (2017-09-28)
* cleanup ([68ea1df](https://github.com/przemyslawpluta/node-youtube-dl/commit/68ea1df))
* cleanup ([5efbce3](https://github.com/przemyslawpluta/node-youtube-dl/commit/5efbce3))
* concat args ([25ed267](https://github.com/przemyslawpluta/node-youtube-dl/commit/25ed267))
* correct repo url ([88ec7c8](https://github.com/przemyslawpluta/node-youtube-dl/commit/88ec7c8))
* Document how to increase buffer size ([3bb3e4d](https://github.com/przemyslawpluta/node-youtube-dl/commit/3bb3e4d))
* drop getFormats, update vimeo test ([da47d4d](https://github.com/przemyslawpluta/node-youtube-dl/commit/da47d4d))
* drop io.js tests ([b1fa4fb](https://github.com/przemyslawpluta/node-youtube-dl/commit/b1fa4fb))
* drop soundcloud due to ssl error on travis ([0c7168d](https://github.com/przemyslawpluta/node-youtube-dl/commit/0c7168d))
* drop tests for 0.10 ([473cdf6](https://github.com/przemyslawpluta/node-youtube-dl/commit/473cdf6))
* fix ([a6d6d36](https://github.com/przemyslawpluta/node-youtube-dl/commit/a6d6d36))
* Fix issue with duration not formatting correctly ([d9dd0ec](https://github.com/przemyslawpluta/node-youtube-dl/commit/d9dd0ec))
* fix package name ([5642547](https://github.com/przemyslawpluta/node-youtube-dl/commit/5642547))
* fix tests, update formatting ([796f922](https://github.com/przemyslawpluta/node-youtube-dl/commit/796f922))
* fixed downloader if user passed in a custom bin dir ([2954eed](https://github.com/przemyslawpluta/node-youtube-dl/commit/2954eed))
* Fixed tests assertion, video sizes changed probably due to change in streaming technology and title ([d2f7894](https://github.com/przemyslawpluta/node-youtube-dl/commit/d2f7894))
* hotfix for the electron issue ([ae7608c](https://github.com/przemyslawpluta/node-youtube-dl/commit/ae7608c))
* Make properties configurable ([dab402b](https://github.com/przemyslawpluta/node-youtube-dl/commit/dab402b))
* manage missing video array plus tests ([6f2840e](https://github.com/przemyslawpluta/node-youtube-dl/commit/6f2840e))
* py + node test ([cf2d5e1](https://github.com/przemyslawpluta/node-youtube-dl/commit/cf2d5e1))
* python test ([e6b597a](https://github.com/przemyslawpluta/node-youtube-dl/commit/e6b597a))
* Quickfix for Copy Error in Usage Example ([db27e8a](https://github.com/przemyslawpluta/node-youtube-dl/commit/db27e8a))
* skip error is video has been removed by the user ([5e94b13](https://github.com/przemyslawpluta/node-youtube-dl/commit/5e94b13))
* skip error is video has been removed by the user ([956056b](https://github.com/przemyslawpluta/node-youtube-dl/commit/956056b))
* ssl err test ([0738a25](https://github.com/przemyslawpluta/node-youtube-dl/commit/0738a25))
* test ([80d924a](https://github.com/przemyslawpluta/node-youtube-dl/commit/80d924a))
* travis ssl force ([6b0f0f8](https://github.com/przemyslawpluta/node-youtube-dl/commit/6b0f0f8))
* update audio.js ([17c3fb1](https://github.com/przemyslawpluta/node-youtube-dl/commit/17c3fb1))
* update build status ([1aa9d82](https://github.com/przemyslawpluta/node-youtube-dl/commit/1aa9d82))
* update details ([653f411](https://github.com/przemyslawpluta/node-youtube-dl/commit/653f411))
* update icons ([0399db6](https://github.com/przemyslawpluta/node-youtube-dl/commit/0399db6))
* update mode ([e83b336](https://github.com/przemyslawpluta/node-youtube-dl/commit/e83b336))
* update package ([2867fc5](https://github.com/przemyslawpluta/node-youtube-dl/commit/2867fc5))
* Update README.md ([76cb708](https://github.com/przemyslawpluta/node-youtube-dl/commit/76cb708))
* update tests ([d745285](https://github.com/przemyslawpluta/node-youtube-dl/commit/d745285))
* update travis env ([08fd355](https://github.com/przemyslawpluta/node-youtube-dl/commit/08fd355))
* update travis-ci ([339460b](https://github.com/przemyslawpluta/node-youtube-dl/commit/339460b))
* update youtube-dl permissions ([621b478](https://github.com/przemyslawpluta/node-youtube-dl/commit/621b478))
* updates & fixes ([8bc4839](https://github.com/przemyslawpluta/node-youtube-dl/commit/8bc4839))
* version bump ([a839a5f](https://github.com/przemyslawpluta/node-youtube-dl/commit/a839a5f))
<a name="1.11.1"></a>
## 1.11.1 (2016-04-06)
* add heroku support ([541e710](https://github.com/przemyslawpluta/node-youtube-dl/commit/541e710))
* version bump ([22abe25](https://github.com/przemyslawpluta/node-youtube-dl/commit/22abe25))
<a name="1.11.0"></a>
# 1.11.0 (2016-03-25)
* add getFormats example ([d9b2925](https://github.com/przemyslawpluta/node-youtube-dl/commit/d9b2925))
* add node 4 & 5 for testing ([8683ac1](https://github.com/przemyslawpluta/node-youtube-dl/commit/8683ac1))
* adding ability to continue partially downloaded files. ([e9e540a](https://github.com/przemyslawpluta/node-youtube-dl/commit/e9e540a))
* allow for external bin but keep details internally ([f35daab](https://github.com/przemyslawpluta/node-youtube-dl/commit/f35daab))
* As requested, I was trying to make the code as readable as possible ([38884d1](https://github.com/przemyslawpluta/node-youtube-dl/commit/38884d1))
* callback err ([f49128c](https://github.com/przemyslawpluta/node-youtube-dl/commit/f49128c))
* change bin permissions ([957172b](https://github.com/przemyslawpluta/node-youtube-dl/commit/957172b))
* check for datadir existence ([1817160](https://github.com/przemyslawpluta/node-youtube-dl/commit/1817160))
* choose bin location ([1123d33](https://github.com/przemyslawpluta/node-youtube-dl/commit/1123d33))
* cleanup ([12eb585](https://github.com/przemyslawpluta/node-youtube-dl/commit/12eb585))
* cleanup ([1a8b2f0](https://github.com/przemyslawpluta/node-youtube-dl/commit/1a8b2f0))
* cleanup .gitignore ([bf5b974](https://github.com/przemyslawpluta/node-youtube-dl/commit/bf5b974))
* dependencies bump ([f131dca](https://github.com/przemyslawpluta/node-youtube-dl/commit/f131dca))
* document `ytdl.exec()` with audio example ([2b8333f](https://github.com/przemyslawpluta/node-youtube-dl/commit/2b8333f))
* extract downloader ([f27c45a](https://github.com/przemyslawpluta/node-youtube-dl/commit/f27c45a))
* fix bin path ([6f9ef39](https://github.com/przemyslawpluta/node-youtube-dl/commit/6f9ef39))
* fix license meta in pacakge.json ([3d2f168](https://github.com/przemyslawpluta/node-youtube-dl/commit/3d2f168))
* fix resolution or audio ([d2a3269](https://github.com/przemyslawpluta/node-youtube-dl/commit/d2a3269))
* handle playlists ([acb1571](https://github.com/przemyslawpluta/node-youtube-dl/commit/acb1571))
* install module before download ([f3e0ac7](https://github.com/przemyslawpluta/node-youtube-dl/commit/f3e0ac7))
* missing dependency ([f56cb24](https://github.com/przemyslawpluta/node-youtube-dl/commit/f56cb24))
* move bin path to datadir ([7ef58ef](https://github.com/przemyslawpluta/node-youtube-dl/commit/7ef58ef))
* no longer maintaining ([1aa9076](https://github.com/przemyslawpluta/node-youtube-dl/commit/1aa9076))
* package postinstall ([c1f052f](https://github.com/przemyslawpluta/node-youtube-dl/commit/c1f052f))
* permission change on bin ([c061caa](https://github.com/przemyslawpluta/node-youtube-dl/commit/c061caa))
* permission change on bin cleanup test ([6912150](https://github.com/przemyslawpluta/node-youtube-dl/commit/6912150))
* preventing options being created if it doesn't exist ([894e215](https://github.com/przemyslawpluta/node-youtube-dl/commit/894e215))
* remove unused module ([6fc3f02](https://github.com/przemyslawpluta/node-youtube-dl/commit/6fc3f02))
* resolve to .exe on win ([2c5467e](https://github.com/przemyslawpluta/node-youtube-dl/commit/2c5467e))
* skip over not available videos during playlist download ([45ee26b](https://github.com/przemyslawpluta/node-youtube-dl/commit/45ee26b))
* store example videos in dir to keep things cleaner ([e7cc0d5](https://github.com/przemyslawpluta/node-youtube-dl/commit/e7cc0d5))
* update ([4da180b](https://github.com/przemyslawpluta/node-youtube-dl/commit/4da180b))
* update ([60a0cf4](https://github.com/przemyslawpluta/node-youtube-dl/commit/60a0cf4))
* update path ([b9992cf](https://github.com/przemyslawpluta/node-youtube-dl/commit/b9992cf))
* update readme ([c159427](https://github.com/przemyslawpluta/node-youtube-dl/commit/c159427))
* update readme ([a41b965](https://github.com/przemyslawpluta/node-youtube-dl/commit/a41b965))
* update README ([1565229](https://github.com/przemyslawpluta/node-youtube-dl/commit/1565229))
* update tests ([7be149d](https://github.com/przemyslawpluta/node-youtube-dl/commit/7be149d))
* Updating comment block for inline quotes, replacing double quotes with single quotes ([1646cec](https://github.com/przemyslawpluta/node-youtube-dl/commit/1646cec))
<a name="1.10.5"></a>
## 1.10.5 (2015-05-07)
* 1.10.5 ([d2d4eba](https://github.com/przemyslawpluta/node-youtube-dl/commit/d2d4eba))
* better check for `--format` ([dbaebb3](https://github.com/przemyslawpluta/node-youtube-dl/commit/dbaebb3))
<a name="1.10.4"></a>
## 1.10.4 (2015-05-07)
* 1.10.4 ([06ec68e](https://github.com/przemyslawpluta/node-youtube-dl/commit/06ec68e))
* check for `--format` too ([08ca167](https://github.com/przemyslawpluta/node-youtube-dl/commit/08ca167))
* Specify download format 'best' if none supplied ([edee4d3](https://github.com/przemyslawpluta/node-youtube-dl/commit/edee4d3))
* update examples ([023a502](https://github.com/przemyslawpluta/node-youtube-dl/commit/023a502))
* update tests ([a85779d](https://github.com/przemyslawpluta/node-youtube-dl/commit/a85779d))
<a name="1.10.3"></a>
## 1.10.3 (2015-04-19)
* 1.10.3 ([a70895e](https://github.com/przemyslawpluta/node-youtube-dl/commit/a70895e))
* Fix the broken Host HTTP Header for Dailymotion && Fix Test ([9657b8c](https://github.com/przemyslawpluta/node-youtube-dl/commit/9657b8c))
<a name="1.10.2"></a>
## 1.10.2 (2015-03-24)
* 1.10.2 ([484d1c3](https://github.com/przemyslawpluta/node-youtube-dl/commit/484d1c3))
* a bit of docs ([c3c1b4b](https://github.com/przemyslawpluta/node-youtube-dl/commit/c3c1b4b))
* print warning when getting warnings from stderr ([26bd213](https://github.com/przemyslawpluta/node-youtube-dl/commit/26bd213))
<a name="1.10.1"></a>
## 1.10.1 (2015-02-26)
* 1.10.1 ([498e288](https://github.com/przemyslawpluta/node-youtube-dl/commit/498e288))
* add io.js and 0.12 to test matrix ([17ce70b](https://github.com/przemyslawpluta/node-youtube-dl/commit/17ce70b))
* call binary with python instead of directly, fixes #66 ([833d281](https://github.com/przemyslawpluta/node-youtube-dl/commit/833d281)), closes [#66](https://github.com/przemyslawpluta/node-youtube-dl/issues/66)
* dont test on node v0.8 ([5c1c182](https://github.com/przemyslawpluta/node-youtube-dl/commit/5c1c182))
* quote iojs ([47d1485](https://github.com/przemyslawpluta/node-youtube-dl/commit/47d1485))
* update packages ([413cf53](https://github.com/przemyslawpluta/node-youtube-dl/commit/413cf53))
* use container based environment ([4947618](https://github.com/przemyslawpluta/node-youtube-dl/commit/4947618))
<a name="1.10.0"></a>
# 1.10.0 (2015-02-19)
* 1.10.0 ([d3018e5](https://github.com/przemyslawpluta/node-youtube-dl/commit/d3018e5))
* Multiple URL support (array param) for getInfo() ([1afab0b](https://github.com/przemyslawpluta/node-youtube-dl/commit/1afab0b))
<a name="1.9.0"></a>
# 1.9.0 (2015-02-13)
* 1.9.0 ([e3be488](https://github.com/przemyslawpluta/node-youtube-dl/commit/e3be488))
* add warnings for using deprecated fields ([d2c53ae](https://github.com/przemyslawpluta/node-youtube-dl/commit/d2c53ae))
* Call getInfo from getFormats ([4ecda89](https://github.com/przemyslawpluta/node-youtube-dl/commit/4ecda89))
* document how to keep youtube-dl binary up to date. fixes #61 ([a8eface](https://github.com/przemyslawpluta/node-youtube-dl/commit/a8eface)), closes [#61](https://github.com/przemyslawpluta/node-youtube-dl/issues/61)
* dont check each individual format object ([50c113f](https://github.com/przemyslawpluta/node-youtube-dl/commit/50c113f))
* fix getting playlist info ([cdb37fe](https://github.com/przemyslawpluta/node-youtube-dl/commit/cdb37fe))
* Move formatDuration to util.js ([c309c24](https://github.com/przemyslawpluta/node-youtube-dl/commit/c309c24))
* remove unused old functions ([e4689a6](https://github.com/przemyslawpluta/node-youtube-dl/commit/e4689a6))
* Return the full info provided by youtube-dl ([ace1b11](https://github.com/przemyslawpluta/node-youtube-dl/commit/ace1b11))
* Use the '--dump-json' option for extracting the video information ([b3a9fcd](https://github.com/przemyslawpluta/node-youtube-dl/commit/b3a9fcd))
* Use the '--dump-json' option for getFormats ([e93a8b9](https://github.com/przemyslawpluta/node-youtube-dl/commit/e93a8b9))
<a name="1.8.0"></a>
# 1.8.0 (2015-01-15)
* 1.8.0 ([ab8b3df](https://github.com/przemyslawpluta/node-youtube-dl/commit/ab8b3df))
* Added extractor API incl. tests and example code ([d2b3983](https://github.com/przemyslawpluta/node-youtube-dl/commit/d2b3983))
* dont download video when downloading subtitles ([3cfa382](https://github.com/przemyslawpluta/node-youtube-dl/commit/3cfa382))
* put try/catch around unlinking subtitle file ([a3f5202](https://github.com/przemyslawpluta/node-youtube-dl/commit/a3f5202))
<a name="1.7.0"></a>
# 1.7.0 (2015-01-08)
* 1.7.0 ([777619e](https://github.com/przemyslawpluta/node-youtube-dl/commit/777619e))
* added more cli args to ignore ([8edbd1e](https://github.com/przemyslawpluta/node-youtube-dl/commit/8edbd1e))
* get duration. fixes #53 ([fd7d7c9](https://github.com/przemyslawpluta/node-youtube-dl/commit/fd7d7c9)), closes [#53](https://github.com/przemyslawpluta/node-youtube-dl/issues/53)
* make `args` passed to youtube-dl actually optional ([413d0ab](https://github.com/przemyslawpluta/node-youtube-dl/commit/413d0ab))
<a name="1.6.0"></a>
# 1.6.0 (2014-11-23)
* 1.6.0 ([8d548eb](https://github.com/przemyslawpluta/node-youtube-dl/commit/8d548eb))
* add `getSubs()` function. fixes #48 ([6cb55af](https://github.com/przemyslawpluta/node-youtube-dl/commit/6cb55af)), closes [#48](https://github.com/przemyslawpluta/node-youtube-dl/issues/48)
* better resolution detection ([cff5763](https://github.com/przemyslawpluta/node-youtube-dl/commit/cff5763))
* check size is defined ([0e67ef1](https://github.com/przemyslawpluta/node-youtube-dl/commit/0e67ef1))
* linting ([916e8da](https://github.com/przemyslawpluta/node-youtube-dl/commit/916e8da))
* linting ([1f5e319](https://github.com/przemyslawpluta/node-youtube-dl/commit/1f5e319))
* update formats returned ([d545f10](https://github.com/przemyslawpluta/node-youtube-dl/commit/d545f10))
* updated getFormats regex to handle unknown & ?x formats ([7e33ace](https://github.com/przemyslawpluta/node-youtube-dl/commit/7e33ace))
<a name="1.5.16"></a>
## 1.5.16 (2014-10-24)
* 1.5.16 ([4acfca7](https://github.com/przemyslawpluta/node-youtube-dl/commit/4acfca7))
* filter out from correct args if no subs ([97346fe](https://github.com/przemyslawpluta/node-youtube-dl/commit/97346fe))
* handle new warning style ([3ae2964](https://github.com/przemyslawpluta/node-youtube-dl/commit/3ae2964))
* update test formats ([24f00e5](https://github.com/przemyslawpluta/node-youtube-dl/commit/24f00e5))
<a name="1.5.15"></a>
## 1.5.15 (2014-09-25)
* 1.5.15 ([f315043](https://github.com/przemyslawpluta/node-youtube-dl/commit/f315043))
* fix ([5d07020](https://github.com/przemyslawpluta/node-youtube-dl/commit/5d07020))
<a name="1.5.14"></a>
## 1.5.14 (2014-09-24)
* 1.5.14 ([c7d7c08](https://github.com/przemyslawpluta/node-youtube-dl/commit/c7d7c08))
* expose call function with empty default args as exec ([e12b538](https://github.com/przemyslawpluta/node-youtube-dl/commit/e12b538))
* ignore any errors after successful download. fixes #43 ([58558d8](https://github.com/przemyslawpluta/node-youtube-dl/commit/58558d8)), closes [#43](https://github.com/przemyslawpluta/node-youtube-dl/issues/43)
<a name="1.5.13"></a>
## 1.5.13 (2014-09-07)
* 1.5.13 ([e72b27d](https://github.com/przemyslawpluta/node-youtube-dl/commit/e72b27d))
* fix for missing env variable in win ([4115b5e](https://github.com/przemyslawpluta/node-youtube-dl/commit/4115b5e))
<a name="1.5.12"></a>
## 1.5.12 (2014-09-04)
* 1.5.12 ([8a8c681](https://github.com/przemyslawpluta/node-youtube-dl/commit/8a8c681))
* fix youtube id filtering ([3cb82a9](https://github.com/przemyslawpluta/node-youtube-dl/commit/3cb82a9))
<a name="1.5.11"></a>
## 1.5.11 (2014-08-24)
* 1.5.11 ([09d2951](https://github.com/przemyslawpluta/node-youtube-dl/commit/09d2951))
* support non-youtube (speificially vimeo) videos. fixes #39 ([cd6938b](https://github.com/przemyslawpluta/node-youtube-dl/commit/cd6938b)), closes [#39](https://github.com/przemyslawpluta/node-youtube-dl/issues/39)
<a name="1.5.10"></a>
## 1.5.10 (2014-08-05)
* 1.5.10 ([f9c0c8f](https://github.com/przemyslawpluta/node-youtube-dl/commit/f9c0c8f))
* fix not passing options ([02fa0df](https://github.com/przemyslawpluta/node-youtube-dl/commit/02fa0df))
<a name="1.5.9"></a>
## 1.5.9 (2014-08-02)
* 1.5.9 ([303fb12](https://github.com/przemyslawpluta/node-youtube-dl/commit/303fb12))
* Add more entries to badArgs ([a6821b5](https://github.com/przemyslawpluta/node-youtube-dl/commit/a6821b5))
* fix for failed download with no subtitles ([36fd75a](https://github.com/przemyslawpluta/node-youtube-dl/commit/36fd75a))
* fix for failed download with no subtitles when requested ([69166bf](https://github.com/przemyslawpluta/node-youtube-dl/commit/69166bf))
* fix for failed download with no subtitles when requested ([aeab2dd](https://github.com/przemyslawpluta/node-youtube-dl/commit/aeab2dd))
* fix for failed download with no subtitles when requested ([038b1fd](https://github.com/przemyslawpluta/node-youtube-dl/commit/038b1fd))
* fix for failed download with no subtitles when requested ([19c13af](https://github.com/przemyslawpluta/node-youtube-dl/commit/19c13af))
* fix for failed download with no subtitles when requested ([82a48a4](https://github.com/przemyslawpluta/node-youtube-dl/commit/82a48a4))
* only notify on build changes ([3cf3363](https://github.com/przemyslawpluta/node-youtube-dl/commit/3cf3363))
* update request to v2.37.0 ([11757f3](https://github.com/przemyslawpluta/node-youtube-dl/commit/11757f3))
<a name="1.5.8"></a>
## 1.5.8 (2014-07-04)
* Fix ReferenceError: onerror is not defined ([acb3512](https://github.com/przemyslawpluta/node-youtube-dl/commit/acb3512))
* Fix var name: from er to err ([21bdbee](https://github.com/przemyslawpluta/node-youtube-dl/commit/21bdbee))
* update request ([f97f90b](https://github.com/przemyslawpluta/node-youtube-dl/commit/f97f90b))
* v1.5.7 ([f19215a](https://github.com/przemyslawpluta/node-youtube-dl/commit/f19215a))
* v1.5.8 ([96083ba](https://github.com/przemyslawpluta/node-youtube-dl/commit/96083ba))
<a name="1.5.6"></a>
## 1.5.6 (2014-06-14)
* comment consistency ([7acea1e](https://github.com/przemyslawpluta/node-youtube-dl/commit/7acea1e))
* fix parsing resolutions ([ac48c37](https://github.com/przemyslawpluta/node-youtube-dl/commit/ac48c37))
* fix when not giving `args` to `getInfo()` ([794617d](https://github.com/przemyslawpluta/node-youtube-dl/commit/794617d))
* v1.5.6 ([80999a5](https://github.com/przemyslawpluta/node-youtube-dl/commit/80999a5))
<a name="1.5.5"></a>
## 1.5.5 (2014-05-02)
* can pass execFile options to download ([2986447](https://github.com/przemyslawpluta/node-youtube-dl/commit/2986447))
* dont parse options twice on download ([67eb88d](https://github.com/przemyslawpluta/node-youtube-dl/commit/67eb88d))
* v1.5.5 ([20c3cd2](https://github.com/przemyslawpluta/node-youtube-dl/commit/20c3cd2))
<a name="1.5.4"></a>
## 1.5.4 (2014-05-01)
* chmod bin directory too ([3d1e88f](https://github.com/przemyslawpluta/node-youtube-dl/commit/3d1e88f))
* run download script on preinstall ([c377b4e](https://github.com/przemyslawpluta/node-youtube-dl/commit/c377b4e))
* update vows ([a3be7a9](https://github.com/przemyslawpluta/node-youtube-dl/commit/a3be7a9))
* v1.5.4 ([a0709a4](https://github.com/przemyslawpluta/node-youtube-dl/commit/a0709a4))
* package: add binary ([2050667](https://github.com/przemyslawpluta/node-youtube-dl/commit/2050667))
<a name="1.5.3"></a>
## 1.5.3 (2014-04-26)
* dont global link youtube-dl binary. too much confusion. ([b74ed8f](https://github.com/przemyslawpluta/node-youtube-dl/commit/b74ed8f))
* Remove /v/ from the id to accept url like http://www.youtube.com/v/6tC1yOUvvMo provided by the youtu ([b4a3350](https://github.com/przemyslawpluta/node-youtube-dl/commit/b4a3350))
* Remove useless g flag from Regex ([1239606](https://github.com/przemyslawpluta/node-youtube-dl/commit/1239606))
* some code organization ([085b9f7](https://github.com/przemyslawpluta/node-youtube-dl/commit/085b9f7))
* update ignore rules ([0acf105](https://github.com/przemyslawpluta/node-youtube-dl/commit/0acf105))
* v1.5.3 ([3175bd0](https://github.com/przemyslawpluta/node-youtube-dl/commit/3175bd0))
<a name="1.5.2"></a>
## 1.5.2 (2014-04-25)
* Add a second var ([76d3468](https://github.com/przemyslawpluta/node-youtube-dl/commit/76d3468))
* Fix "Cannot call method 'split' of undefined" bug with last version of youtube-dl (2014.04.21.6) ([864a526](https://github.com/przemyslawpluta/node-youtube-dl/commit/864a526))
* Remove commented old code ([9804155](https://github.com/przemyslawpluta/node-youtube-dl/commit/9804155))
* Remove the extra space ([11aabf9](https://github.com/przemyslawpluta/node-youtube-dl/commit/11aabf9))
* Save the regexp in the outer scope so it's not compiled every time this function runs ([585c526](https://github.com/przemyslawpluta/node-youtube-dl/commit/585c526))
* v1.5.2 ([88be6d7](https://github.com/przemyslawpluta/node-youtube-dl/commit/88be6d7))
<a name="1.5.1"></a>
## 1.5.1 (2014-04-08)
* add Przemyslaw to contributors ([afc4cc9](https://github.com/przemyslawpluta/node-youtube-dl/commit/afc4cc9))
* fix for win py2.x / py3.x ([472a8db](https://github.com/przemyslawpluta/node-youtube-dl/commit/472a8db))
* v1.5.1 ([7a2620d](https://github.com/przemyslawpluta/node-youtube-dl/commit/7a2620d))
<a name="1.5.0"></a>
# 1.5.0 (2014-04-08)
* download first if array of clips ([28ed6bb](https://github.com/przemyslawpluta/node-youtube-dl/commit/28ed6bb))
* handle videos download from youtube playlist ([b7434da](https://github.com/przemyslawpluta/node-youtube-dl/commit/b7434da))
* refactor ([6c5187e](https://github.com/przemyslawpluta/node-youtube-dl/commit/6c5187e))
* test update ([8704b8e](https://github.com/przemyslawpluta/node-youtube-dl/commit/8704b8e))
* typo ([540ee03](https://github.com/przemyslawpluta/node-youtube-dl/commit/540ee03))
* typo ([2647ed5](https://github.com/przemyslawpluta/node-youtube-dl/commit/2647ed5))
* v1.5.0 ([b27d373](https://github.com/przemyslawpluta/node-youtube-dl/commit/b27d373))
<a name="1.4.0"></a>
# 1.4.0 (2014-03-14)
* not needed ([7dcd88f](https://github.com/przemyslawpluta/node-youtube-dl/commit/7dcd88f))
* reflect api changes ([82aeb41](https://github.com/przemyslawpluta/node-youtube-dl/commit/82aeb41))
* update example videos ([3bd98d7](https://github.com/przemyslawpluta/node-youtube-dl/commit/3bd98d7))
* update tests ([c4ab33d](https://github.com/przemyslawpluta/node-youtube-dl/commit/c4ab33d))
* use youtube-dl to get download url, return stream ([3479e52](https://github.com/przemyslawpluta/node-youtube-dl/commit/3479e52))
* v1.4.0 ([e23e5f3](https://github.com/przemyslawpluta/node-youtube-dl/commit/e23e5f3))
<a name="1.3.6"></a>
## 1.3.6 (2014-02-15)
* fix - youtube-dl incorrect download ([8c439b1](https://github.com/przemyslawpluta/node-youtube-dl/commit/8c439b1))
* v1.3.6 ([be7c22f](https://github.com/przemyslawpluta/node-youtube-dl/commit/be7c22f))
<a name="1.3.5"></a>
## 1.3.5 (2014-02-15)
* Fix - win handling getInfo & getFormats ([19ccc54](https://github.com/przemyslawpluta/node-youtube-dl/commit/19ccc54))
* Fix - win handling getInfo & getFormats ([7655ea1](https://github.com/przemyslawpluta/node-youtube-dl/commit/7655ea1))
* v1.3.5 ([6f4eb9c](https://github.com/przemyslawpluta/node-youtube-dl/commit/6f4eb9c))
<a name="1.3.4"></a>
## 1.3.4 (2014-02-14)
* Fix - Incorrect youtube video URL ([954df15](https://github.com/przemyslawpluta/node-youtube-dl/commit/954df15))
* Fix - Incorrect youtube video URL ([17c4214](https://github.com/przemyslawpluta/node-youtube-dl/commit/17c4214))
* Fix - Incorrect youtube video URL ([12dea04](https://github.com/przemyslawpluta/node-youtube-dl/commit/12dea04))
* Fix - Incorrect youtube video URL ([1b10dff](https://github.com/przemyslawpluta/node-youtube-dl/commit/1b10dff))
* Fix - Incorrect youtube video URL ([408e2b1](https://github.com/przemyslawpluta/node-youtube-dl/commit/408e2b1))
* Fix - Incorrect youtube video URL ([c161fa6](https://github.com/przemyslawpluta/node-youtube-dl/commit/c161fa6))
* Fix - Incorrect youtube video URL ([753ae6b](https://github.com/przemyslawpluta/node-youtube-dl/commit/753ae6b))
* Fix - Incorrect youtube video URL ([04f4aaa](https://github.com/przemyslawpluta/node-youtube-dl/commit/04f4aaa))
* Fix - Incorrect youtube video URL ([a5eeb09](https://github.com/przemyslawpluta/node-youtube-dl/commit/a5eeb09))
* Fix - Incorrect youtube video URL ([28dd461](https://github.com/przemyslawpluta/node-youtube-dl/commit/28dd461))
* only write version to file if downloaded successfully ([091f425](https://github.com/przemyslawpluta/node-youtube-dl/commit/091f425))
* v1.3.4 ([6825c7b](https://github.com/przemyslawpluta/node-youtube-dl/commit/6825c7b))
<a name="1.3.3"></a>
## 1.3.3 (2014-02-12)
* spawn ENOENT in win ([48a309d](https://github.com/przemyslawpluta/node-youtube-dl/commit/48a309d))
* spawn ENOENT in win ([b6191c8](https://github.com/przemyslawpluta/node-youtube-dl/commit/b6191c8))
* spawn ENOENT in win ([a816720](https://github.com/przemyslawpluta/node-youtube-dl/commit/a816720))
* spawn ENOENT in win ([b6178e6](https://github.com/przemyslawpluta/node-youtube-dl/commit/b6178e6))
* tiny cleanup ([19a0059](https://github.com/przemyslawpluta/node-youtube-dl/commit/19a0059))
* update get formats regexp ([9df37f0](https://github.com/przemyslawpluta/node-youtube-dl/commit/9df37f0))
* update ugh tests ([db2388c](https://github.com/przemyslawpluta/node-youtube-dl/commit/db2388c))
* v1.3.3 ([f4498fa](https://github.com/przemyslawpluta/node-youtube-dl/commit/f4498fa))
<a name="1.3.2"></a>
## 1.3.2 (2013-10-22)
* improve regexp to download latest version ([9040f81](https://github.com/przemyslawpluta/node-youtube-dl/commit/9040f81))
* removed check for query.v that breaks soundcloud functionality ([11da4f7](https://github.com/przemyslawpluta/node-youtube-dl/commit/11da4f7))
* version bump ([60cce67](https://github.com/przemyslawpluta/node-youtube-dl/commit/60cce67))
<a name="1.3.1"></a>
## 1.3.1 (2013-10-15)
* always download latest version of youtube-dl ([c7de217](https://github.com/przemyslawpluta/node-youtube-dl/commit/c7de217))
* fix reading download state ([174743a](https://github.com/przemyslawpluta/node-youtube-dl/commit/174743a))
* formats change :/ ([e6f172d](https://github.com/przemyslawpluta/node-youtube-dl/commit/e6f172d))
* make sure to delete downloaded file ([be74d80](https://github.com/przemyslawpluta/node-youtube-dl/commit/be74d80))
* only download if new version ([1c8211c](https://github.com/przemyslawpluta/node-youtube-dl/commit/1c8211c))
* specify format to download ([429687c](https://github.com/przemyslawpluta/node-youtube-dl/commit/429687c))
* v1.3.1 ([23128d7](https://github.com/przemyslawpluta/node-youtube-dl/commit/23128d7))
<a name="1.3.0"></a>
# 1.3.0 (2013-09-13)
* add getFormats() ([604fa7b](https://github.com/przemyslawpluta/node-youtube-dl/commit/604fa7b))
* some style changes ([08a2ba5](https://github.com/przemyslawpluta/node-youtube-dl/commit/08a2ba5))
* version bump ([1735865](https://github.com/przemyslawpluta/node-youtube-dl/commit/1735865))
<a name="1.2.12"></a>
## 1.2.12 (2013-08-27)
* add id to download info ([eb92288](https://github.com/przemyslawpluta/node-youtube-dl/commit/eb92288))
* better info test ([e4a1b2f](https://github.com/przemyslawpluta/node-youtube-dl/commit/e4a1b2f))
* take into account multi line descriptions ([63ad7c2](https://github.com/przemyslawpluta/node-youtube-dl/commit/63ad7c2))
* version bump ([8625ff4](https://github.com/przemyslawpluta/node-youtube-dl/commit/8625ff4))
<a name="1.2.11"></a>
## 1.2.11 (2013-08-23)
* add id, itag, and resolution to `info()` ([11c7f68](https://github.com/przemyslawpluta/node-youtube-dl/commit/11c7f68))
* version bump ([c5fc896](https://github.com/przemyslawpluta/node-youtube-dl/commit/c5fc896))
<a name="1.2.10"></a>
## 1.2.10 (2013-08-04)
* cleaner example output ([7fcdf8f](https://github.com/przemyslawpluta/node-youtube-dl/commit/7fcdf8f))
* correctly split lines ([13368d1](https://github.com/przemyslawpluta/node-youtube-dl/commit/13368d1))
* update event-stream ([87983c1](https://github.com/przemyslawpluta/node-youtube-dl/commit/87983c1))
* version bump ([b605c93](https://github.com/przemyslawpluta/node-youtube-dl/commit/b605c93))
<a name="1.2.9"></a>
## 1.2.9 (2013-08-04)
* error checking ([524416b](https://github.com/przemyslawpluta/node-youtube-dl/commit/524416b))
* update youtube-dl version ([f4d21ec](https://github.com/przemyslawpluta/node-youtube-dl/commit/f4d21ec))
* version bump ([4fc9e1c](https://github.com/przemyslawpluta/node-youtube-dl/commit/4fc9e1c))
<a name="1.2.8"></a>
## 1.2.8 (2013-05-17)
* [ci skip] ([8af4a1f](https://github.com/przemyslawpluta/node-youtube-dl/commit/8af4a1f))
* check if progress is printed at least once ([189834d](https://github.com/przemyslawpluta/node-youtube-dl/commit/189834d))
* fix tests ([e0895a4](https://github.com/przemyslawpluta/node-youtube-dl/commit/e0895a4))
* minor cosmetics ([af3a82c](https://github.com/przemyslawpluta/node-youtube-dl/commit/af3a82c))
* more thorough tests ([1d96ad2](https://github.com/przemyslawpluta/node-youtube-dl/commit/1d96ad2))
* Release v1.2.8 ([85ca0da](https://github.com/przemyslawpluta/node-youtube-dl/commit/85ca0da))
* update exists method ([1fbfb00](https://github.com/przemyslawpluta/node-youtube-dl/commit/1fbfb00))
* update node versions ([73e93d1](https://github.com/przemyslawpluta/node-youtube-dl/commit/73e93d1))
* update regexp for download progress ([f64ff44](https://github.com/przemyslawpluta/node-youtube-dl/commit/f64ff44))
* update where youtube-dl is downloaded from ([dfe6234](https://github.com/przemyslawpluta/node-youtube-dl/commit/dfe6234))
<a name="1.2.7"></a>
## 1.2.7 (2012-08-19)
* cleanup ([36e8741](https://github.com/przemyslawpluta/node-youtube-dl/commit/36e8741))
* link to ytdl ([fc09348](https://github.com/przemyslawpluta/node-youtube-dl/commit/fc09348))
* Release v1.2.7 ([dafa422](https://github.com/przemyslawpluta/node-youtube-dl/commit/dafa422))
* version bump ([236a4a7](https://github.com/przemyslawpluta/node-youtube-dl/commit/236a4a7))
<a name="1.2.6"></a>
## 1.2.6 (2012-08-01)
* buffer info call ([c46a993](https://github.com/przemyslawpluta/node-youtube-dl/commit/c46a993))
* make sure to delete downloaded file ([5247bdb](https://github.com/przemyslawpluta/node-youtube-dl/commit/5247bdb))
* separate youtubedl stdout by line ([a1b7294](https://github.com/przemyslawpluta/node-youtube-dl/commit/a1b7294))
* version bump ([4f30db8](https://github.com/przemyslawpluta/node-youtube-dl/commit/4f30db8))
<a name="1.2.5"></a>
## 1.2.5 (2012-07-07)
* [fix] path.existsSync was moved to fs.existsSync ([aadc85a](https://github.com/przemyslawpluta/node-youtube-dl/commit/aadc85a))
* added node v0.8 ([a0dc4d8](https://github.com/przemyslawpluta/node-youtube-dl/commit/a0dc4d8))
* existsSync ([876d969](https://github.com/przemyslawpluta/node-youtube-dl/commit/876d969))
* fix existsSync ([24b7db7](https://github.com/przemyslawpluta/node-youtube-dl/commit/24b7db7))
* removed engines ([1e3c85e](https://github.com/przemyslawpluta/node-youtube-dl/commit/1e3c85e))
* use `fs.exists` ([658c651](https://github.com/przemyslawpluta/node-youtube-dl/commit/658c651))
* version bump ([6d678d8](https://github.com/przemyslawpluta/node-youtube-dl/commit/6d678d8))
<a name="1.2.4"></a>
## 1.2.4 (2012-03-10)
* more efficient youtube-dl download ([574cd7f](https://github.com/przemyslawpluta/node-youtube-dl/commit/574cd7f))
* ver bump ([fe10efb](https://github.com/przemyslawpluta/node-youtube-dl/commit/fe10efb))
* ver bump ([3fb0f0e](https://github.com/przemyslawpluta/node-youtube-dl/commit/3fb0f0e))
<a name="1.2.3"></a>
## 1.2.3 (2012-03-04)
* used `__dirname` instead of `./` to save download ([b5fb4bf](https://github.com/przemyslawpluta/node-youtube-dl/commit/b5fb4bf))
* used `path.join` to make it more cross-platform ([05c2ba3](https://github.com/przemyslawpluta/node-youtube-dl/commit/05c2ba3))
<a name="1.2.2"></a>
## 1.2.2 (2012-02-06)
* Better error reporting ([e853b64](https://github.com/przemyslawpluta/node-youtube-dl/commit/e853b64))
<a name="1.2.1"></a>
## 1.2.1 (2012-01-04)
* added test dir ([1695d60](https://github.com/przemyslawpluta/node-youtube-dl/commit/1695d60))
* added test script ([39ecfd6](https://github.com/przemyslawpluta/node-youtube-dl/commit/39ecfd6))
* better formatting ([16ad412](https://github.com/przemyslawpluta/node-youtube-dl/commit/16ad412))
* better versioning ([40d175e](https://github.com/przemyslawpluta/node-youtube-dl/commit/40d175e))
* cleared file ([c30ae25](https://github.com/przemyslawpluta/node-youtube-dl/commit/c30ae25))
* javascript syntax ([42c9fd9](https://github.com/przemyslawpluta/node-youtube-dl/commit/42c9fd9))
* organized readme ([c6069fd](https://github.com/przemyslawpluta/node-youtube-dl/commit/c6069fd))
* removed v0.5 ([ef5e15c](https://github.com/przemyslawpluta/node-youtube-dl/commit/ef5e15c))
* restored ([2ab9779](https://github.com/przemyslawpluta/node-youtube-dl/commit/2ab9779))
* travis ci ([548d808](https://github.com/przemyslawpluta/node-youtube-dl/commit/548d808))
* Written back to Javascript ([0063944](https://github.com/przemyslawpluta/node-youtube-dl/commit/0063944))
<a name="1.2.0"></a>
# 1.2.0 (2011-09-16)
* added filename to data returned ([49909ca](https://github.com/przemyslawpluta/node-youtube-dl/commit/49909ca))
* added tests ([1377915](https://github.com/przemyslawpluta/node-youtube-dl/commit/1377915))
* fixed installation issue ([d05b14c](https://github.com/przemyslawpluta/node-youtube-dl/commit/d05b14c))
* fixed symlink installation issue ([68199c0](https://github.com/przemyslawpluta/node-youtube-dl/commit/68199c0))
<a name="1.1.0"></a>
# 1.1.0 (2011-08-27)
* now uses emitter ([7063855](https://github.com/przemyslawpluta/node-youtube-dl/commit/7063855))
* update ([5c6ff08](https://github.com/przemyslawpluta/node-youtube-dl/commit/5c6ff08))
<a name="1.0.4"></a>
## 1.0.4 (2011-08-07)
* added *.mp4 ([6b7a1dc](https://github.com/przemyslawpluta/node-youtube-dl/commit/6b7a1dc))
* added scripts folder to tasks ([bfa584b](https://github.com/przemyslawpluta/node-youtube-dl/commit/bfa584b))
* added scripts to watch task ([0afc347](https://github.com/przemyslawpluta/node-youtube-dl/commit/0afc347))
* better organized ([dfd57c6](https://github.com/przemyslawpluta/node-youtube-dl/commit/dfd57c6))
* commit ([059d81b](https://github.com/przemyslawpluta/node-youtube-dl/commit/059d81b))
* convenience ([2cb471e](https://github.com/przemyslawpluta/node-youtube-dl/commit/2cb471e))
* fixed error in info function ([ea6ceda](https://github.com/przemyslawpluta/node-youtube-dl/commit/ea6ceda))
* fixed main ([572509b](https://github.com/przemyslawpluta/node-youtube-dl/commit/572509b))
* minimalist ([bb5c5fb](https://github.com/przemyslawpluta/node-youtube-dl/commit/bb5c5fb))
* now requires coffee-script to run ([8be7f53](https://github.com/przemyslawpluta/node-youtube-dl/commit/8be7f53))
* organized ([aeaf9c8](https://github.com/przemyslawpluta/node-youtube-dl/commit/aeaf9c8))
* organized ([2544054](https://github.com/przemyslawpluta/node-youtube-dl/commit/2544054))
* organized ([cbea725](https://github.com/przemyslawpluta/node-youtube-dl/commit/cbea725))
* removed coffeescript from installation ([b5bc9d8](https://github.com/przemyslawpluta/node-youtube-dl/commit/b5bc9d8))
* updated version number ([df8861a](https://github.com/przemyslawpluta/node-youtube-dl/commit/df8861a))
* when finished downloading, statistics data will be passed ([77a99e5](https://github.com/przemyslawpluta/node-youtube-dl/commit/77a99e5))
Copyright (C) 2011 by Roly Fentanes
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
# youtube-dl
[![Build Status](https://travis-ci.org/przemyslawpluta/node-youtube-dl.svg?branch=master)](https://travis-ci.org/przemyslawpluta/node-youtube-dl) [![npm version](https://badge.fury.io/js/youtube-dl.svg)](https://badge.fury.io/js/youtube-dl)
Download videos from youtube in node.js using [youtube-dl](http://rg3.github.com/youtube-dl/).
If you're only interested in downloading only from youtube, you should consider using [pure Javascript youtube downloading module](https://github.com/fent/node-ytdl).
## Installation
With [npm](https://www.npmjs.com/) do:
``` sh
npm install @microlink/youtube-dl
```
## Usage
### Downloading videos
``` js
var fs = require('fs');
var youtubedl = require('youtube-dl');
var video = youtubedl('http://www.youtube.com/watch?v=90AiXO1pAiA',
// Optional arguments passed to youtube-dl.
['--format=18'],
// Additional options can be given for calling `child_process.execFile()`.
{ cwd: __dirname });
// Will be called when the download starts.
video.on('info', function(info) {
console.log('Download started');
console.log('filename: ' + info._filename);
console.log('size: ' + info.size);
});
video.pipe(fs.createWriteStream('myvideo.mp4'));
```
It will produce an output that looks like the following when ran.
```bash
Got video info
saving to T-ara - Number Nine - MV - 티아라-Seku9G1kT0c.mp4
100.00%
```
### Resuming partially downloaded videos
``` js
var youtubedl = require('./');
var fs = require('fs');
var output = 'myvideo.mp4';
var downloaded = 0;
if (fs.existsSync(output)) {
downloaded = fs.statSync(output).size;
}
var video = youtubedl('https://www.youtube.com/watch?v=179MiZSibco',
// Optional arguments passed to youtube-dl.
['--format=18'],
// start will be sent as a range header
{ start: downloaded, cwd: __dirname });
// Will be called when the download starts.
video.on('info', function(info) {
console.log('Download started');
console.log('filename: ' + info._filename);
// info.size will be the amount to download, add
var total = info.size + downloaded;
console.log('size: ' + total);
if (downloaded > 0) {
// size will be the amount already downloaded
console.log('resuming from: ' + downloaded);
// display the remaining bytes to download
console.log('remaining bytes: ' + info.size);
}
});
video.pipe(fs.createWriteStream('myvideo.mp4', { flags: 'a' }));
// Will be called if download was already completed and there is nothing more to download.
video.on('complete', function complete(info) {
'use strict';
console.log('filename: ' + info._filename + ' already downloaded.');
});
video.on('end', function() {
console.log('finished downloading!');
});
```
It will produce an output that looks like the following when ran.
**Output:**
``` sh
[~/nodejs/node-youtube-dl/example]$ node resume.js
Download started
filename: 1 1 1-179MiZSibco.mp4
size: 5109213
^C
```
``` sh
[~/nodejs/node-youtube-dl/example]$ node resume.js
Download started
filename: 1 1 1-179MiZSibco.mp4
size: 5109213
resuming from: 917504
remaining bytes: 4191709
finished downloading
```
### Getting video information
``` js
var youtubedl = require('youtube-dl');
var url = 'http://www.youtube.com/watch?v=WKsjaOqDXgg';
// Optional arguments passed to youtube-dl.
var options = ['--username=user', '--password=hunter2'];
youtubedl.getInfo(url, options, function(err, info) {
if (err) throw err;
console.log('id:', info.id);
console.log('title:', info.title);
console.log('url:', info.url);
console.log('thumbnail:', info.thumbnail);
console.log('description:', info.description);
console.log('filename:', info._filename);
console.log('format id:', info.format_id);
});
```
Running that will produce something like
``` sh
id: WKsjaOqDXgg
title: Ace Rimmer to the Rescue
url: http://r5---sn-p5qlsn7e.c.youtube.com/videoplayback?ms=au&ip=160.79.125.18&cp=U0hWTFVQVl9FTENONl9NSlpDOjgtU1VsODlkVmRH&id=58ab2368ea835e08&source=youtube&expire=1377558202&factor=1.25&key=yt1&ipbits=8&mt=1377534150&itag=34&sver=3&upn=-rGWz2vYpN4&fexp=912306%2C927900%2C919395%2C926518%2C936203%2C913819%2C929117%2C929121%2C929906%2C929907%2C929922%2C929127%2C929129%2C929131%2C929930%2C925726%2C925720%2C925722%2C925718%2C929917%2C906945%2C929919%2C929933%2C912521%2C932306%2C913428%2C904830%2C919373%2C930803%2C908536%2C904122%2C938701%2C936308%2C909549%2C900816%2C912711%2C904494%2C904497%2C900375%2C906001&sparams=algorithm%2Cburst%2Ccp%2Cfactor%2Cid%2Cip%2Cipbits%2Citag%2Csource%2Cupn%2Cexpire&mv=m&burst=40&algorithm=throttle-factor&signature=ABD3A847684AD9B39331E567568D3FA0DCFA4776.7895521E130A042FB3625A17242CE3C02A4460B7&ratebypass=yes
thumbnail: https://i1.ytimg.com/vi/WKsjaOqDXgg/hqdefault.jpg
description: An old Red Dwarf eposide where Ace Rimmer saves the Princess Bonjella.
filename: Ace Rimmer to the Rescue-WKsjaOqDXgg.flv
format id: 34
```
You can use an array of urls to produce an array of response objects with matching array index (e.g. the 1st response object will match the first url etc...)
``` js
var youtubedl = require('youtube-dl');
var url1 = 'http://www.youtube.com/watch?v=WKsjaOqDXgg';
var url2 = 'https://vimeo.com/6586873';
youtubedl.getInfo([url1, url2], function(err, info) {
if (err) throw err;
console.log('title for the url1:', info[0].title);
console.log('title for the url2:', info[1].title);
});
```
### Downloading subtitles
``` js
var youtubedl = require('youtube-dl');
var url = 'https://youtu.be/PizwcirYuGY';
var options = {
// Write automatic subtitle file (youtube only)
auto: false,
// Downloads all the available subtitles.
all: false,
// Subtitle format. YouTube generated subtitles
// are available ttml or vtt.
format: 'ttml',
// Languages of subtitles to download, separated by commas.
lang: 'en',
// The directory to save the downloaded files in.
cwd: __dirname,
};
youtubedl.getSubs(url, options, function(err, files) {
if (err) throw err;
console.log('subtitle files downloaded:', files);
});
```
### Downloading thumbnails
``` js
var youtubedl = require('youtube-dl');
var url = 'https://youtu.be/PizwcirYuGY';
var options = {
// Downloads available thumbnail.
all: false,
// The directory to save the downloaded files in.
cwd: __dirname,
};
youtubedl.getThumbs(url, options, function(err, files) {
if (err) throw err;
console.log('thumbnail file downloaded:', files);
});
```
For more usage info on youtube-dl and the arguments you can pass to it, do `youtube-dl -h` or go to the [youtube-dl documentation][].
### Downloading playlists
``` js
var path = require('path');
var fs = require('fs');
var ytdl = require('youtube-dl');
function playlist(url) {
'use strict';
var video = ytdl(url);
video.on('error', function error(err) {
console.log('error 2:', err);
});
var size = 0;
video.on('info', function(info) {
size = info.size;
var output = path.join(__dirname + '/', size + '.mp4');
video.pipe(fs.createWriteStream(output));
});
var pos = 0;
video.on('data', function data(chunk) {
pos += chunk.length;
// `size` should not be 0 here.
if (size) {
var percent = (pos / size * 100).toFixed(2);
process.stdout.cursorTo(0);
process.stdout.clearLine(1);
process.stdout.write(percent + '%');
}
});
video.on('next', playlist);
}
playlist('https://www.youtube.com/playlist?list=PLEFA9E9D96CB7F807');
```
### Getting the list of extractors
``` js
var youtubedl = require('youtube-dl');
youtubedl.getExtractors(true, function(err, list) {
console.log('Found ' + list.length + ' extractors');
for (var i = 0; i < list.length; i++) {
console.log(list[i]);
}
});
```
Will print something like
``` sh
Found 521 extractors
1up.com
220.ro
24video
3sat
```
### Call the `youtube-dl` binary directly
This module doesn't have `youtube-dl` download the video. Instead, it uses the `url` key from the `--dump-json` CLI option to create a node stream. That way, it can be used like any other node stream.
If that, or none of the above support your use case, you can use `ytdl.exec()` to call `youtube-dl` however you like.
``` js
ytdl.exec(url, ['-x', '--audio-format', 'mp3'], {}, function(err, output) {
if (err) throw err;
console.log(output.join('\n'));
});
```
### Update
Since the youtube-dl binary is updated regularly, you can run `npm run update` to check for and download any updates for it. You can also require `../lib/downloader` in your app if you'd like to place `youtube-dl` binary in a specific directory and control when it gets updates.
``` js
var downloader = require('../lib/downloader');
downloader('path/to-binary', function error(err, done) {
'use strict';
if (err) { return console.log(err.stack); }
console.log(done);
});
```
### Tests
Tests are written with [vows](http://vowsjs.org/)
``` sh
npm test
```
## License
MIT
[youtube-dl]: http://rg3.github.com/youtube-dl/
[youtube-dl documentation]: http://rg3.github.com/youtube-dl/documentation.html
{"version":"2019.05.20","path":null,"exec":"youtube-dl.exe"}
\ No newline at end of file
'use strict'
const request = require('request')
const mkdirp = require('mkdirp')
const path = require('path')
const fs = require('fs')
const [, , ...flags] = process.argv
const isWin = flags.includes('--platform=windows') || require('./util').isWin
// First, look for the download link.
let dir, filePath
const defaultBin = path.join(__dirname, '..', 'bin')
const defaultPath = path.join(defaultBin, 'details')
const url = 'https://yt-dl.org/downloads/latest/youtube-dl'
function download (url, callback) {
let status
// download the correct version of the binary based on the platform
url = exec(url)
request.get(url, { followRedirect: false }, function (err, res) {
if (err) return callback(err)
if (res.statusCode !== 302) {
return callback(
new Error(
'Did not get redirect for the latest version link. Status: ' +
res.statusCode
)
)
}
const url = res.headers.location
const downloadFile = request.get(url)
const newVersion = /yt-dl\.org\/downloads\/(\d{4}\.\d\d\.\d\d(\.\d)?)\/youtube-dl/.exec(
url
)[1]
downloadFile.on('response', function response (res) {
if (res.statusCode !== 200) {
status = new Error('Response Error: ' + res.statusCode)
return
}
downloadFile.pipe(fs.createWriteStream(filePath, { mode: 493 }))
})
downloadFile.on('error', function error (err) {
callback(err)
})
downloadFile.on('end', function end () {
callback(status, newVersion)
})
})
}
const exec = path => (isWin ? path + '.exe' : path)
function createBase (binDir) {
dir = binDir || defaultBin
mkdirp.sync(dir)
if (binDir) mkdirp.sync(defaultBin)
filePath = path.join(dir, exec('youtube-dl'))
}
function downloader (binDir, callback) {
if (typeof binDir === 'function') {
callback = binDir
binDir = null
}
createBase(binDir)
download(url, function error (err, newVersion) {
if (err) return callback(err)
fs.writeFileSync(
defaultPath,
JSON.stringify({
version: newVersion,
path: binDir ? filePath : binDir,
exec: exec('youtube-dl')
}),
'utf8'
)
return callback(null, 'Downloaded youtube-dl ' + newVersion)
})
}
module.exports = downloader
// Arguments we dont want users to use with youtube-dl
// because they will break the module.
const badArgs = [
'-h',
'--help',
'-v',
'--version',
'-U',
'--update',
'-q',
'--quiet',
'-s',
'--simulate',
'-g',
'--get-url',
'-e',
'--get-title',
'--get-id',
'--get-thumbnail',
'--get-description',
'--get-duration',
'--get-filename',
'--get-format',
'-j',
'--dump-json',
'--newline',
'--no-progress',
'--console-title',
'-v',
'--verbose',
'--dump-intermediate-pages',
'--write-pages',
'--print-traffic'
]
/**
* Helps parse options used in youtube-dl command.
*
* @param {Array.<String>}
* @return {Array.<String>}
*/
exports.parseOpts = function (args) {
var pos
for (var i = 0, len = badArgs.length; i < len; i++) {
if ((pos = args.indexOf(badArgs[i])) !== -1) {
args.splice(pos, 1)
}
}
return args
}
/**
* Converts seconds to format hh:mm:ss
*
* @param {Number} seconds
* @return {String}
*/
exports.formatDuration = function (seconds) {
var parts = []
parts.push(seconds % 60)
var minutes = Math.floor(seconds / 60)
if (minutes > 0) {
parts.push(minutes % 60)
var hours = Math.floor(minutes / 60)
if (hours > 0) {
parts.push(hours)
}
}
return parts.reverse().join(':')
}
/**
* Checks wether str is a string or not
*
* @param {String} str
* @return {Boolean}
*/
exports.isString = str => typeof str === 'string'
/**
* Checks arr contains value
*
* @param {Array} arr
* @param {string|number} arr
* @return {Boolean}
*/
exports.has = (arr, value) => arr && arr.indexOf(value) > -1
exports.isYouTubeRegex = /^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.be)\//
exports.isWin =
process.platform === 'win32' || process.env.NODE_PLATFORM === 'windows'
'use strict'
const execFile = require('child_process').execFile
const streamify = require('streamify')
const request = require('request')
const hms = require('hh-mm-ss')
const path = require('path')
const http = require('http')
const url = require('url')
const fs = require('fs')
const {
isYouTubeRegex,
isWin,
formatDuration,
has,
isString
} = require('./util')
const detailsPath = path.join(__dirname, '..', 'bin/details')
const TEN_MEGABYTES = 1000 * 1000 * 10
const execFileOpts = { maxBuffer: TEN_MEGABYTES }
let ytdlBinary = (() => {
if (fs.existsSync(detailsPath)) {
const details = JSON.parse(fs.readFileSync(detailsPath))
return details.path
? details.path
: path.resolve(__dirname, '..', 'bin', details.exec)
}
if (!fs.existsSync(ytdlBinary)) {
console.error(
'ERROR: unable to locate youtube-dl details in ' +
path.dirname(ytdlBinary)
)
process.exit(1)
}
})()
function youtubeDl (args, options, cb) {
execFile(ytdlBinary, args, { ...execFileOpts, ...options }, function done (
err,
stdout,
stderr
) {
if (err) return cb(err)
return cb(null, stdout.trim().split(/\r?\n/))
})
}
/**
* Processes data
*
* @param {Object} data
* @param {Object} options
* @param {Object} stream
*/
function processData (data, options, stream) {
const item = !data.length ? data : data.shift()
// fix for pause/resume downloads
const headers = Object.assign(
{ Host: url.parse(item.url).hostname },
data.http_headers
)
if (options && options.start > 0 && options.end > 0) {
headers.Range = 'bytes=' + options.start + '-' + options.end
}
const req = request({ url: item.url, headers: headers, ecdhCurve: 'auto' })
req.on('response', function response (res) {
const size = parseInt(res.headers['content-length'], 10)
if (size) item.size = size
if (options && options.start > 0 && res.statusCode === 416) {
// the file that is being resumed is complete.
return stream.emit('complete', item)
}
if (res.statusCode !== 200 && res.statusCode !== 206) {
return stream.emit('error', new Error('status code ' + res.statusCode))
}
stream.emit('info', item)
stream.on('end', function end () {
if (data.length) stream.emit('next', data)
})
})
return stream.resolve(req)
}
/**
* Downloads a video.
*
* @param {String} videoUrl
* @param {!Array.<String>} args
* @param {!Object} options
*/
const ytdl = (module.exports = function (videoUrl, args, options) {
const stream = streamify({
superCtor: http.ClientResponse,
readable: true,
writable: false
})
if (!isString(videoUrl)) {
processData(videoUrl, options, stream)
return stream
}
ytdl.getInfo(videoUrl, args, options, function getInfo (err, data) {
return err ? stream.emit('error', err) : processData(data, options, stream)
})
return stream
})
/**
* Calls youtube-dl with some arguments and the `cb`
* gets called with the output.
*
* @param {String|Array.<String>}
* @param {Array.<String>} args
* @param {Array.<String>} args2
* @param {Object} options
* @param {Function(!Error, String)} cb
*/
function call (urls, args1, args2, options = {}, cb) {
let args = args1
if (args2) args = args.concat(args2)
// check if encoding is already set
if (isWin && !args.includes('--encoding')) {
args.push('--encoding')
args.push('utf8')
}
if (urls !== null) {
if (isString(urls)) urls = [urls]
for (let i = 0; i < urls.length; i++) {
const video = urls[i]
if (isYouTubeRegex.test(video)) {
// Get possible IDs.
const details = url.parse(video, true)
let id = details.query.v || ''
if (id) {
args.push('http://www.youtube.com/watch?v=' + id)
} else {
// Get possible IDs for youtu.be from urladdr.
id = details.pathname.slice(1).replace(/^v\//, '')
if (id) {
args.push(video)
args.unshift('-i')
}
}
} else {
if (i === 0) args.push('--')
args.push(video)
}
}
}
return youtubeDl(args, options, cb)
}
/**
* Calls youtube-dl with some arguments and the `cb`
* gets called with the output.
*
* @param {String} url
* @param {Array.<String>} args
* @param {Object} options
* @param {Function(!Error, String)} cb
*/
ytdl.exec = function exec (url, args, options, cb) {
return call(url, [], args, options, cb)
}
/**
* @param {Object} data
* @returns {Object}
*/
function parseInfo (data) {
// youtube-dl might return just an url as a string when using the "-g" or "--get-url" flag
if (isString(data) && data.startsWith('http')) {
data = JSON.stringify({ url: data })
}
const info = JSON.parse(data)
info._duration_raw = info.duration
info._duration_hms = info.duration
? hms.fromS(info.duration, 'hh:mm:ss')
: info.duration
info.duration = info.duration ? formatDuration(info.duration) : info.duration
return info
}
/**
* Set path from youtube-dl.
*
* @param {String} path
*/
ytdl.setYtdlBinary = function setYtdlBinary (path) {
ytdlBinary = path
}
/**
* Get path from youtube-dl.
*
* @param {String} path
*/
ytdl.getYtdlBinary = function getYtdlBinary () {
return ytdlBinary
}
/**
* Gets info from a video.
*
* @param {String} url
* @param {Array.<String>} args
* @param {Object} options
* @param {Function(!Error, Object)} cb
*/
ytdl.getInfo = function getInfo (url, args, options, cb) {
if (typeof options === 'function') {
cb = options
options = {}
} else if (typeof args === 'function') {
cb = args
options = {}
args = []
}
const defaultArgs = ['--dump-json']
if (
!args ||
(!has(args, '-f') &&
!has(args, '--format') &&
args.every(function (a) {
return a.indexOf('--format=') !== 0
}))
) {
defaultArgs.push('-f')
defaultArgs.push('best')
}
call(url, defaultArgs, args, options, function done (err, data) {
if (err) return cb(err)
let info
// If using the "-g" or "--get-url" flag youtube-dl will return just a string (the URL to the video) which messes up the parsing
// This fixes this behaviour
if (has(args, '-g') || has(args, '--get-url')) {
if (Array.isArray(data) && data.length >= 2) data.splice(0, 1)
}
try {
info = data.map(parseInfo)
} catch (err) {
return cb(err)
}
return cb(null, info.length === 1 ? info[0] : info)
})
}
/**
* @param {String} url
* @param {Object} options
* {Boolean} auto
* {Boolean} all
* {String} lang
* {String} format
* {String} cwd
* @param {Function(!Error, Object)} cb
*/
ytdl.getSubs = function getSubs (url, options, cb) {
if (typeof options === 'function') {
cb = options
options = {}
}
const args = ['--skip-download']
args.push('--write' + (options.auto ? '-auto' : '') + '-sub')
if (options.all) args.push('--all-subs')
if (options.lang) args.push('--sub-lang=' + options.lang)
if (options.format) args.push('--sub-format=' + options.format)
if (!options.warrning) args.push('--no-warnings')
call(url, args, [], { cwd: options.cwd }, function (err, data) {
if (err) return cb(err)
const files = []
for (let i = 0, len = data.length; i < len; i++) {
const line = data[i]
if (line.indexOf('[info] Writing video subtitles to: ') === 0) {
files.push(line.slice(35))
}
}
return cb(null, files)
})
}
/**
* @param {String} url
* @param {Object} options
* {Boolean} all
* {String} cwd
* @param {Function(!Error, Object)} cb
*/
ytdl.getThumbs = function getThumbs (url, options, cb) {
if (typeof options === 'function') {
cb = options
options = {}
}
const args = ['--skip-download']
if (options.all) args.push('--write-all-thumbnails')
else args.push('--write-thumbnail')
if (!options.warrning) args.push('--no-warnings')
call(url, args, [], { cwd: options.cwd }, function (err, data) {
if (err) return cb(err)
const files = []
for (let i = 0, len = data.length; i < len; i++) {
const line = data[i]
const info = 'Writing thumbnail to: '
if (has(line, info)) {
files.push(line.slice(line.indexOf(info) + info.length))
}
}
return cb(null, files)
})
}
/**
* @param {!Boolean} descriptions
* @param {!Object} options
* @param {Function(!Error, Object)} cb
*/
ytdl.getExtractors = function getExtractors (descriptions, options, cb) {
if (typeof options === 'function') {
cb = options
options = {}
} else if (typeof descriptions === 'function') {
cb = descriptions
options = {}
descriptions = false
}
const args = descriptions
? ['--extractor-descriptions']
: ['--list-extractors']
return call(null, args, null, options, cb)
}
{
"_from": "@microlink/youtube-dl",
"_id": "@microlink/youtube-dl@2.0.0",
"_inBundle": false,
"_integrity": "sha512-B2DqRrDHFMu1MsBTq6ZAKR4BtKgvOK91Ci9EQiMVbSGC1/3UIPxpIYP4Py4kzcS94B++zVSMirhnCgX//5Qs4w==",
"_location": "/@microlink/youtube-dl",
"_phantomChildren": {},
"_requested": {
"type": "tag",
"registry": true,
"raw": "@microlink/youtube-dl",
"name": "@microlink/youtube-dl",
"escapedName": "@microlink%2fyoutube-dl",
"scope": "@microlink",
"rawSpec": "",
"saveSpec": null,
"fetchSpec": "latest"
},
"_requiredBy": [
"#USER",
"/"
],
"_resolved": "https://registry.npmjs.org/@microlink/youtube-dl/-/youtube-dl-2.0.0.tgz",
"_shasum": "0120c67949185228afe4d771cfd80719b278cd73",
"_spec": "@microlink/youtube-dl",
"_where": "C:\\Users\\user\\Desktop\\오소git\\오소플젝\\Youtube_MPL",
"author": {
"name": "Roly Fentanes",
"url": "https://github.com/fent"
},
"bugs": {
"url": "https://github.com/przemyslawpluta/node-youtube-dl/issues"
},
"bundleDependencies": false,
"commitlint": {
"extends": [
"@commitlint/config-conventional"
]
},
"contributors": [
{
"name": "Roly Fentanes",
"email": "roly426@gmail.com"
},
{
"name": "przemyslawpluta",
"email": "przemekpluta@hotmail.com"
},
{
"name": "Kiko Beats",
"email": "josefrancisco.verdu@gmail.com"
},
{
"name": "Jay Salvat",
"email": "jay@jaysalvat.com"
},
{
"name": "Benjamin C",
"email": "benjamin@coriou.net"
},
{
"name": "Gregoire Guémas",
"email": "gregoire.guemas@navispeed.eu"
},
{
"name": "Jaime Marquínez Ferrándiz",
"email": "jaime.marquinez.ferrandiz@gmail.com"
},
{
"name": "Jay Baker",
"email": "logikal@gmail.com"
},
{
"name": "Jack Li",
"email": "jack.lee2980@gmail.com"
},
{
"name": "optikfluffel",
"email": "optik@fluffel.io"
},
{
"name": "Calvin",
"email": "calvin@sealtelecom.com.br"
},
{
"name": "Jeremy Louie",
"email": "jeremy@jeremylouie.com"
},
{
"name": "Sergey M․",
"email": "dstftw@gmail.com"
},
{
"name": "t3rr0r",
"email": "mail@t3rr0r.com"
},
{
"name": "EragonJ",
"email": "eragonj@eragonj.me"
},
{
"name": "tifroz",
"email": "hhardel@gmail.com"
},
{
"name": "walheresq",
"email": "walheresq@hotmail.com"
},
{
"name": "Alireza Mirian",
"email": "alireza.mirian@gmail.com"
},
{
"name": "▟ ▖▟ ▖",
"email": "dodo.the.last@gmail.com"
},
{
"name": "Davide Pastore",
"email": "pasdavide@gmail.com"
},
{
"name": "Farrin Reid",
"email": "blakmatrix@gmail.com"
},
{
"name": "Jason Penny",
"email": "jason@jooraccess.com"
},
{
"name": "Juan C. Olivares",
"email": "cristobal@cxsoftware.com"
},
{
"name": "Lopez Hugo",
"email": "hugo.lpz@gmail.com"
},
{
"name": "Meral",
"email": "meral.harbes@gmail.com"
},
{
"name": "Michael Nguyen",
"email": "tehtotalpwnage@gmail.com"
},
{
"name": "Nicolas Gotchac",
"email": "ngotchac@gmail.com"
},
{
"name": "Parikshit Hooda",
"email": "phooda804@live.com"
},
{
"name": "Pietro",
"email": "pietro.passarelli@gmail.com"
},
{
"name": "Sagi Nadir",
"email": "saginadir@gmail.com"
},
{
"name": "bartronicus",
"email": "matthewdavidbarton@gmail.com"
},
{
"name": "btmdave",
"email": "dave@bluetopmedia.com"
},
{
"name": "coderaiser",
"email": "mnemonic.enemy@gmail.com"
}
],
"dependencies": {
"hh-mm-ss": "~1.2.0",
"mkdirp": "~0.5.1",
"request": "~2.88.0",
"streamify": "~0.2.9"
},
"deprecated": false,
"description": "youtube-dl driver for node",
"devDependencies": {
"@commitlint/cli": "latest",
"@commitlint/config-conventional": "latest",
"finepack": "latest",
"git-authors-cli": "latest",
"husky": "latest",
"lint-staged": "latest",
"prettier-standard": "latest",
"standard": "latest",
"standard-markdown": "latest",
"standard-version": "latest",
"vows": "latest"
},
"engines": {
"node": ">= 8"
},
"files": [
"lib",
"scripts"
],
"homepage": "https://github.com/przemyslawpluta/node-youtube-dl#readme",
"husky": {
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS",
"pre-commit": "lint-staged"
}
},
"keywords": [
"download",
"video",
"youtube"
],
"license": "MIT",
"lint-staged": {
"linters": {
"package.json": [
"finepack",
"git add"
],
"*.js": [
"prettier-standard",
"git add"
],
"*.md": [
"standard-markdown",
"git add"
]
}
},
"main": "./lib/youtube-dl.js",
"name": "@microlink/youtube-dl",
"repository": {
"type": "git",
"url": "git://github.com/przemyslawpluta/node-youtube-dl.git"
},
"scripts": {
"lint": "standard-markdown README.md && standard",
"postinstall": "node ./scripts/download.js",
"release": "bumped release",
"test": "vows ./test/*.js --spec",
"update": "node ./scripts/download.js"
},
"version": "2.0.0"
}
var downloader = require('../lib/downloader')
downloader(function error (err, done) {
if (err) return console.log(err.stack)
console.log(done)
})
Hashish
=======
Hashish is a node.js library for manipulating hash data structures.
It is distilled from the finest that ruby, perl, and haskell have to offer by
way of hash/map interfaces.
Hashish provides a chaining interface, where you can do:
var Hash = require('hashish');
Hash({ a : 1, b : 2, c : 3, d : 4 })
.map(function (x) { return x * 10 })
.filter(function (x) { return x < 30 })
.forEach(function (x, key) {
console.log(key + ' => ' + x);
})
;
Output:
a => 10
b => 20
Some functions and attributes in the chaining interface are terminal, like
`.items` or `.detect()`. They return values of their own instead of the chain
context.
Each function in the chainable interface is also attached to `Hash` in chainless
form:
var Hash = require('hashish');
var obj = { a : 1, b : 2, c : 3, d : 4 };
var mapped = Hash.map(obj, function (x) {
return x * 10
});
console.dir(mapped);
Output:
{ a: 10, b: 20, c: 30, d: 40 }
In either case, the 'this' context of the function calls is the same object that
the chained functions return, so you can make nested chains.
Methods
=======
forEach(cb)
-----------
For each key/value in the hash, calls `cb(value, key)`.
map(cb)
-------
For each key/value in the hash, calls `cb(value, key)`.
The return value of `cb` is the new value at `key` in the resulting hash.
filter(cb)
----------
For each key/value in the hash, calls `cb(value, key)`.
The resulting hash omits key/value pairs where `cb` returned a falsy value.
detect(cb)
----------
Returns the first value in the hash for which `cb(value, key)` is non-falsy.
Order of hashes is not well-defined so watch out for that.
reduce(cb)
----------
Returns the accumulated value of a left-fold over the key/value pairs.
some(cb)
--------
Returns a boolean: whether or not `cb(value, key)` ever returned a non-falsy
value.
update(obj1, [obj2, obj3, ...])
-----------
Mutate the context hash, merging the key/value pairs from the passed objects
and overwriting keys from the context hash if the current `obj` has keys of
the same name. Falsy arguments are silently ignored.
updateAll([ obj1, obj2, ... ])
------------------------------
Like multi-argument `update()` but operate on an array directly.
merge(obj1, [obj2, obj3, ...])
----------
Merge the key/value pairs from the passed objects into the resultant hash
without modifying the context hash. Falsy arguments are silently ignored.
mergeAll([ obj1, obj2, ... ])
------------------------------
Like multi-argument `merge()` but operate on an array directly.
has(key)
--------
Return whether the hash has a key, `key`.
valuesAt(keys)
--------------
Return an Array with the values at the keys from `keys`.
tap(cb)
-------
Call `cb` with the present raw hash.
This function is chainable.
extract(keys)
-------------
Filter by including only those keys in `keys` in the resulting hash.
exclude(keys)
-------------
Filter by excluding those keys in `keys` in the resulting hash.
Attributes
==========
These are attributes in the chaining interface and functions in the `Hash.xxx`
interface.
keys
----
Return all the enumerable attribute keys in the hash.
values
------
Return all the enumerable attribute values in the hash.
compact
-------
Filter out values which are `=== undefined`.
clone
-----
Make a deep copy of the hash.
copy
----
Make a shallow copy of the hash.
length
------
Return the number of key/value pairs in the hash.
Note: use `Hash.size()` for non-chain mode.
size
----
Alias for `length` since `Hash.length` is masked by `Function.prototype`.
See Also
========
See also [creationix's pattern/hash](http://github.com/creationix/pattern),
which does a similar thing except with hash inputs and array outputs.
Installation
============
To install with [npm](http://github.com/isaacs/npm):
npm install hashish
To run the tests with [expresso](http://github.com/visionmedia/expresso):
expresso
var Hash = require('hashish');
Hash({ a : 1, b : 2, c : 3, d : 4 })
.map(function (x) { return x * 10 })
.filter(function (x) { return x < 30 })
.forEach(function (x, key) {
console.log(key + ' => ' + x);
})
;
var Hash = require('hashish');
var obj = { a : 1, b : 2, c : 3, d : 4 };
var mapped = Hash.map(obj, function (x) {
return x * 10
});
console.dir(mapped);
module.exports = Hash;
var Traverse = require('traverse');
function Hash (hash, xs) {
if (Array.isArray(hash) && Array.isArray(xs)) {
var to = Math.min(hash.length, xs.length);
var acc = {};
for (var i = 0; i < to; i++) {
acc[hash[i]] = xs[i];
}
return Hash(acc);
}
if (hash === undefined) return Hash({});
var self = {
map : function (f) {
var acc = { __proto__ : hash.__proto__ };
Object.keys(hash).forEach(function (key) {
acc[key] = f.call(self, hash[key], key);
});
return Hash(acc);
},
forEach : function (f) {
Object.keys(hash).forEach(function (key) {
f.call(self, hash[key], key);
});
return self;
},
filter : function (f) {
var acc = { __proto__ : hash.__proto__ };
Object.keys(hash).forEach(function (key) {
if (f.call(self, hash[key], key)) {
acc[key] = hash[key];
}
});
return Hash(acc);
},
detect : function (f) {
for (var key in hash) {
if (f.call(self, hash[key], key)) {
return hash[key];
}
}
return undefined;
},
reduce : function (f, acc) {
var keys = Object.keys(hash);
if (acc === undefined) acc = keys.shift();
keys.forEach(function (key) {
acc = f.call(self, acc, hash[key], key);
});
return acc;
},
some : function (f) {
for (var key in hash) {
if (f.call(self, hash[key], key)) return true;
}
return false;
},
update : function (obj) {
if (arguments.length > 1) {
self.updateAll([].slice.call(arguments));
}
else {
Object.keys(obj).forEach(function (key) {
hash[key] = obj[key];
});
}
return self;
},
updateAll : function (xs) {
xs.filter(Boolean).forEach(function (x) {
self.update(x);
});
return self;
},
merge : function (obj) {
if (arguments.length > 1) {
return self.copy.updateAll([].slice.call(arguments));
}
else {
return self.copy.update(obj);
}
},
mergeAll : function (xs) {
return self.copy.updateAll(xs);
},
has : function (key) { // only operates on enumerables
return Array.isArray(key)
? key.every(function (k) { return self.has(k) })
: self.keys.indexOf(key.toString()) >= 0;
},
valuesAt : function (keys) {
return Array.isArray(keys)
? keys.map(function (key) { return hash[key] })
: hash[keys]
;
},
tap : function (f) {
f.call(self, hash);
return self;
},
extract : function (keys) {
var acc = {};
keys.forEach(function (key) {
acc[key] = hash[key];
});
return Hash(acc);
},
exclude : function (keys) {
return self.filter(function (_, key) {
return keys.indexOf(key) < 0
});
},
end : hash,
items : hash
};
var props = {
keys : function () { return Object.keys(hash) },
values : function () {
return Object.keys(hash).map(function (key) { return hash[key] });
},
compact : function () {
return self.filter(function (x) { return x !== undefined });
},
clone : function () { return Hash(Hash.clone(hash)) },
copy : function () { return Hash(Hash.copy(hash)) },
length : function () { return Object.keys(hash).length },
size : function () { return self.length }
};
if (Object.defineProperty) {
// es5-shim has an Object.defineProperty but it throws for getters
try {
for (var key in props) {
Object.defineProperty(self, key, { get : props[key] });
}
}
catch (err) {
for (var key in props) {
if (key !== 'clone' && key !== 'copy' && key !== 'compact') {
// ^ those keys use Hash() so can't call them without
// a stack overflow
self[key] = props[key]();
}
}
}
}
else if (self.__defineGetter__) {
for (var key in props) {
self.__defineGetter__(key, props[key]);
}
}
else {
// non-lazy version for browsers that suck >_<
for (var key in props) {
self[key] = props[key]();
}
}
return self;
};
// deep copy
Hash.clone = function (ref) {
return Traverse.clone(ref);
};
// shallow copy
Hash.copy = function (ref) {
var hash = { __proto__ : ref.__proto__ };
Object.keys(ref).forEach(function (key) {
hash[key] = ref[key];
});
return hash;
};
Hash.map = function (ref, f) {
return Hash(ref).map(f).items;
};
Hash.forEach = function (ref, f) {
Hash(ref).forEach(f);
};
Hash.filter = function (ref, f) {
return Hash(ref).filter(f).items;
};
Hash.detect = function (ref, f) {
return Hash(ref).detect(f);
};
Hash.reduce = function (ref, f, acc) {
return Hash(ref).reduce(f, acc);
};
Hash.some = function (ref, f) {
return Hash(ref).some(f);
};
Hash.update = function (a /*, b, c, ... */) {
var args = Array.prototype.slice.call(arguments, 1);
var hash = Hash(a);
return hash.update.apply(hash, args).items;
};
Hash.merge = function (a /*, b, c, ... */) {
var args = Array.prototype.slice.call(arguments, 1);
var hash = Hash(a);
return hash.merge.apply(hash, args).items;
};
Hash.has = function (ref, key) {
return Hash(ref).has(key);
};
Hash.valuesAt = function (ref, keys) {
return Hash(ref).valuesAt(keys);
};
Hash.tap = function (ref, f) {
return Hash(ref).tap(f).items;
};
Hash.extract = function (ref, keys) {
return Hash(ref).extract(keys).items;
};
Hash.exclude = function (ref, keys) {
return Hash(ref).exclude(keys).items;
};
Hash.concat = function (xs) {
var hash = Hash({});
xs.forEach(function (x) { hash.update(x) });
return hash.items;
};
Hash.zip = function (xs, ys) {
return Hash(xs, ys).items;
};
// .length is already defined for function prototypes
Hash.size = function (ref) {
return Hash(ref).size;
};
Hash.compact = function (ref) {
return Hash(ref).compact.items;
};
{
"_from": "hashish@~0.0.4",
"_id": "hashish@0.0.4",
"_inBundle": false,
"_integrity": "sha1-bWC8b/r3Ebav1g5CbQd5iAFOZVQ=",
"_location": "/hashish",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "hashish@~0.0.4",
"name": "hashish",
"escapedName": "hashish",
"rawSpec": "~0.0.4",
"saveSpec": null,
"fetchSpec": "~0.0.4"
},
"_requiredBy": [
"/streamify"
],
"_resolved": "https://registry.npmjs.org/hashish/-/hashish-0.0.4.tgz",
"_shasum": "6d60bc6ffaf711b6afd60e426d077988014e6554",
"_spec": "hashish@~0.0.4",
"_where": "C:\\Users\\user\\Desktop\\오소git\\오소플젝\\Youtube_MPL\\node_modules\\streamify",
"author": {
"name": "James Halliday",
"email": "mail@substack.net",
"url": "http://substack.net"
},
"bugs": {
"url": "https://github.com/substack/node-hashish/issues"
},
"bundleDependencies": false,
"dependencies": {
"traverse": ">=0.2.4"
},
"deprecated": false,
"description": "Hash data structure manipulation functions",
"devDependencies": {
"expresso": ">=0.6.0"
},
"engine": [
"node >=0.2.0"
],
"engines": {
"node": "*"
},
"homepage": "https://github.com/substack/node-hashish#readme",
"keywords": [
"hash",
"object",
"convenience",
"manipulation",
"data structure"
],
"license": "MIT/X11",
"main": "./index.js",
"name": "hashish",
"repository": {
"type": "git",
"url": "git+ssh://git@github.com/substack/node-hashish.git"
},
"scripts": {
"test": "expresso"
},
"version": "0.0.4"
}
var Hash = require('hashish');
var assert = require('assert');
exports.map = function () {
var ref = { a : 1, b : 2 };
var items = Hash(ref).map(function (v) { return v + 1 }).items;
var hash = Hash.map(ref, function (v) { return v + 1 });
assert.deepEqual(ref, { a : 1, b : 2 });
assert.deepEqual(items, { a : 2, b : 3 });
assert.deepEqual(hash, { a : 2, b : 3 });
};
exports['cloned map'] = function () {
var ref = { foo : [1,2], bar : [4,5] };
var hash = Hash(ref).clone.map(
function (v) { v.unshift(v[0] - 1); return v }
).items;
assert.deepEqual(ref.foo, [1,2]);
assert.deepEqual(ref.bar, [4,5]);
assert.deepEqual(hash.foo, [0,1,2]);
assert.deepEqual(hash.bar, [3,4,5]);
};
exports.forEach = function () {
var ref = { a : 5, b : 2, c : 7, 1337 : 'leet' };
var xs = [];
Hash(ref).forEach(function (x, i) {
xs.push([ i, x ]);
});
assert.eql(
xs.map(function (x) { return x[0] }).sort(),
[ '1337', 'a', 'b', 'c' ]
);
assert.eql(
xs.map(function (x) { return x[1] }).sort(),
[ 2, 5, 7, 'leet' ]
);
var ys = [];
Hash.forEach(ref, function (x, i) {
ys.push([ i, x ]);
});
assert.eql(xs.sort(), ys.sort());
};
exports.filter_items = function () {
var ref = { a : 5, b : 2, c : 7, 1337 : 'leet' };
var items = Hash(ref).filter(function (v, k) {
return v > 5 || k > 5
}).items;
var hash = Hash.filter(ref, function (v, k) { return v > 5 || k > 5 });
assert.deepEqual(items, { 1337 : 'leet', c : 7 });
assert.deepEqual(hash, { 1337 : 'leet', c : 7 });
assert.deepEqual(ref, { a : 5, b : 2, c : 7, 1337 : 'leet' });
assert.equal(Hash(ref).length, 4);
};
exports.detect = function () {
var h = { a : 5, b : 6, c : 7, d : 8 };
var hh = Hash(h);
var gt6hh = hh.detect(function (x) { return x > 6 });
assert.ok(gt6hh == 7 || gt6hh == 8);
var gt6h = Hash.detect(h, function (x) { return x > 6 });
assert.ok(gt6h == 7 || gt6h == 8);
assert.equal(hh.detect(function (x) { return x > 100 }), undefined);
};
exports.reduce = function () {
var ref = { foo : [1,2], bar : [4,5] };
var sum1 = Hash(ref).reduce(function (acc, v) {
return acc + v.length
}, 0);
assert.equal(sum1, 4);
var sum2 = Hash.reduce(ref, function (acc, v) {
return acc + v.length
}, 0);
assert.equal(sum2, 4);
};
exports.some = function () {
var h = { a : 5, b : 6, c : 7, d : 8 };
var hh = Hash(h);
assert.ok(Hash.some(h, function (x) { return x > 7 }));
assert.ok(Hash.some(h, function (x) { return x < 6 }));
assert.ok(!Hash.some(h, function (x) { return x > 10 }));
assert.ok(!Hash.some(h, function (x) { return x < 0 }));
assert.ok(hh.some(function (x) { return x > 7 }));
assert.ok(hh.some(function (x) { return x < 6 }));
assert.ok(!hh.some(function (x) { return x > 10 }));
assert.ok(!hh.some(function (x) { return x < 0 }));
};
exports.update = function () {
var ref = { a : 1, b : 2 };
var items = Hash(ref).clone.update({ c : 3, a : 0 }).items;
assert.deepEqual(ref, { a : 1, b : 2 });
assert.deepEqual(items, { a : 0, b : 2, c : 3 });
var hash = Hash.update(ref, { c : 3, a : 0 });
assert.deepEqual(ref, hash);
assert.deepEqual(hash, { a : 0, b : 2, c : 3 });
var ref2 = {a: 1};
var hash2 = Hash.update(ref2, { b: 2, c: 3 }, undefined, { d: 4 });
assert.deepEqual(ref2, { a: 1, b: 2, c: 3, d: 4 });
};
exports.merge = function () {
var ref = { a : 1, b : 2 };
var items = Hash(ref).merge({ b : 3, c : 3.14 }).items;
var hash = Hash.merge(ref, { b : 3, c : 3.14 });
assert.deepEqual(ref, { a : 1, b : 2 });
assert.deepEqual(items, { a : 1, b : 3, c : 3.14 });
assert.deepEqual(hash, { a : 1, b : 3, c : 3.14 });
var ref2 = { a : 1 };
var hash2 = Hash.merge(ref, { b: 2, c: 3 }, undefined, { d: 4 });
assert.deepEqual(hash2, { a: 1, b: 2, c: 3, d: 4 });
};
exports.has = function () {
var h = { a : 4, b : 5 };
var hh = Hash(h);
assert.ok(hh.has('a'));
assert.equal(hh.has('c'), false);
assert.ok(hh.has(['a','b']));
assert.equal(hh.has(['a','b','c']), false);
assert.ok(Hash.has(h, 'a'));
assert.equal(Hash.has(h, 'c'), false);
assert.ok(Hash.has(h, ['a','b']));
assert.equal(Hash.has(h, ['a','b','c']), false);
};
exports.valuesAt = function () {
var h = { a : 4, b : 5, c : 6 };
assert.equal(Hash(h).valuesAt('a'), 4);
assert.equal(Hash(h).valuesAt(['a'])[0], 4);
assert.deepEqual(Hash(h).valuesAt(['a','b']), [4,5]);
assert.equal(Hash.valuesAt(h, 'a'), 4);
assert.deepEqual(Hash.valuesAt(h, ['a']), [4]);
assert.deepEqual(Hash.valuesAt(h, ['a','b']), [4,5]);
};
exports.tap = function () {
var h = { a : 4, b : 5, c : 6 };
var hh = Hash(h);
hh.tap(function (x) {
assert.ok(this === hh)
assert.eql(x, h);
});
Hash.tap(h, function (x) {
assert.eql(
Object.keys(this).sort(),
Object.keys(hh).sort()
);
assert.eql(x, h);
});
};
exports.extract = function () {
var hash = Hash({ a : 1, b : 2, c : 3 }).clone;
var extracted = hash.extract(['a','b']);
assert.equal(extracted.length, 2);
assert.deepEqual(extracted.items, { a : 1, b : 2 });
};
exports.exclude = function () {
var hash = Hash({ a : 1, b : 2, c : 3 }).clone;
var extracted = hash.exclude(['a','b']);
assert.equal(extracted.length, 1);
assert.deepEqual(extracted.items, { c : 3 });
};
exports.concat = function () {
var ref1 = { a : 1, b : 2 };
var ref2 = { foo : 100, bar : 200 };
var ref3 = { b : 3, c : 4, bar : 300 };
assert.deepEqual(
Hash.concat([ ref1, ref2 ]),
{ a : 1, b : 2, foo : 100, bar : 200 }
);
assert.deepEqual(
Hash.concat([ ref1, ref2, ref3 ]),
{ a : 1, b : 3, c : 4, foo : 100, bar : 300 }
);
};
exports.zip = function () {
var xs = ['a','b','c'];
var ys = [1,2,3,4];
var h = Hash(xs,ys);
assert.equal(h.length, 3);
assert.deepEqual(h.items, { a : 1, b : 2, c : 3 });
var zipped = Hash.zip(xs,ys);
assert.deepEqual(zipped, { a : 1, b : 2, c : 3 });
};
exports.length = function () {
assert.equal(Hash({ a : 1, b : [2,3], c : 4 }).length, 3);
assert.equal(Hash({ a : 1, b : [2,3], c : 4 }).size, 3);
assert.equal(Hash.size({ a : 1, b : [2,3], c : 4 }), 3);
};
exports.compact = function () {
var hash = {
a : 1,
b : undefined,
c : false,
d : 4,
e : [ undefined, 4 ],
f : null
};
var compacted = Hash(hash).compact;
assert.deepEqual(
{
a : 1,
b : undefined,
c : false,
d : 4,
e : [ undefined, 4 ],
f : null
},
hash, 'compact modified the hash'
);
assert.deepEqual(
compacted.items,
{
a : 1,
c : false,
d : 4,
e : [ undefined, 4 ],
f : null
}
);
var h = Hash.compact(hash);
assert.deepEqual(h, compacted.items);
};
var Hash = require('hashish');
var assert = require('assert');
var vm = require('vm');
var fs = require('fs');
var src = fs.readFileSync(__dirname + '/../index.js', 'utf8');
exports.defineGetter = function () {
var context = {
module : { exports : {} },
Object : {
keys : Object.keys,
defineProperty : undefined,
},
require : require,
};
context.exports = context.module.exports;
vm.runInNewContext('(function () {' + src + '})()', context);
var Hash_ = context.module.exports;
var times = 0;
Hash_.__proto__.__proto__.__defineGetter__ = function () {
times ++;
return Object.__defineGetter__.apply(this, arguments);
};
assert.equal(vm.runInNewContext('Object.defineProperty', context), null);
assert.deepEqual(
Hash_({ a : 1, b : 2, c : 3 }).values,
[ 1, 2, 3 ]
);
assert.ok(times > 5);
};
exports.defineProperty = function () {
var times = 0;
var context = {
module : { exports : {} },
Object : {
keys : Object.keys,
defineProperty : function (prop) {
times ++;
if (prop.get) throw new TypeError('engine does not support')
assert.fail('should have asserted by now');
},
},
require : require
};
context.exports = context.module.exports;
vm.runInNewContext('(function () {' + src + '})()', context);
var Hash_ = context.module.exports;
Hash_.__proto__.__proto__.__defineGetter__ = function () {
assert.fail('getter called when a perfectly good'
+ ' defineProperty was available'
);
};
assert.deepEqual(
Hash_({ a : 1, b : 2, c : 3 }).values,
[ 1, 2, 3 ]
);
assert.equal(times, 1);
};
language: node_js
node_js:
- 'node'
The MIT License (MIT)
Copyright (c) Adam Gotlib
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# hh-mm-ss: time formatting utility
[![Build Status](https://travis-ci.org/Goldob/hh-mm-ss.svg?branch=master)](https://travis-ci.org/Goldob/hh-mm-ss)
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/)
:watch: Convert seconds or miliseconds to `hh:mm:ss` format and vice versa.
```js
var TimeFormat = require('hh-mm-ss')
TimeFormat.toS('137:00:00') // 493200
TimeFormat.toS('02:00') // 120
TimeFormat.toS('02:00', 'hh:mm') // 7200
TimeFormat.fromS(194) // '03:14'
TimeFormat.fromS(150, 'hh:mm:ss') // '00:02:30'
TimeFormat.fromS(8100, 'hh:mm') // '02:15'
TimeFormat.fromMs(12345) // '00:12.345'
```
## Usage
### `toMs(time, format)`
Convert given `hh:mm:ss` formatted string to miliseconds
#### Parameters
- `time` String representation
- `format` _(optional)_ Default input format. If present, it will be used to resolve amiguities during interpretation. If not specified, `mm:ss` is implied. See section below for supported format list
### `toS(time, format)`
Convert given `hh:mm:ss` formatted string to seconds
#### Parameters
- `time` String representation
- `format` _(optional)_ Default input format. If present, it will be used to resolve amiguities during interpretation. If not specified, `mm:ss` is implied. See section below for supported format list
### `fromMs(ms, format)`
Generate formatted string from time in miliseconds
#### Parameters
- `ms` Time in miliseconds
- `format` _(optional)_ Default output format. If not specified, `mm:ss` is implied. See section below for supported format list.
### `fromS(s, format)`
Generate formatted string from time in seconds
#### Parameters
- `s` Time in seconds
- `format` _(optional)_ Default output format. If not specified, `mm:ss` is implied. See section below for supported format list
### Supported time formats
The following formats are supported: `mm:ss`, `hh:mm`, `hh:mm:ss`, `mm:ss.sss`, `hh:mm:ss.sss`.
- `hh` - hours
- `mm` - minutes
- `ss` - second
- `sss` - miliseconds
Specified format constitutes a baseline for corresponding functions, but will be appropriately extended as needed. For example, `fromMs(9000, 'mm:ss')` will return `01:30`, yet `fromMs(9500, 'mm:ss')` will return `01:30.500` to account for the miliseconds part.
## Install
`npm install hh-mm-ss --save`
## License
MIT
'use strict'
module.exports = {
fromMs,
fromS,
toMs,
toS
}
const zeroFill = require('zero-fill')
// Time units with their corresponding values in miliseconds
const HOUR = 3600000
const MINUTE = 60000
const SECOND = 1000
const TIME_FORMAT_ERRMSG = 'Time format error'
// =============================================================================
// Export functions
// =============================================================================
function fromMs (ms, format = 'mm:ss') {
if (typeof ms !== 'number' || Number.isNaN(ms)) {
throw new Error('NaN error')
}
let absMs = Math.abs(ms)
let negative = (ms < 0)
let hours = Math.floor(absMs / HOUR)
let minutes = Math.floor(absMs % HOUR / MINUTE)
let seconds = Math.floor(absMs % MINUTE / SECOND)
let miliseconds = Math.floor(absMs % SECOND)
return formatTime({
negative, hours, minutes, seconds, miliseconds
}, format)
}
function fromS (s, format = 'mm:ss') {
if (typeof s !== 'number' || Number.isNaN(s)) {
throw new Error('NaN error')
}
let ms = s * SECOND
return fromMs(ms, format)
}
function toMs (time, format = 'mm:ss') {
let re
if (['mm:ss', 'mm:ss.sss', 'hh:mm:ss', 'hh:mm:ss.sss'].includes(format)) {
re = /^(-)?(?:(\d\d+):)?(\d\d):(\d\d)(\.\d+)?$/
} else if (format === 'hh:mm') {
re = /^(-)?(\d\d):(\d\d)(?::(\d\d)(?:(\.\d+))?)?$/
} else {
throw new Error(TIME_FORMAT_ERRMSG)
}
let result = re.exec(time)
if (!result) throw new Error()
let negative = result[1] === '-'
let hours = result[2] | 0
let minutes = result[3] | 0
let seconds = result[4] | 0
let miliseconds = Math.floor(1000 * result[5] | 0)
if (minutes > 60 || seconds > 60) {
throw new Error()
}
return (negative ? -1 : 1) * (
hours * HOUR + minutes * MINUTE + seconds * SECOND + miliseconds
)
}
function toS (time, format = 'mm:ss') {
let ms = toMs(time, format)
return Math.floor(ms / SECOND)
}
// =============================================================================
// Utility functions
// =============================================================================
function formatTime (time, format) {
let showMs
let showSc
let showHr
switch (format.toLowerCase()) {
case 'hh:mm:ss.sss':
showMs = true
showSc = true
showHr = true
break
case 'hh:mm:ss':
showMs = !(!time.miliseconds)
showSc = true
showHr = true
break
case 'hh:mm':
showMs = !(!time.miliseconds)
showSc = showMs || !(!time.seconds)
showHr = true
break
case 'mm:ss':
showMs = !(!time.miliseconds)
showSc = true
showHr = !(!time.hours)
break
case 'mm:ss.sss':
showMs = true
showSc = true
showHr = !(!time.hours)
break
default:
throw new Error(TIME_FORMAT_ERRMSG)
}
let hh = zeroFill(2, time.hours)
let mm = zeroFill(2, time.minutes)
let ss = zeroFill(2, time.seconds)
let sss = zeroFill(3, time.miliseconds)
return (time.negative ? '-' : '') + (showHr ? (
showMs ? `${hh}:${mm}:${ss}.${sss}` : showSc ? `${hh}:${mm}:${ss}` : `${hh}:${mm}`
) : (
showMs ? `${mm}:${ss}.${sss}` : `${mm}:${ss}`
))
}
{
"_from": "hh-mm-ss@~1.2.0",
"_id": "hh-mm-ss@1.2.0",
"_inBundle": false,
"_integrity": "sha512-f4I9Hz1dLpX/3mrEs7yq30+FiuO3tt5NWAqAGeBTaoeoBfB8vhcQ3BphuDc5DjZb/K809agqrAaFlP0jhEU/8w==",
"_location": "/hh-mm-ss",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "hh-mm-ss@~1.2.0",
"name": "hh-mm-ss",
"escapedName": "hh-mm-ss",
"rawSpec": "~1.2.0",
"saveSpec": null,
"fetchSpec": "~1.2.0"
},
"_requiredBy": [
"/youtube-dl"
],
"_resolved": "https://registry.npmjs.org/hh-mm-ss/-/hh-mm-ss-1.2.0.tgz",
"_shasum": "6d0f0b8280824a634cb1d1f20e0bc7bc8b689948",
"_spec": "hh-mm-ss@~1.2.0",
"_where": "C:\\Users\\user\\Desktop\\오소git\\오소플젝\\Youtube_MPL\\node_modules\\youtube-dl",
"author": {
"name": "Adam Gotlib"
},
"bugs": {
"url": "https://github.com/Goldob/hh-mm-ss/issues"
},
"bundleDependencies": false,
"dependencies": {
"zero-fill": "^2.2.3"
},
"deprecated": false,
"description": "Simple hh:mm:ss time formatting utility",
"devDependencies": {
"standard": "^7.1.2",
"tape": "^4.6.0"
},
"homepage": "https://github.com/Goldob/hh-mm-ss#readme",
"keywords": [
"time format",
"hours",
"minutes",
"seconds",
"miliseconds",
"hh:mm:ss"
],
"license": "MIT",
"main": "index.js",
"name": "hh-mm-ss",
"repository": {
"type": "git",
"url": "git+https://github.com/Goldob/hh-mm-ss.git"
},
"scripts": {
"test": "standard & node test"
},
"version": "1.2.0"
}
'use-strict'
const test = require('tape')
const {fromMs, fromS, toMs, toS} = require('../')
// =============================================================================
// Test cases
// =============================================================================
test('fromMs() test', (t) => {
// Basic functionality
t.equal(fromMs(75000), '01:15')
t.equal(fromMs(442800000), '123:00:00')
t.equal(fromMs(90576), '01:30.576')
t.equal(fromMs(-157250), '-02:37.250')
// Output formatting
t.equal(fromMs(38000, 'mm:ss.sss'), '00:38.000')
t.equal(fromMs(0, 'hh:mm:ss'), '00:00:00')
t.equal(fromMs(3600000, 'mm:ss'), '01:00:00')
t.equal(fromMs(4500000, 'hh:mm'), '01:15')
t.equal(fromMs(-9900000, 'hh:mm'), '-02:45')
// Input validation
t.throws(() => fromMs(null))
t.throws(() => fromMs('text'))
t.throws(() => fromMs(0, 'mm:hh:ss'))
t.end()
})
test('fromS() test', (t) => {
// Basic functionality
t.equal(fromS(75), '01:15')
t.equal(fromS(442800), '123:00:00')
t.equal(fromS(-442800), '-123:00:00')
// Output formatting
t.equal(fromS(38, 'mm:ss.sss'), '00:38.000')
t.equal(fromS(0, 'hh:mm:ss'), '00:00:00')
t.equal(fromS(3600, 'mm:ss'), '01:00:00')
t.equal(fromS(4500, 'hh:mm'), '01:15')
t.equal(fromS(-9900, 'hh:mm'), '-02:45')
// Input validation
t.throws(() => fromS(null))
t.throws(() => fromS('text'))
t.throws(() => fromS(0, 'mm:hh:ss'))
t.end()
})
test('toMs() test', (t) => {
// Basic functionality
t.equal(toMs('01:05:17'), 3917000)
t.equal(toMs('137:00:00.0'), 493200000)
t.equal(toMs('00:10.230'), 10230)
t.equal(toMs('00:00:07.10845'), 7108)
t.equal(toMs('-02:07:12'), -7632000)
t.equal(toMs('02:00'), 120000)
t.equal(toMs('02:00', 'hh:mm'), 7200000)
t.equal(toMs('-04:35', 'hh:mm'), -16500000)
t.equal(toMs('00:00:07.10845', 'hh:mm'), 7108)
// Input validation
t.throws(() => toMs('13:05:02:11'))
t.throws(() => toMs('153'))
t.throws(() => toMs(null))
t.throws(() => toMs('00:62'))
t.throws(() => toS('01:30', 'mm:hh:ss'))
t.end()
})
test('toS() test', (t) => {
// Basic functionality
t.equal(toS('01:05:17'), 3917)
t.equal(toS('137:00:00.0'), 493200)
t.equal(toS('00:10.230'), 10)
t.equal(toS('00:00:07.10845'), 7)
t.equal(toS('-02:07:12'), -7632)
t.equal(toS('02:00'), 120)
t.equal(toS('02:00', 'hh:mm'), 7200)
t.equal(toS('-04:35', 'hh:mm'), -16500)
t.equal(toS('00:00:07.10845', 'hh:mm'), 7)
// Input validation
t.throws(() => toS('13:05:02:11'))
t.throws(() => toS('153'))
t.throws(() => toS(null))
t.throws(() => toS('00:62'))
t.throws(() => toS('01:30', 'mm:hh:ss'))
t.end()
})
test('symmetrical conversion test', (t) => {
/*
* fromMs() and toMs() for all formats
*/
// 90000ms = 1m 30s
t.equal(toMs(fromMs(90000, 'mm:ss'), 'mm:ss'), 90000)
t.equal(toMs(fromMs(90000, 'mm:ss.sss'), 'mm:ss.sss'), 90000)
t.equal(toMs(fromMs(90000, 'hh:mm'), 'hh:mm'), 90000)
t.equal(toMs(fromMs(90000, 'hh:mm:ss'), 'hh:mm:ss'), 90000)
t.equal(toMs(fromMs(90000, 'hh:mm:ss.sss'), 'hh:mm:ss.sss'), 90000)
// 7517245ms = 2h 5m 17.245s
t.equal(toMs(fromMs(7517245, 'mm:ss'), 'mm:ss'), 7517245)
t.equal(toMs(fromMs(7517245, 'mm:ss.sss'), 'mm:ss.sss'), 7517245)
t.equal(toMs(fromMs(7517245, 'hh:mm'), 'hh:mm'), 7517245)
t.equal(toMs(fromMs(7517245, 'hh:mm:ss'), 'hh:mm:ss'), 7517245)
t.equal(toMs(fromMs(7517245, 'hh:mm:ss.sss'), 'hh:mm:ss.sss'), 7517245)
// -10800000ms = -3h
t.equal(toMs(fromMs(-10800000, 'mm:ss'), 'mm:ss'), -10800000)
t.equal(toMs(fromMs(-10800000, 'mm:ss.sss'), 'mm:ss.sss'), -10800000)
t.equal(toMs(fromMs(-10800000, 'hh:mm'), 'hh:mm'), -10800000)
t.equal(toMs(fromMs(-10800000, 'hh:mm:ss'), 'hh:mm:ss'), -10800000)
t.equal(toMs(fromMs(-10800000, 'hh:mm:ss.sss'), 'hh:mm:ss.sss'), -10800000)
/*
* fromS() and toMs() for all formats
*/
// 930s = 15m 30s
t.equal(toS(fromS(930, 'mm:ss'), 'mm:ss'), 930)
t.equal(toS(fromS(930, 'mm:ss.sss'), 'mm:ss.sss'), 930)
t.equal(toS(fromS(930, 'hh:mm'), 'hh:mm'), 930)
t.equal(toS(fromS(930, 'hh:mm:ss'), 'hh:mm:ss'), 930)
t.equal(toS(fromS(930, 'hh:mm:ss.sss'), 'hh:mm:ss.sss'), 930)
// 4850s = 1h 20m 50s
t.equal(toS(fromS(4850, 'mm:ss'), 'mm:ss'), 4850)
t.equal(toS(fromS(4850, 'mm:ss.sss'), 'mm:ss.sss'), 4850)
t.equal(toS(fromS(4850, 'hh:mm'), 'hh:mm'), 4850)
t.equal(toS(fromS(4850, 'hh:mm:ss'), 'hh:mm:ss'), 4850)
t.equal(toS(fromS(4850, 'hh:mm:ss.sss'), 'hh:mm:ss.sss'), 4850)
// -300s = -5m
t.equal(toS(fromS(-300, 'mm:ss'), 'mm:ss'), -300)
t.equal(toS(fromS(-300, 'mm:ss.sss'), 'mm:ss.sss'), -300)
t.equal(toS(fromS(-300, 'hh:mm'), 'hh:mm'), -300)
t.equal(toS(fromS(-300, 'hh:mm:ss'), 'hh:mm:ss'), -300)
t.equal(toS(fromS(-300, 'hh:mm:ss.sss'), 'hh:mm:ss.sss'), -300)
t.end()
})
language: node_js
node_js:
- "0.8"
- "0.10"
This software is released under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
var argv = require('../')(process.argv.slice(2));
console.dir(argv);
module.exports = function (args, opts) {
if (!opts) opts = {};
var flags = { bools : {}, strings : {} };
[].concat(opts['boolean']).filter(Boolean).forEach(function (key) {
flags.bools[key] = true;
});
[].concat(opts.string).filter(Boolean).forEach(function (key) {
flags.strings[key] = true;
});
var aliases = {};
Object.keys(opts.alias || {}).forEach(function (key) {
aliases[key] = [].concat(opts.alias[key]);
aliases[key].forEach(function (x) {
aliases[x] = [key].concat(aliases[key].filter(function (y) {
return x !== y;
}));
});
});
var defaults = opts['default'] || {};
var argv = { _ : [] };
Object.keys(flags.bools).forEach(function (key) {
setArg(key, defaults[key] === undefined ? false : defaults[key]);
});
var notFlags = [];
if (args.indexOf('--') !== -1) {
notFlags = args.slice(args.indexOf('--')+1);
args = args.slice(0, args.indexOf('--'));
}
function setArg (key, val) {
var value = !flags.strings[key] && isNumber(val)
? Number(val) : val
;
setKey(argv, key.split('.'), value);
(aliases[key] || []).forEach(function (x) {
setKey(argv, x.split('.'), value);
});
}
for (var i = 0; i < args.length; i++) {
var arg = args[i];
if (/^--.+=/.test(arg)) {
// Using [\s\S] instead of . because js doesn't support the
// 'dotall' regex modifier. See:
// http://stackoverflow.com/a/1068308/13216
var m = arg.match(/^--([^=]+)=([\s\S]*)$/);
setArg(m[1], m[2]);
}
else if (/^--no-.+/.test(arg)) {
var key = arg.match(/^--no-(.+)/)[1];
setArg(key, false);
}
else if (/^--.+/.test(arg)) {
var key = arg.match(/^--(.+)/)[1];
var next = args[i + 1];
if (next !== undefined && !/^-/.test(next)
&& !flags.bools[key]
&& (aliases[key] ? !flags.bools[aliases[key]] : true)) {
setArg(key, next);
i++;
}
else if (/^(true|false)$/.test(next)) {
setArg(key, next === 'true');
i++;
}
else {
setArg(key, flags.strings[key] ? '' : true);
}
}
else if (/^-[^-]+/.test(arg)) {
var letters = arg.slice(1,-1).split('');
var broken = false;
for (var j = 0; j < letters.length; j++) {
var next = arg.slice(j+2);
if (next === '-') {
setArg(letters[j], next)
continue;
}
if (/[A-Za-z]/.test(letters[j])
&& /-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) {
setArg(letters[j], next);
broken = true;
break;
}
if (letters[j+1] && letters[j+1].match(/\W/)) {
setArg(letters[j], arg.slice(j+2));
broken = true;
break;
}
else {
setArg(letters[j], flags.strings[letters[j]] ? '' : true);
}
}
var key = arg.slice(-1)[0];
if (!broken && key !== '-') {
if (args[i+1] && !/^(-|--)[^-]/.test(args[i+1])
&& !flags.bools[key]
&& (aliases[key] ? !flags.bools[aliases[key]] : true)) {
setArg(key, args[i+1]);
i++;
}
else if (args[i+1] && /true|false/.test(args[i+1])) {
setArg(key, args[i+1] === 'true');
i++;
}
else {
setArg(key, flags.strings[key] ? '' : true);
}
}
}
else {
argv._.push(
flags.strings['_'] || !isNumber(arg) ? arg : Number(arg)
);
}
}
Object.keys(defaults).forEach(function (key) {
if (!hasKey(argv, key.split('.'))) {
setKey(argv, key.split('.'), defaults[key]);
(aliases[key] || []).forEach(function (x) {
setKey(argv, x.split('.'), defaults[key]);
});
}
});
notFlags.forEach(function(key) {
argv._.push(key);
});
return argv;
};
function hasKey (obj, keys) {
var o = obj;
keys.slice(0,-1).forEach(function (key) {
o = (o[key] || {});
});
var key = keys[keys.length - 1];
return key in o;
}
function setKey (obj, keys, value) {
var o = obj;
keys.slice(0,-1).forEach(function (key) {
if (o[key] === undefined) o[key] = {};
o = o[key];
});
var key = keys[keys.length - 1];
if (o[key] === undefined || typeof o[key] === 'boolean') {
o[key] = value;
}
else if (Array.isArray(o[key])) {
o[key].push(value);
}
else {
o[key] = [ o[key], value ];
}
}
function isNumber (x) {
if (typeof x === 'number') return true;
if (/^0x[0-9a-f]+$/i.test(x)) return true;
return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(x);
}
function longest (xs) {
return Math.max.apply(null, xs.map(function (x) { return x.length }));
}
{
"_from": "minimist@0.0.8",
"_id": "minimist@0.0.8",
"_inBundle": false,
"_integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"_location": "/minimist",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "minimist@0.0.8",
"name": "minimist",
"escapedName": "minimist",
"rawSpec": "0.0.8",
"saveSpec": null,
"fetchSpec": "0.0.8"
},
"_requiredBy": [
"/mkdirp"
],
"_resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"_shasum": "857fcabfc3397d2625b8228262e86aa7a011b05d",
"_spec": "minimist@0.0.8",
"_where": "C:\\Users\\user\\Desktop\\오소git\\오소플젝\\Youtube_MPL\\node_modules\\mkdirp",
"author": {
"name": "James Halliday",
"email": "mail@substack.net",
"url": "http://substack.net"
},
"bugs": {
"url": "https://github.com/substack/minimist/issues"
},
"bundleDependencies": false,
"deprecated": false,
"description": "parse argument options",
"devDependencies": {
"tap": "~0.4.0",
"tape": "~1.0.4"
},
"homepage": "https://github.com/substack/minimist",
"keywords": [
"argv",
"getopt",
"parser",
"optimist"
],
"license": "MIT",
"main": "index.js",
"name": "minimist",
"repository": {
"type": "git",
"url": "git://github.com/substack/minimist.git"
},
"scripts": {
"test": "tap test/*.js"
},
"testling": {
"files": "test/*.js",
"browsers": [
"ie/6..latest",
"ff/5",
"firefox/latest",
"chrome/10",
"chrome/latest",
"safari/5.1",
"safari/latest",
"opera/12"
]
},
"version": "0.0.8"
}
# minimist
parse argument options
This module is the guts of optimist's argument parser without all the
fanciful decoration.
[![browser support](https://ci.testling.com/substack/minimist.png)](http://ci.testling.com/substack/minimist)
[![build status](https://secure.travis-ci.org/substack/minimist.png)](http://travis-ci.org/substack/minimist)
# example
``` js
var argv = require('minimist')(process.argv.slice(2));
console.dir(argv);
```
```
$ node example/parse.js -a beep -b boop
{ _: [], a: 'beep', b: 'boop' }
```
```
$ node example/parse.js -x 3 -y 4 -n5 -abc --beep=boop foo bar baz
{ _: [ 'foo', 'bar', 'baz' ],
x: 3,
y: 4,
n: 5,
a: true,
b: true,
c: true,
beep: 'boop' }
```
# methods
``` js
var parseArgs = require('minimist')
```
## var argv = parseArgs(args, opts={})
Return an argument object `argv` populated with the array arguments from `args`.
`argv._` contains all the arguments that didn't have an option associated with
them.
Numeric-looking arguments will be returned as numbers unless `opts.string` or
`opts.boolean` is set for that argument name.
Any arguments after `'--'` will not be parsed and will end up in `argv._`.
options can be:
* `opts.string` - a string or array of strings argument names to always treat as
strings
* `opts.boolean` - a string or array of strings to always treat as booleans
* `opts.alias` - an object mapping string names to strings or arrays of string
argument names to use as aliases
* `opts.default` - an object mapping string argument names to default values
# install
With [npm](https://npmjs.org) do:
```
npm install minimist
```
# license
MIT
var parse = require('../');
var test = require('tape');
test('-', function (t) {
t.plan(5);
t.deepEqual(parse([ '-n', '-' ]), { n: '-', _: [] });
t.deepEqual(parse([ '-' ]), { _: [ '-' ] });
t.deepEqual(parse([ '-f-' ]), { f: '-', _: [] });
t.deepEqual(
parse([ '-b', '-' ], { boolean: 'b' }),
{ b: true, _: [ '-' ] }
);
t.deepEqual(
parse([ '-s', '-' ], { string: 's' }),
{ s: '-', _: [] }
);
});
test('-a -- b', function (t) {
t.plan(3);
t.deepEqual(parse([ '-a', '--', 'b' ]), { a: true, _: [ 'b' ] });
t.deepEqual(parse([ '--a', '--', 'b' ]), { a: true, _: [ 'b' ] });
t.deepEqual(parse([ '--a', '--', 'b' ]), { a: true, _: [ 'b' ] });
});
var test = require('tape');
var parse = require('../');
test('boolean default true', function (t) {
var argv = parse([], {
boolean: 'sometrue',
default: { sometrue: true }
});
t.equal(argv.sometrue, true);
t.end();
});
test('boolean default false', function (t) {
var argv = parse([], {
boolean: 'somefalse',
default: { somefalse: false }
});
t.equal(argv.somefalse, false);
t.end();
});
var parse = require('../');
var test = require('tape');
test('dotted alias', function (t) {
var argv = parse(['--a.b', '22'], {default: {'a.b': 11}, alias: {'a.b': 'aa.bb'}});
t.equal(argv.a.b, 22);
t.equal(argv.aa.bb, 22);
t.end();
});
test('dotted default', function (t) {
var argv = parse('', {default: {'a.b': 11}, alias: {'a.b': 'aa.bb'}});
t.equal(argv.a.b, 11);
t.equal(argv.aa.bb, 11);
t.end();
});
var test = require('tape');
var parse = require('../');
test('long opts', function (t) {
t.deepEqual(
parse([ '--bool' ]),
{ bool : true, _ : [] },
'long boolean'
);
t.deepEqual(
parse([ '--pow', 'xixxle' ]),
{ pow : 'xixxle', _ : [] },
'long capture sp'
);
t.deepEqual(
parse([ '--pow=xixxle' ]),
{ pow : 'xixxle', _ : [] },
'long capture eq'
);
t.deepEqual(
parse([ '--host', 'localhost', '--port', '555' ]),
{ host : 'localhost', port : 555, _ : [] },
'long captures sp'
);
t.deepEqual(
parse([ '--host=localhost', '--port=555' ]),
{ host : 'localhost', port : 555, _ : [] },
'long captures eq'
);
t.end();
});
var parse = require('../');
var test = require('tape');
test('parse args', function (t) {
t.deepEqual(
parse([ '--no-moo' ]),
{ moo : false, _ : [] },
'no'
);
t.deepEqual(
parse([ '-v', 'a', '-v', 'b', '-v', 'c' ]),
{ v : ['a','b','c'], _ : [] },
'multi'
);
t.end();
});
test('comprehensive', function (t) {
t.deepEqual(
parse([
'--name=meowmers', 'bare', '-cats', 'woo',
'-h', 'awesome', '--multi=quux',
'--key', 'value',
'-b', '--bool', '--no-meep', '--multi=baz',
'--', '--not-a-flag', 'eek'
]),
{
c : true,
a : true,
t : true,
s : 'woo',
h : 'awesome',
b : true,
bool : true,
key : 'value',
multi : [ 'quux', 'baz' ],
meep : false,
name : 'meowmers',
_ : [ 'bare', '--not-a-flag', 'eek' ]
}
);
t.end();
});
test('nums', function (t) {
var argv = parse([
'-x', '1234',
'-y', '5.67',
'-z', '1e7',
'-w', '10f',
'--hex', '0xdeadbeef',
'789'
]);
t.deepEqual(argv, {
x : 1234,
y : 5.67,
z : 1e7,
w : '10f',
hex : 0xdeadbeef,
_ : [ 789 ]
});
t.deepEqual(typeof argv.x, 'number');
t.deepEqual(typeof argv.y, 'number');
t.deepEqual(typeof argv.z, 'number');
t.deepEqual(typeof argv.w, 'string');
t.deepEqual(typeof argv.hex, 'number');
t.deepEqual(typeof argv._[0], 'number');
t.end();
});
test('flag boolean', function (t) {
var argv = parse([ '-t', 'moo' ], { boolean: 't' });
t.deepEqual(argv, { t : true, _ : [ 'moo' ] });
t.deepEqual(typeof argv.t, 'boolean');
t.end();
});
test('flag boolean value', function (t) {
var argv = parse(['--verbose', 'false', 'moo', '-t', 'true'], {
boolean: [ 't', 'verbose' ],
default: { verbose: true }
});
t.deepEqual(argv, {
verbose: false,
t: true,
_: ['moo']
});
t.deepEqual(typeof argv.verbose, 'boolean');
t.deepEqual(typeof argv.t, 'boolean');
t.end();
});
test('flag boolean default false', function (t) {
var argv = parse(['moo'], {
boolean: ['t', 'verbose'],
default: { verbose: false, t: false }
});
t.deepEqual(argv, {
verbose: false,
t: false,
_: ['moo']
});
t.deepEqual(typeof argv.verbose, 'boolean');
t.deepEqual(typeof argv.t, 'boolean');
t.end();
});
test('boolean groups', function (t) {
var argv = parse([ '-x', '-z', 'one', 'two', 'three' ], {
boolean: ['x','y','z']
});
t.deepEqual(argv, {
x : true,
y : false,
z : true,
_ : [ 'one', 'two', 'three' ]
});
t.deepEqual(typeof argv.x, 'boolean');
t.deepEqual(typeof argv.y, 'boolean');
t.deepEqual(typeof argv.z, 'boolean');
t.end();
});
test('newlines in params' , function (t) {
var args = parse([ '-s', "X\nX" ])
t.deepEqual(args, { _ : [], s : "X\nX" });
// reproduce in bash:
// VALUE="new
// line"
// node program.js --s="$VALUE"
args = parse([ "--s=X\nX" ])
t.deepEqual(args, { _ : [], s : "X\nX" });
t.end();
});
test('strings' , function (t) {
var s = parse([ '-s', '0001234' ], { string: 's' }).s;
t.equal(s, '0001234');
t.equal(typeof s, 'string');
var x = parse([ '-x', '56' ], { string: 'x' }).x;
t.equal(x, '56');
t.equal(typeof x, 'string');
t.end();
});
test('stringArgs', function (t) {
var s = parse([ ' ', ' ' ], { string: '_' })._;
t.same(s.length, 2);
t.same(typeof s[0], 'string');
t.same(s[0], ' ');
t.same(typeof s[1], 'string');
t.same(s[1], ' ');
t.end();
});
test('empty strings', function(t) {
var s = parse([ '-s' ], { string: 's' }).s;
t.equal(s, '');
t.equal(typeof s, 'string');
var str = parse([ '--str' ], { string: 'str' }).str;
t.equal(str, '');
t.equal(typeof str, 'string');
var letters = parse([ '-art' ], {
string: [ 'a', 't' ]
});
t.equal(letters.a, '');
t.equal(letters.r, true);
t.equal(letters.t, '');
t.end();
});
test('slashBreak', function (t) {
t.same(
parse([ '-I/foo/bar/baz' ]),
{ I : '/foo/bar/baz', _ : [] }
);
t.same(
parse([ '-xyz/foo/bar/baz' ]),
{ x : true, y : true, z : '/foo/bar/baz', _ : [] }
);
t.end();
});
test('alias', function (t) {
var argv = parse([ '-f', '11', '--zoom', '55' ], {
alias: { z: 'zoom' }
});
t.equal(argv.zoom, 55);
t.equal(argv.z, argv.zoom);
t.equal(argv.f, 11);
t.end();
});
test('multiAlias', function (t) {
var argv = parse([ '-f', '11', '--zoom', '55' ], {
alias: { z: [ 'zm', 'zoom' ] }
});
t.equal(argv.zoom, 55);
t.equal(argv.z, argv.zoom);
t.equal(argv.z, argv.zm);
t.equal(argv.f, 11);
t.end();
});
test('nested dotted objects', function (t) {
var argv = parse([
'--foo.bar', '3', '--foo.baz', '4',
'--foo.quux.quibble', '5', '--foo.quux.o_O',
'--beep.boop'
]);
t.same(argv.foo, {
bar : 3,
baz : 4,
quux : {
quibble : 5,
o_O : true
}
});
t.same(argv.beep, { boop : true });
t.end();
});
test('boolean and alias with chainable api', function (t) {
var aliased = [ '-h', 'derp' ];
var regular = [ '--herp', 'derp' ];
var opts = {
herp: { alias: 'h', boolean: true }
};
var aliasedArgv = parse(aliased, {
boolean: 'herp',
alias: { h: 'herp' }
});
var propertyArgv = parse(regular, {
boolean: 'herp',
alias: { h: 'herp' }
});
var expected = {
herp: true,
h: true,
'_': [ 'derp' ]
};
t.same(aliasedArgv, expected);
t.same(propertyArgv, expected);
t.end();
});
test('boolean and alias with options hash', function (t) {
var aliased = [ '-h', 'derp' ];
var regular = [ '--herp', 'derp' ];
var opts = {
alias: { 'h': 'herp' },
boolean: 'herp'
};
var aliasedArgv = parse(aliased, opts);
var propertyArgv = parse(regular, opts);
var expected = {
herp: true,
h: true,
'_': [ 'derp' ]
};
t.same(aliasedArgv, expected);
t.same(propertyArgv, expected);
t.end();
});
test('boolean and alias using explicit true', function (t) {
var aliased = [ '-h', 'true' ];
var regular = [ '--herp', 'true' ];
var opts = {
alias: { h: 'herp' },
boolean: 'h'
};
var aliasedArgv = parse(aliased, opts);
var propertyArgv = parse(regular, opts);
var expected = {
herp: true,
h: true,
'_': [ ]
};
t.same(aliasedArgv, expected);
t.same(propertyArgv, expected);
t.end();
});
// regression, see https://github.com/substack/node-optimist/issues/71
test('boolean and --x=true', function(t) {
var parsed = parse(['--boool', '--other=true'], {
boolean: 'boool'
});
t.same(parsed.boool, true);
t.same(parsed.other, 'true');
parsed = parse(['--boool', '--other=false'], {
boolean: 'boool'
});
t.same(parsed.boool, true);
t.same(parsed.other, 'false');
t.end();
});
var parse = require('../');
var test = require('tape');
test('parse with modifier functions' , function (t) {
t.plan(1);
var argv = parse([ '-b', '123' ], { boolean: 'b' });
t.deepEqual(argv, { b: true, _: ['123'] });
});
var parse = require('../');
var test = require('tape');
test('numeric short args', function (t) {
t.plan(2);
t.deepEqual(parse([ '-n123' ]), { n: 123, _: [] });
t.deepEqual(
parse([ '-123', '456' ]),
{ 1: true, 2: true, 3: 456, _: [] }
);
});
test('short', function (t) {
t.deepEqual(
parse([ '-b' ]),
{ b : true, _ : [] },
'short boolean'
);
t.deepEqual(
parse([ 'foo', 'bar', 'baz' ]),
{ _ : [ 'foo', 'bar', 'baz' ] },
'bare'
);
t.deepEqual(
parse([ '-cats' ]),
{ c : true, a : true, t : true, s : true, _ : [] },
'group'
);
t.deepEqual(
parse([ '-cats', 'meow' ]),
{ c : true, a : true, t : true, s : 'meow', _ : [] },
'short group next'
);
t.deepEqual(
parse([ '-h', 'localhost' ]),
{ h : 'localhost', _ : [] },
'short capture'
);
t.deepEqual(
parse([ '-h', 'localhost', '-p', '555' ]),
{ h : 'localhost', p : 555, _ : [] },
'short captures'
);
t.end();
});
test('mixed short bool and capture', function (t) {
t.same(
parse([ '-h', 'localhost', '-fp', '555', 'script.js' ]),
{
f : true, p : 555, h : 'localhost',
_ : [ 'script.js' ]
}
);
t.end();
});
test('short and long', function (t) {
t.deepEqual(
parse([ '-h', 'localhost', '-fp', '555', 'script.js' ]),
{
f : true, p : 555, h : 'localhost',
_ : [ 'script.js' ]
}
);
t.end();
});
var parse = require('../');
var test = require('tape');
test('whitespace should be whitespace' , function (t) {
t.plan(1);
var x = parse([ '-x', '\t' ]).x;
t.equal(x, '\t');
});
language: node_js
node_js:
- "0.8"
- "0.10"
- "0.12"
- "iojs"
before_install:
- npm install -g npm@~1.4.6
Copyright 2010 James Halliday (mail@substack.net)
This project is free software released under the MIT/X11 license:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
#!/usr/bin/env node
var mkdirp = require('../');
var minimist = require('minimist');
var fs = require('fs');
var argv = minimist(process.argv.slice(2), {
alias: { m: 'mode', h: 'help' },
string: [ 'mode' ]
});
if (argv.help) {
fs.createReadStream(__dirname + '/usage.txt').pipe(process.stdout);
return;
}
var paths = argv._.slice();
var mode = argv.mode ? parseInt(argv.mode, 8) : undefined;
(function next () {
if (paths.length === 0) return;
var p = paths.shift();
if (mode === undefined) mkdirp(p, cb)
else mkdirp(p, mode, cb)
function cb (err) {
if (err) {
console.error(err.message);
process.exit(1);
}
else next();
}
})();
usage: mkdirp [DIR1,DIR2..] {OPTIONS}
Create each supplied directory including any necessary parent directories that
don't yet exist.
If the directory already exists, do nothing.
OPTIONS are:
-m, --mode If a directory needs to be created, set the mode as an octal
permission string.
var mkdirp = require('mkdirp');
mkdirp('/tmp/foo/bar/baz', function (err) {
if (err) console.error(err)
else console.log('pow!')
});
var path = require('path');
var fs = require('fs');
var _0777 = parseInt('0777', 8);
module.exports = mkdirP.mkdirp = mkdirP.mkdirP = mkdirP;
function mkdirP (p, opts, f, made) {
if (typeof opts === 'function') {
f = opts;
opts = {};
}
else if (!opts || typeof opts !== 'object') {
opts = { mode: opts };
}
var mode = opts.mode;
var xfs = opts.fs || fs;
if (mode === undefined) {
mode = _0777 & (~process.umask());
}
if (!made) made = null;
var cb = f || function () {};
p = path.resolve(p);
xfs.mkdir(p, mode, function (er) {
if (!er) {
made = made || p;
return cb(null, made);
}
switch (er.code) {
case 'ENOENT':
mkdirP(path.dirname(p), opts, function (er, made) {
if (er) cb(er, made);
else mkdirP(p, opts, cb, made);
});
break;
// In the case of any other error, just see if there's a dir
// there already. If so, then hooray! If not, then something
// is borked.
default:
xfs.stat(p, function (er2, stat) {
// if the stat fails, then that's super weird.
// let the original error be the failure reason.
if (er2 || !stat.isDirectory()) cb(er, made)
else cb(null, made);
});
break;
}
});
}
mkdirP.sync = function sync (p, opts, made) {
if (!opts || typeof opts !== 'object') {
opts = { mode: opts };
}
var mode = opts.mode;
var xfs = opts.fs || fs;
if (mode === undefined) {
mode = _0777 & (~process.umask());
}
if (!made) made = null;
p = path.resolve(p);
try {
xfs.mkdirSync(p, mode);
made = made || p;
}
catch (err0) {
switch (err0.code) {
case 'ENOENT' :
made = sync(path.dirname(p), opts, made);
sync(p, opts, made);
break;
// In the case of any other error, just see if there's a dir
// there already. If so, then hooray! If not, then something
// is borked.
default:
var stat;
try {
stat = xfs.statSync(p);
}
catch (err1) {
throw err0;
}
if (!stat.isDirectory()) throw err0;
break;
}
}
return made;
};
{
"_from": "mkdirp@~0.5.1",
"_id": "mkdirp@0.5.1",
"_inBundle": false,
"_integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"_location": "/mkdirp",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "mkdirp@~0.5.1",
"name": "mkdirp",
"escapedName": "mkdirp",
"rawSpec": "~0.5.1",
"saveSpec": null,
"fetchSpec": "~0.5.1"
},
"_requiredBy": [
"/youtube-dl"
],
"_resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"_shasum": "30057438eac6cf7f8c4767f38648d6697d75c903",
"_spec": "mkdirp@~0.5.1",
"_where": "C:\\Users\\user\\Desktop\\오소git\\오소플젝\\Youtube_MPL\\node_modules\\youtube-dl",
"author": {
"name": "James Halliday",
"email": "mail@substack.net",
"url": "http://substack.net"
},
"bin": {
"mkdirp": "bin/cmd.js"
},
"bugs": {
"url": "https://github.com/substack/node-mkdirp/issues"
},
"bundleDependencies": false,
"dependencies": {
"minimist": "0.0.8"
},
"deprecated": false,
"description": "Recursively mkdir, like `mkdir -p`",
"devDependencies": {
"mock-fs": "2 >=2.7.0",
"tap": "1"
},
"homepage": "https://github.com/substack/node-mkdirp#readme",
"keywords": [
"mkdir",
"directory"
],
"license": "MIT",
"main": "index.js",
"name": "mkdirp",
"repository": {
"type": "git",
"url": "git+https://github.com/substack/node-mkdirp.git"
},
"scripts": {
"test": "tap test/*.js"
},
"version": "0.5.1"
}
# mkdirp
Like `mkdir -p`, but in node.js!
[![build status](https://secure.travis-ci.org/substack/node-mkdirp.png)](http://travis-ci.org/substack/node-mkdirp)
# example
## pow.js
```js
var mkdirp = require('mkdirp');
mkdirp('/tmp/foo/bar/baz', function (err) {
if (err) console.error(err)
else console.log('pow!')
});
```
Output
```
pow!
```
And now /tmp/foo/bar/baz exists, huzzah!
# methods
```js
var mkdirp = require('mkdirp');
```
## mkdirp(dir, opts, cb)
Create a new directory and any necessary subdirectories at `dir` with octal
permission string `opts.mode`. If `opts` is a non-object, it will be treated as
the `opts.mode`.
If `opts.mode` isn't specified, it defaults to `0777 & (~process.umask())`.
`cb(err, made)` fires with the error or the first directory `made`
that had to be created, if any.
You can optionally pass in an alternate `fs` implementation by passing in
`opts.fs`. Your implementation should have `opts.fs.mkdir(path, mode, cb)` and
`opts.fs.stat(path, cb)`.
## mkdirp.sync(dir, opts)
Synchronously create a new directory and any necessary subdirectories at `dir`
with octal permission string `opts.mode`. If `opts` is a non-object, it will be
treated as the `opts.mode`.
If `opts.mode` isn't specified, it defaults to `0777 & (~process.umask())`.
Returns the first directory that had to be created, if any.
You can optionally pass in an alternate `fs` implementation by passing in
`opts.fs`. Your implementation should have `opts.fs.mkdirSync(path, mode)` and
`opts.fs.statSync(path)`.
# usage
This package also ships with a `mkdirp` command.
```
usage: mkdirp [DIR1,DIR2..] {OPTIONS}
Create each supplied directory including any necessary parent directories that
don't yet exist.
If the directory already exists, do nothing.
OPTIONS are:
-m, --mode If a directory needs to be created, set the mode as an octal
permission string.
```
# install
With [npm](http://npmjs.org) do:
```
npm install mkdirp
```
to get the library, or
```
npm install -g mkdirp
```
to get the command.
# license
MIT
var mkdirp = require('../').mkdirp;
var path = require('path');
var fs = require('fs');
var test = require('tap').test;
var _0777 = parseInt('0777', 8);
var _0755 = parseInt('0755', 8);
var _0744 = parseInt('0744', 8);
var ps = [ '', 'tmp' ];
for (var i = 0; i < 25; i++) {
var dir = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
ps.push(dir);
}
var file = ps.join('/');
test('chmod-pre', function (t) {
var mode = _0744
mkdirp(file, mode, function (er) {
t.ifError(er, 'should not error');
fs.stat(file, function (er, stat) {
t.ifError(er, 'should exist');
t.ok(stat && stat.isDirectory(), 'should be directory');
t.equal(stat && stat.mode & _0777, mode, 'should be 0744');
t.end();
});
});
});
test('chmod', function (t) {
var mode = _0755
mkdirp(file, mode, function (er) {
t.ifError(er, 'should not error');
fs.stat(file, function (er, stat) {
t.ifError(er, 'should exist');
t.ok(stat && stat.isDirectory(), 'should be directory');
t.end();
});
});
});
var mkdirp = require('../').mkdirp;
var path = require('path');
var fs = require('fs');
var test = require('tap').test;
var _0755 = parseInt('0755', 8);
var ps = [ '', 'tmp' ];
for (var i = 0; i < 25; i++) {
var dir = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
ps.push(dir);
}
var file = ps.join('/');
// a file in the way
var itw = ps.slice(0, 3).join('/');
test('clobber-pre', function (t) {
console.error("about to write to "+itw)
fs.writeFileSync(itw, 'I AM IN THE WAY, THE TRUTH, AND THE LIGHT.');
fs.stat(itw, function (er, stat) {
t.ifError(er)
t.ok(stat && stat.isFile(), 'should be file')
t.end()
})
})
test('clobber', function (t) {
t.plan(2);
mkdirp(file, _0755, function (err) {
t.ok(err);
t.equal(err.code, 'ENOTDIR');
t.end();
});
});
var mkdirp = require('../');
var path = require('path');
var fs = require('fs');
var exists = fs.exists || path.exists;
var test = require('tap').test;
var _0777 = parseInt('0777', 8);
var _0755 = parseInt('0755', 8);
test('woo', function (t) {
t.plan(5);
var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
var file = '/tmp/' + [x,y,z].join('/');
mkdirp(file, _0755, function (err) {
t.ifError(err);
exists(file, function (ex) {
t.ok(ex, 'file created');
fs.stat(file, function (err, stat) {
t.ifError(err);
t.equal(stat.mode & _0777, _0755);
t.ok(stat.isDirectory(), 'target not a directory');
})
})
});
});
var mkdirp = require('../');
var path = require('path');
var test = require('tap').test;
var mockfs = require('mock-fs');
var _0777 = parseInt('0777', 8);
var _0755 = parseInt('0755', 8);
test('opts.fs', function (t) {
t.plan(5);
var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
var file = '/beep/boop/' + [x,y,z].join('/');
var xfs = mockfs.fs();
mkdirp(file, { fs: xfs, mode: _0755 }, function (err) {
t.ifError(err);
xfs.exists(file, function (ex) {
t.ok(ex, 'created file');
xfs.stat(file, function (err, stat) {
t.ifError(err);
t.equal(stat.mode & _0777, _0755);
t.ok(stat.isDirectory(), 'target not a directory');
});
});
});
});
var mkdirp = require('../');
var path = require('path');
var test = require('tap').test;
var mockfs = require('mock-fs');
var _0777 = parseInt('0777', 8);
var _0755 = parseInt('0755', 8);
test('opts.fs sync', function (t) {
t.plan(4);
var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
var file = '/beep/boop/' + [x,y,z].join('/');
var xfs = mockfs.fs();
mkdirp.sync(file, { fs: xfs, mode: _0755 });
xfs.exists(file, function (ex) {
t.ok(ex, 'created file');
xfs.stat(file, function (err, stat) {
t.ifError(err);
t.equal(stat.mode & _0777, _0755);
t.ok(stat.isDirectory(), 'target not a directory');
});
});
});
var mkdirp = require('../');
var path = require('path');
var fs = require('fs');
var exists = fs.exists || path.exists;
var test = require('tap').test;
var _0777 = parseInt('0777', 8);
var _0755 = parseInt('0755', 8);
test('async perm', function (t) {
t.plan(5);
var file = '/tmp/' + (Math.random() * (1<<30)).toString(16);
mkdirp(file, _0755, function (err) {
t.ifError(err);
exists(file, function (ex) {
t.ok(ex, 'file created');
fs.stat(file, function (err, stat) {
t.ifError(err);
t.equal(stat.mode & _0777, _0755);
t.ok(stat.isDirectory(), 'target not a directory');
})
})
});
});
test('async root perm', function (t) {
mkdirp('/tmp', _0755, function (err) {
if (err) t.fail(err);
t.end();
});
t.end();
});
var mkdirp = require('../');
var path = require('path');
var fs = require('fs');
var exists = fs.exists || path.exists;
var test = require('tap').test;
var _0777 = parseInt('0777', 8);
var _0755 = parseInt('0755', 8);
test('sync perm', function (t) {
t.plan(4);
var file = '/tmp/' + (Math.random() * (1<<30)).toString(16) + '.json';
mkdirp.sync(file, _0755);
exists(file, function (ex) {
t.ok(ex, 'file created');
fs.stat(file, function (err, stat) {
t.ifError(err);
t.equal(stat.mode & _0777, _0755);
t.ok(stat.isDirectory(), 'target not a directory');
});
});
});
test('sync root perm', function (t) {
t.plan(3);
var file = '/tmp';
mkdirp.sync(file, _0755);
exists(file, function (ex) {
t.ok(ex, 'file created');
fs.stat(file, function (err, stat) {
t.ifError(err);
t.ok(stat.isDirectory(), 'target not a directory');
})
});
});
var mkdirp = require('../').mkdirp;
var path = require('path');
var fs = require('fs');
var exists = fs.exists || path.exists;
var test = require('tap').test;
var _0777 = parseInt('0777', 8);
var _0755 = parseInt('0755', 8);
test('race', function (t) {
t.plan(10);
var ps = [ '', 'tmp' ];
for (var i = 0; i < 25; i++) {
var dir = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
ps.push(dir);
}
var file = ps.join('/');
var res = 2;
mk(file);
mk(file);
function mk (file, cb) {
mkdirp(file, _0755, function (err) {
t.ifError(err);
exists(file, function (ex) {
t.ok(ex, 'file created');
fs.stat(file, function (err, stat) {
t.ifError(err);
t.equal(stat.mode & _0777, _0755);
t.ok(stat.isDirectory(), 'target not a directory');
});
})
});
}
});
var mkdirp = require('../');
var path = require('path');
var fs = require('fs');
var exists = fs.exists || path.exists;
var test = require('tap').test;
var _0777 = parseInt('0777', 8);
var _0755 = parseInt('0755', 8);
test('rel', function (t) {
t.plan(5);
var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
var cwd = process.cwd();
process.chdir('/tmp');
var file = [x,y,z].join('/');
mkdirp(file, _0755, function (err) {
t.ifError(err);
exists(file, function (ex) {
t.ok(ex, 'file created');
fs.stat(file, function (err, stat) {
t.ifError(err);
process.chdir(cwd);
t.equal(stat.mode & _0777, _0755);
t.ok(stat.isDirectory(), 'target not a directory');
})
})
});
});
var mkdirp = require('../');
var path = require('path');
var fs = require('fs');
var test = require('tap').test;
test('return value', function (t) {
t.plan(4);
var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
var file = '/tmp/' + [x,y,z].join('/');
// should return the first dir created.
// By this point, it would be profoundly surprising if /tmp didn't
// already exist, since every other test makes things in there.
mkdirp(file, function (err, made) {
t.ifError(err);
t.equal(made, '/tmp/' + x);
mkdirp(file, function (err, made) {
t.ifError(err);
t.equal(made, null);
});
});
});
var mkdirp = require('../');
var path = require('path');
var fs = require('fs');
var test = require('tap').test;
test('return value', function (t) {
t.plan(2);
var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
var file = '/tmp/' + [x,y,z].join('/');
// should return the first dir created.
// By this point, it would be profoundly surprising if /tmp didn't
// already exist, since every other test makes things in there.
// Note that this will throw on failure, which will fail the test.
var made = mkdirp.sync(file);
t.equal(made, '/tmp/' + x);
// making the same file again should have no effect.
made = mkdirp.sync(file);
t.equal(made, null);
});
var mkdirp = require('../');
var path = require('path');
var fs = require('fs');
var test = require('tap').test;
var _0755 = parseInt('0755', 8);
test('root', function (t) {
// '/' on unix, 'c:/' on windows.
var file = path.resolve('/');
mkdirp(file, _0755, function (err) {
if (err) throw err
fs.stat(file, function (er, stat) {
if (er) throw er
t.ok(stat.isDirectory(), 'target is a directory');
t.end();
})
});
});
var mkdirp = require('../');
var path = require('path');
var fs = require('fs');
var exists = fs.exists || path.exists;
var test = require('tap').test;
var _0777 = parseInt('0777', 8);
var _0755 = parseInt('0755', 8);
test('sync', function (t) {
t.plan(4);
var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
var file = '/tmp/' + [x,y,z].join('/');
try {
mkdirp.sync(file, _0755);
} catch (err) {
t.fail(err);
return t.end();
}
exists(file, function (ex) {
t.ok(ex, 'file created');
fs.stat(file, function (err, stat) {
t.ifError(err);
t.equal(stat.mode & _0777, _0755);
t.ok(stat.isDirectory(), 'target not a directory');
});
});
});
var mkdirp = require('../');
var path = require('path');
var fs = require('fs');
var exists = fs.exists || path.exists;
var test = require('tap').test;
var _0777 = parseInt('0777', 8);
var _0755 = parseInt('0755', 8);
test('implicit mode from umask', function (t) {
t.plan(5);
var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
var file = '/tmp/' + [x,y,z].join('/');
mkdirp(file, function (err) {
t.ifError(err);
exists(file, function (ex) {
t.ok(ex, 'file created');
fs.stat(file, function (err, stat) {
t.ifError(err);
t.equal(stat.mode & _0777, _0777 & (~process.umask()));
t.ok(stat.isDirectory(), 'target not a directory');
});
})
});
});
var mkdirp = require('../');
var path = require('path');
var fs = require('fs');
var exists = fs.exists || path.exists;
var test = require('tap').test;
var _0777 = parseInt('0777', 8);
var _0755 = parseInt('0755', 8);
test('umask sync modes', function (t) {
t.plan(4);
var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
var file = '/tmp/' + [x,y,z].join('/');
try {
mkdirp.sync(file);
} catch (err) {
t.fail(err);
return t.end();
}
exists(file, function (ex) {
t.ok(ex, 'file created');
fs.stat(file, function (err, stat) {
t.ifError(err);
t.equal(stat.mode & _0777, (_0777 & (~process.umask())));
t.ok(stat.isDirectory(), 'target not a directory');
});
});
});
Copyright (C) 2012 by Roly Fentanes
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
# node-streamify
Streamify helps you easily provide a streaming interface for your code.
[![Build Status](https://secure.travis-ci.org/fent/node-streamify.svg)](http://travis-ci.org/fent/node-streamify)
[![Dependency Status](https://david-dm.org/fent/node-streamify.svg)](https://david-dm.org/fent/node-streamify)
[![codecov](https://codecov.io/gh/fent/node-streamify/branch/master/graph/badge.svg)](https://codecov.io/gh/fent/node-streamify)
# Usage
```js
var streamify = require('streamify');
var request = require('request');
exports.doSomething = function doSomething() {
var stream = streamify();
request(url1, function(err, res, body) {
// do something with `body`
// once the actual stream you want to return is ready,
// call `stream.resolve()`
stream.resolve(request(url2));
});
// your function can return back a stream!!
return stream;
}
// because `doSomething()` returns a stream, it can be piped
exports.doSomething().pipe(anotherStream);
```
# API
### streamify([options])
Returns an instance of a stream. `options` can be
* `superCtor` - The object from which it inherits. Defaults to `require('stream').Stream`. Sometimes you may want to use this if your stream might be checked with the `instanceof` operator against objects such as `http.ServerResponse`.
* `readable` - Defaults to `true`.
* `writable` - Defaults to `true`.
### Stream#resolve(stream)
Must be called only once when the actual stream you are proxying to becomes available after an asynchronous operation.
### Stream#unresolve()
Can be used to unbind a a resolved stream to later call `resolve()` again.
### Stream#addSource(stream)
Add a source readable stream.
### Stream#removeSource()
Remove previously added source stream.
### Stream#addDest(stream)
Add a destination writable stream.
### Stream#removeDest()
Remove a previously added destination stream.
# Install
npm install streamify
# Tests
Tests are written with [mocha](https://mochajs.org)
```bash
npm test
```
# License
MIT
var Readable = require('stream').Readable;
var Writable = require('stream').Writable;
var Duplex = require('stream').Duplex;
var hashish = require('hashish');
/**
* Proxy some events from underlying readable and writable streams.
*/
var SOURCE_EVENTS = ['error', 'close'];
var DEST_EVENTS = ['drain', 'close'];
/**
* Creates property to use with `Object.create()`
*
* @param {Object} value
* @return {Object}
*/
function prop(value) {
return {
writable: true,
enumerable: true,
configurable: true,
value: value
};
}
/**
* @constructor
* @param {Object} options
* {Object} superCtor
* {Boolean} readable
* {Boolean} writable
* @return {Duplex}
*/
var Streamify = module.exports = function Streamify(options) {
options = options || {};
options.readable = typeof options.readable !== 'undefined' ?
options.readable : true;
options.writable = typeof options.writable !== 'undefined' ?
options.writable : true;
var superCtor = getConstructor(options);
// Add `Streamify.prototype` methods.
var properties = hashish.map(Streamify.prototype, prop);
var o = Object.create(superCtor.prototype, properties);
superCtor.call(o);
o.readable = options.readable;
o.writable = options.writable;
o.__options = options;
o._onevent = function onevent() {
};
o._destWritten = [];
if (options.writable) {
o.once('finish', function() {
if (o._dest) {
o._dest.stream.end();
}
});
}
return o;
};
/**
* Required implementation by streaming API.
*
* @param {Number} size
*/
Streamify.prototype._read = function(size) {
if (this._source) {
var self = this;
var onreadable = this._source.onreadable = function onreadable() {
if (!self._source) { return; }
var data = self._source.stream.read(size);
if (data) {
self.push(data);
} else {
self._source.stream.once('readable', onreadable);
}
};
onreadable();
} else {
this._sourceRead = size;
}
};
/**
* Required implementation by streaming API.
*
* @param {Buffer|String} chunk
* @param {!String} encoding
* @param {Function(!Error)} callback
*/
Streamify.prototype._write = function(chunk, encoding, callback) {
if (this._dest) {
this._dest.stream.write(chunk, encoding, callback);
} else {
this._destWritten.push(arguments);
}
};
/**
* Add a stream to be the readable stream source.
*
* @param {Readable|Stream} stream
*/
Streamify.prototype.addSource = function(stream) {
if (this._source) {
throw Error('A source stream has already been added.');
}
stream = getReadable(stream);
this._source = { stream: stream, listeners: {}, onend: onend };
var self = this;
SOURCE_EVENTS.forEach(function(event) {
var onevent = self._source.listeners[event] = function onevent() {
var args = Array.prototype.slice.call(arguments);
self.emit.apply(self, [event].concat(args));
};
stream.on(event, onevent);
});
// Listen for `end` event to signal for end of data.
function onend() {
self.push(null);
}
stream.on('end', onend);
// Check if `Readable#_read()` has already been called.
this._read(this._sourceRead);
};
/**
* Remove a stream from being the source.
*/
Streamify.prototype.removeSource = function() {
if (!this._source) {
throw Error('A source stream has not been added.');
}
var source = this._source;
SOURCE_EVENTS.forEach(function(event) {
source.stream.removeListener(event, source.listeners[event]);
});
source.stream.removeListener('readable', source.onreadable);
source.stream.removeListener('end', source.onend);
delete this._source;
};
/**
* Add a stream to be the writable stream destination.
*
* @param {Writable|Stream} stream
*/
Streamify.prototype.addDest = function(stream) {
if (this._dest) {
throw Error('A destination stream has already been added.');
}
this._dest = { stream: stream, listeners: {} };
var self = this;
DEST_EVENTS.forEach(function(event) {
var onevent = self._dest.listeners[event] = function onevent() {
var args = Array.prototype.slice.call(arguments);
self.emit.apply(self, [event].concat(args));
};
stream.on(event, onevent);
});
if (this._destWritten.length) {
this._destWritten.forEach(function(args) {
stream.write.apply(stream, args);
});
}
};
/**
* Remove a stream from being the destination.
*/
Streamify.prototype.removeDest = function() {
if (!this._dest) {
throw Error('A destination stream has not been added.');
}
var dest = this._dest;
DEST_EVENTS.forEach(function(event) {
dest.stream.removeListener(event, dest.listeners[event]);
});
delete this._dest;
this._destWritten = [];
};
/**
* Begins fueling data from actual stream into Streamify instance.
*
* @param {Readable|Writable|Duplex|Stream} stream
*/
Streamify.prototype.resolve = function(stream) {
if (this.__options.readable && stream.readable) {
this.addSource(stream);
}
if (this.__options.writable && stream.writable) {
this.addDest(stream);
}
};
/**
* Removes a stream from this, possibly because another is replacing it.
*/
Streamify.prototype.unresolve = function() {
if (this._source) {
this.removeSource();
}
if (this._dest) {
this.removeDest();
}
};
/**
* Returns a readable new stream API stream if the stream is using the
* old API. Otherwise it returns the same stream.
*
* @param {Readable|Stream} stream
* @return {Readable}
*/
function getReadable(stream) {
if (isOldStyleStream(stream)) {
var readable = new Readable();
readable.wrap(stream);
return readable;
} else {
return stream;
}
}
/**
* Returns true if a stream is an old style API stream.
*
* @param {Readable|Stream} stream
* @return {Boolean}
*/
function isOldStyleStream(stream) {
return typeof stream.read !== 'function' ||
typeof stream._read !== 'function' ||
typeof stream.push !== 'function' ||
typeof stream.unshift !== 'function' ||
typeof stream.wrap !== 'function';
}
function getConstructor (options) {
var superCtor = Duplex;
if (options.readable && !options.writable) {
superCtor = Readable;
}
if (options.writable && !options.readable) {
superCtor = Writable;
}
return superCtor;
}
\ No newline at end of file
{
"_from": "streamify@~0.2.9",
"_id": "streamify@0.2.9",
"_inBundle": false,
"_integrity": "sha512-8pUxeLEef9UO1FxtTt5iikAiyzGI4SZRnGuJ3sz8axZ5Xk+/7ezEV5kuJQsMEFxw7AKYw3xp0Ow+20mmSaJbQQ==",
"_location": "/streamify",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "streamify@~0.2.9",
"name": "streamify",
"escapedName": "streamify",
"rawSpec": "~0.2.9",
"saveSpec": null,
"fetchSpec": "~0.2.9"
},
"_requiredBy": [
"/youtube-dl"
],
"_resolved": "https://registry.npmjs.org/streamify/-/streamify-0.2.9.tgz",
"_shasum": "8938b14db491e2b6be4f8d99cc4133c9f0384f0b",
"_spec": "streamify@~0.2.9",
"_where": "C:\\Users\\user\\Desktop\\오소git\\오소플젝\\Youtube_MPL\\node_modules\\youtube-dl",
"author": {
"name": "Roly Fentanes",
"url": "https://github.com/fent"
},
"bugs": {
"url": "https://github.com/fent/node-streamify/issues"
},
"bundleDependencies": false,
"dependencies": {
"hashish": "~0.0.4"
},
"deprecated": false,
"description": "Streamify helps you easily provide a streaming interface for code.",
"devDependencies": {
"istanbul": "*",
"mocha": "*",
"stream-equal": "~1.0.0"
},
"directories": {
"lib": "./lib"
},
"engines": {
"node": ">=0.12"
},
"files": [
"lib"
],
"homepage": "https://github.com/fent/node-streamify#readme",
"keywords": [
"stream",
"input",
"output",
"api"
],
"license": "MIT",
"main": "./lib/index.js",
"name": "streamify",
"repository": {
"type": "git",
"url": "git://github.com/fent/node-streamify.git"
},
"scripts": {
"test": "istanbul cover node_modules/.bin/_mocha -- test/*-test.js"
},
"version": "0.2.9"
}
language: node_js
node_js:
- 0.6
Copyright 2010 James Halliday (mail@substack.net)
This project is free software released under the MIT/X11 license:
http://www.opensource.org/licenses/mit-license.php
Copyright 2010 James Halliday (mail@substack.net)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
var traverse = require('traverse');
var id = 54;
var callbacks = {};
var obj = { moo : function () {}, foo : [2,3,4, function () {}] };
var scrubbed = traverse(obj).map(function (x) {
if (typeof x === 'function') {
callbacks[id] = { id : id, f : x, path : this.path };
this.update('[Function]');
id++;
}
});
console.dir(scrubbed);
console.dir(callbacks);
var traverse = require('traverse');
var obj = {
a : [1,2,3],
b : 4,
c : [5,6],
d : { e : [7,8], f : 9 },
};
var leaves = traverse(obj).reduce(function (acc, x) {
if (this.isLeaf) acc.push(x);
return acc;
}, []);
console.dir(leaves);
var traverse = require('traverse');
var obj = [ 5, 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ];
traverse(obj).forEach(function (x) {
if (x < 0) this.update(x + 128);
});
console.dir(obj);
// scrub out circular references
var traverse = require('traverse');
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
obj.c.push(obj);
var scrubbed = traverse(obj).map(function (x) {
if (this.circular) this.remove()
});
console.dir(scrubbed);
#!/usr/bin/env node
var traverse = require('traverse');
var obj = [ 'five', 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ];
var s = '';
traverse(obj).forEach(function to_s (node) {
if (Array.isArray(node)) {
this.before(function () { s += '[' });
this.post(function (child) {
if (!child.isLast) s += ',';
});
this.after(function () { s += ']' });
}
else if (typeof node == 'object') {
this.before(function () { s += '{' });
this.pre(function (x, key) {
to_s(key);
s += ':';
});
this.post(function (child) {
if (!child.isLast) s += ',';
});
this.after(function () { s += '}' });
}
else if (typeof node == 'string') {
s += '"' + node.toString().replace(/"/g, '\\"') + '"';
}
else if (typeof node == 'function') {
s += 'null';
}
else {
s += node.toString();
}
});
console.log('JSON.stringify: ' + JSON.stringify(obj));
console.log('this stringify: ' + s);
var traverse = module.exports = function (obj) {
return new Traverse(obj);
};
function Traverse (obj) {
this.value = obj;
}
Traverse.prototype.get = function (ps) {
var node = this.value;
for (var i = 0; i < ps.length; i ++) {
var key = ps[i];
if (!node || !hasOwnProperty.call(node, key)) {
node = undefined;
break;
}
node = node[key];
}
return node;
};
Traverse.prototype.has = function (ps) {
var node = this.value;
for (var i = 0; i < ps.length; i ++) {
var key = ps[i];
if (!node || !hasOwnProperty.call(node, key)) {
return false;
}
node = node[key];
}
return true;
};
Traverse.prototype.set = function (ps, value) {
var node = this.value;
for (var i = 0; i < ps.length - 1; i ++) {
var key = ps[i];
if (!hasOwnProperty.call(node, key)) node[key] = {};
node = node[key];
}
node[ps[i]] = value;
return value;
};
Traverse.prototype.map = function (cb) {
return walk(this.value, cb, true);
};
Traverse.prototype.forEach = function (cb) {
this.value = walk(this.value, cb, false);
return this.value;
};
Traverse.prototype.reduce = function (cb, init) {
var skip = arguments.length === 1;
var acc = skip ? this.value : init;
this.forEach(function (x) {
if (!this.isRoot || !skip) {
acc = cb.call(this, acc, x);
}
});
return acc;
};
Traverse.prototype.paths = function () {
var acc = [];
this.forEach(function (x) {
acc.push(this.path);
});
return acc;
};
Traverse.prototype.nodes = function () {
var acc = [];
this.forEach(function (x) {
acc.push(this.node);
});
return acc;
};
Traverse.prototype.clone = function () {
var parents = [], nodes = [];
return (function clone (src) {
for (var i = 0; i < parents.length; i++) {
if (parents[i] === src) {
return nodes[i];
}
}
if (typeof src === 'object' && src !== null) {
var dst = copy(src);
parents.push(src);
nodes.push(dst);
forEach(objectKeys(src), function (key) {
dst[key] = clone(src[key]);
});
parents.pop();
nodes.pop();
return dst;
}
else {
return src;
}
})(this.value);
};
function walk (root, cb, immutable) {
var path = [];
var parents = [];
var alive = true;
return (function walker (node_) {
var node = immutable ? copy(node_) : node_;
var modifiers = {};
var keepGoing = true;
var state = {
node : node,
node_ : node_,
path : [].concat(path),
parent : parents[parents.length - 1],
parents : parents,
key : path.slice(-1)[0],
isRoot : path.length === 0,
level : path.length,
circular : null,
update : function (x, stopHere) {
if (!state.isRoot) {
state.parent.node[state.key] = x;
}
state.node = x;
if (stopHere) keepGoing = false;
},
'delete' : function (stopHere) {
delete state.parent.node[state.key];
if (stopHere) keepGoing = false;
},
remove : function (stopHere) {
if (isArray(state.parent.node)) {
state.parent.node.splice(state.key, 1);
}
else {
delete state.parent.node[state.key];
}
if (stopHere) keepGoing = false;
},
keys : null,
before : function (f) { modifiers.before = f },
after : function (f) { modifiers.after = f },
pre : function (f) { modifiers.pre = f },
post : function (f) { modifiers.post = f },
stop : function () { alive = false },
block : function () { keepGoing = false }
};
if (!alive) return state;
function updateState() {
if (typeof state.node === 'object' && state.node !== null) {
if (!state.keys || state.node_ !== state.node) {
state.keys = objectKeys(state.node)
}
state.isLeaf = state.keys.length == 0;
for (var i = 0; i < parents.length; i++) {
if (parents[i].node_ === node_) {
state.circular = parents[i];
break;
}
}
}
else {
state.isLeaf = true;
state.keys = null;
}
state.notLeaf = !state.isLeaf;
state.notRoot = !state.isRoot;
}
updateState();
// use return values to update if defined
var ret = cb.call(state, state.node);
if (ret !== undefined && state.update) state.update(ret);
if (modifiers.before) modifiers.before.call(state, state.node);
if (!keepGoing) return state;
if (typeof state.node == 'object'
&& state.node !== null && !state.circular) {
parents.push(state);
updateState();
forEach(state.keys, function (key, i) {
path.push(key);
if (modifiers.pre) modifiers.pre.call(state, state.node[key], key);
var child = walker(state.node[key]);
if (immutable && hasOwnProperty.call(state.node, key)) {
state.node[key] = child.node;
}
child.isLast = i == state.keys.length - 1;
child.isFirst = i == 0;
if (modifiers.post) modifiers.post.call(state, child);
path.pop();
});
parents.pop();
}
if (modifiers.after) modifiers.after.call(state, state.node);
return state;
})(root).node;
}
function copy (src) {
if (typeof src === 'object' && src !== null) {
var dst;
if (isArray(src)) {
dst = [];
}
else if (isDate(src)) {
dst = new Date(src.getTime ? src.getTime() : src);
}
else if (isRegExp(src)) {
dst = new RegExp(src);
}
else if (isError(src)) {
dst = { message: src.message };
}
else if (isBoolean(src)) {
dst = new Boolean(src);
}
else if (isNumber(src)) {
dst = new Number(src);
}
else if (isString(src)) {
dst = new String(src);
}
else if (Object.create && Object.getPrototypeOf) {
dst = Object.create(Object.getPrototypeOf(src));
}
else if (src.constructor === Object) {
dst = {};
}
else {
var proto =
(src.constructor && src.constructor.prototype)
|| src.__proto__
|| {}
;
var T = function () {};
T.prototype = proto;
dst = new T;
}
forEach(objectKeys(src), function (key) {
dst[key] = src[key];
});
return dst;
}
else return src;
}
var objectKeys = Object.keys || function keys (obj) {
var res = [];
for (var key in obj) res.push(key)
return res;
};
function toS (obj) { return Object.prototype.toString.call(obj) }
function isDate (obj) { return toS(obj) === '[object Date]' }
function isRegExp (obj) { return toS(obj) === '[object RegExp]' }
function isError (obj) { return toS(obj) === '[object Error]' }
function isBoolean (obj) { return toS(obj) === '[object Boolean]' }
function isNumber (obj) { return toS(obj) === '[object Number]' }
function isString (obj) { return toS(obj) === '[object String]' }
var isArray = Array.isArray || function isArray (xs) {
return Object.prototype.toString.call(xs) === '[object Array]';
};
var forEach = function (xs, fn) {
if (xs.forEach) return xs.forEach(fn)
else for (var i = 0; i < xs.length; i++) {
fn(xs[i], i, xs);
}
};
forEach(objectKeys(Traverse.prototype), function (key) {
traverse[key] = function (obj) {
var args = [].slice.call(arguments, 1);
var t = new Traverse(obj);
return t[key].apply(t, args);
};
});
var hasOwnProperty = Object.hasOwnProperty || function (obj, key) {
return key in obj;
};
{
"_from": "traverse@>=0.2.4",
"_id": "traverse@0.6.6",
"_inBundle": false,
"_integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=",
"_location": "/traverse",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "traverse@>=0.2.4",
"name": "traverse",
"escapedName": "traverse",
"rawSpec": ">=0.2.4",
"saveSpec": null,
"fetchSpec": ">=0.2.4"
},
"_requiredBy": [
"/hashish"
],
"_resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz",
"_shasum": "cbdf560fd7b9af632502fed40f918c157ea97137",
"_spec": "traverse@>=0.2.4",
"_where": "C:\\Users\\user\\Desktop\\오소git\\오소플젝\\Youtube_MPL\\node_modules\\hashish",
"author": {
"name": "James Halliday",
"email": "mail@substack.net",
"url": "http://substack.net"
},
"bugs": {
"url": "https://github.com/substack/js-traverse/issues"
},
"bundleDependencies": false,
"deprecated": false,
"description": "traverse and transform objects by visiting every node on a recursive walk",
"devDependencies": {
"tape": "~1.0.4"
},
"directories": {
"example": "example",
"test": "test"
},
"homepage": "https://github.com/substack/js-traverse",
"keywords": [
"traverse",
"walk",
"recursive",
"map",
"forEach",
"deep",
"clone"
],
"license": "MIT",
"main": "index.js",
"name": "traverse",
"repository": {
"type": "git",
"url": "git://github.com/substack/js-traverse.git"
},
"scripts": {
"test": "tape test/*.js"
},
"testling": {
"files": "test/*.js",
"browsers": {
"iexplore": [
"6.0",
"7.0",
"8.0",
"9.0"
],
"chrome": [
"10.0",
"20.0"
],
"firefox": [
"10.0",
"15.0"
],
"safari": [
"5.1"
],
"opera": [
"12.0"
]
}
},
"version": "0.6.6"
}
# traverse
Traverse and transform objects by visiting every node on a recursive walk.
[![browser support](http://ci.testling.com/substack/js-traverse.png)](http://ci.testling.com/substack/js-traverse)
[![build status](https://secure.travis-ci.org/substack/js-traverse.png)](http://travis-ci.org/substack/js-traverse)
# examples
## transform negative numbers in-place
negative.js
````javascript
var traverse = require('traverse');
var obj = [ 5, 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ];
traverse(obj).forEach(function (x) {
if (x < 0) this.update(x + 128);
});
console.dir(obj);
````
Output:
[ 5, 6, 125, [ 7, 8, 126, 1 ], { f: 10, g: 115 } ]
## collect leaf nodes
leaves.js
````javascript
var traverse = require('traverse');
var obj = {
a : [1,2,3],
b : 4,
c : [5,6],
d : { e : [7,8], f : 9 },
};
var leaves = traverse(obj).reduce(function (acc, x) {
if (this.isLeaf) acc.push(x);
return acc;
}, []);
console.dir(leaves);
````
Output:
[ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
## scrub circular references
scrub.js:
````javascript
var traverse = require('traverse');
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
obj.c.push(obj);
var scrubbed = traverse(obj).map(function (x) {
if (this.circular) this.remove()
});
console.dir(scrubbed);
````
output:
{ a: 1, b: 2, c: [ 3, 4 ] }
# methods
Each method that takes an `fn` uses the context documented below in the context
section.
## .map(fn)
Execute `fn` for each node in the object and return a new object with the
results of the walk. To update nodes in the result use `this.update(value)`.
## .forEach(fn)
Execute `fn` for each node in the object but unlike `.map()`, when
`this.update()` is called it updates the object in-place.
## .reduce(fn, acc)
For each node in the object, perform a
[left-fold](http://en.wikipedia.org/wiki/Fold_(higher-order_function))
with the return value of `fn(acc, node)`.
If `acc` isn't specified, `acc` is set to the root object for the first step
and the root element is skipped.
## .paths()
Return an `Array` of every possible non-cyclic path in the object.
Paths are `Array`s of string keys.
## .nodes()
Return an `Array` of every node in the object.
## .clone()
Create a deep clone of the object.
## .get(path)
Get the element at the array `path`.
## .set(path, value)
Set the element at the array `path` to `value`.
## .has(path)
Return whether the element at the array `path` exists.
# context
Each method that takes a callback has a context (its `this` object) with these
attributes:
## this.node
The present node on the recursive walk
## this.path
An array of string keys from the root to the present node
## this.parent
The context of the node's parent.
This is `undefined` for the root node.
## this.key
The name of the key of the present node in its parent.
This is `undefined` for the root node.
## this.isRoot, this.notRoot
Whether the present node is the root node
## this.isLeaf, this.notLeaf
Whether or not the present node is a leaf node (has no children)
## this.level
Depth of the node within the traversal
## this.circular
If the node equals one of its parents, the `circular` attribute is set to the
context of that parent and the traversal progresses no deeper.
## this.update(value, stopHere=false)
Set a new value for the present node.
All the elements in `value` will be recursively traversed unless `stopHere` is
true.
## this.remove(stopHere=false)
Remove the current element from the output. If the node is in an Array it will
be spliced off. Otherwise it will be deleted from its parent.
## this.delete(stopHere=false)
Delete the current element from its parent in the output. Calls `delete` even on
Arrays.
## this.before(fn)
Call this function before any of the children are traversed.
You can assign into `this.keys` here to traverse in a custom order.
## this.after(fn)
Call this function after any of the children are traversed.
## this.pre(fn)
Call this function before each of the children are traversed.
## this.post(fn)
Call this function after each of the children are traversed.
# install
Using [npm](http://npmjs.org) do:
$ npm install traverse
# license
MIT
var test = require('tape');
var traverse = require('../');
var deepEqual = require('./lib/deep_equal');
var util = require('util');
test('circular', function (t) {
t.plan(1);
var obj = { x : 3 };
obj.y = obj;
traverse(obj).forEach(function (x) {
if (this.path.join('') == 'y') {
t.equal(
util.inspect(this.circular.node),
util.inspect(obj)
);
}
});
});
test('deepCirc', function (t) {
t.plan(2);
var obj = { x : [ 1, 2, 3 ], y : [ 4, 5 ] };
obj.y[2] = obj;
var times = 0;
traverse(obj).forEach(function (x) {
if (this.circular) {
t.same(this.circular.path, []);
t.same(this.path, [ 'y', 2 ]);
}
});
});
test('doubleCirc', function (t) {
var obj = { x : [ 1, 2, 3 ], y : [ 4, 5 ] };
obj.y[2] = obj;
obj.x.push(obj.y);
var circs = [];
traverse(obj).forEach(function (x) {
if (this.circular) {
circs.push({ circ : this.circular, self : this, node : x });
}
});
t.same(circs[0].self.path, [ 'x', 3, 2 ]);
t.same(circs[0].circ.path, []);
t.same(circs[1].self.path, [ 'y', 2 ]);
t.same(circs[1].circ.path, []);
t.same(circs.length, 2);
t.end();
});
test('circDubForEach', function (t) {
var obj = { x : [ 1, 2, 3 ], y : [ 4, 5 ] };
obj.y[2] = obj;
obj.x.push(obj.y);
traverse(obj).forEach(function (x) {
if (this.circular) this.update('...');
});
t.same(obj, { x : [ 1, 2, 3, [ 4, 5, '...' ] ], y : [ 4, 5, '...' ] });
t.end();
});
test('circDubMap', function (t) {
var obj = { x : [ 1, 2, 3 ], y : [ 4, 5 ] };
obj.y[2] = obj;
obj.x.push(obj.y);
var c = traverse(obj).map(function (x) {
if (this.circular) {
this.update('...');
}
});
t.same(c, { x : [ 1, 2, 3, [ 4, 5, '...' ] ], y : [ 4, 5, '...' ] });
t.end();
});
test('circClone', function (t) {
var obj = { x : [ 1, 2, 3 ], y : [ 4, 5 ] };
obj.y[2] = obj;
obj.x.push(obj.y);
var clone = traverse.clone(obj);
t.ok(obj !== clone);
t.ok(clone.y[2] === clone);
t.ok(clone.y[2] !== obj);
t.ok(clone.x[3][2] === clone);
t.ok(clone.x[3][2] !== obj);
t.same(clone.x.slice(0,3), [1,2,3]);
t.same(clone.y.slice(0,2), [4,5]);
t.end();
});
test('circMapScrub', function (t) {
var obj = { a : 1, b : 2 };
obj.c = obj;
var scrubbed = traverse(obj).map(function (node) {
if (this.circular) this.remove();
});
t.same(
Object.keys(scrubbed).sort(),
[ 'a', 'b' ]
);
t.ok(deepEqual(scrubbed, { a : 1, b : 2 }));
t.equal(obj.c, obj);
t.end();
});
var test = require('tape');
var traverse = require('../');
test('dateEach', function (t) {
var obj = { x : new Date, y : 10, z : 5 };
var counts = {};
traverse(obj).forEach(function (node) {
var t = (node instanceof Date && 'Date') || typeof node;
counts[t] = (counts[t] || 0) + 1;
});
t.same(counts, {
object : 1,
Date : 1,
number : 2,
});
t.end();
});
test('dateMap', function (t) {
var obj = { x : new Date, y : 10, z : 5 };
var res = traverse(obj).map(function (node) {
if (typeof node === 'number') this.update(node + 100);
});
t.ok(obj.x !== res.x);
t.same(res, {
x : obj.x,
y : 110,
z : 105,
});
t.end();
});
var test = require('tape');
var traverse = require('../');
var deepEqual = require('./lib/deep_equal');
test('deepDates', function (t) {
t.plan(2);
t.ok(
deepEqual(
{ d : new Date, x : [ 1, 2, 3 ] },
{ d : new Date, x : [ 1, 2, 3 ] }
),
'dates should be equal'
);
var d0 = new Date;
setTimeout(function () {
t.ok(
!deepEqual(
{ d : d0, x : [ 1, 2, 3 ], },
{ d : new Date, x : [ 1, 2, 3 ] }
),
'microseconds should count in date equality'
);
}, 5);
});
test('deepCircular', function (t) {
var a = [1];
a.push(a); // a = [ 1, *a ]
var b = [1];
b.push(a); // b = [ 1, [ 1, *a ] ]
t.ok(
!deepEqual(a, b),
'circular ref mount points count towards equality'
);
var c = [1];
c.push(c); // c = [ 1, *c ]
t.ok(
deepEqual(a, c),
'circular refs are structurally the same here'
);
var d = [1];
d.push(a); // c = [ 1, [ 1, *d ] ]
t.ok(
deepEqual(b, d),
'non-root circular ref structural comparison'
);
t.end();
});
test('deepInstances', function (t) {
t.ok(
!deepEqual([ new Boolean(false) ], [ false ]),
'boolean instances are not real booleans'
);
t.ok(
!deepEqual([ new String('x') ], [ 'x' ]),
'string instances are not real strings'
);
t.ok(
!deepEqual([ new Number(4) ], [ 4 ]),
'number instances are not real numbers'
);
t.ok(
deepEqual([ new RegExp('x') ], [ /x/ ]),
'regexp instances are real regexps'
);
t.ok(
!deepEqual([ new RegExp(/./) ], [ /../ ]),
'these regexps aren\'t the same'
);
t.ok(
!deepEqual(
[ function (x) { return x * 2 } ],
[ function (x) { return x * 2 } ]
),
'functions with the same .toString() aren\'t necessarily the same'
);
var f = function (x) { return x * 2 };
t.ok(
deepEqual([ f ], [ f ]),
'these functions are actually equal'
);
t.end();
});
test('deepEqual', function (t) {
t.ok(
!deepEqual([ 1, 2, 3 ], { 0 : 1, 1 : 2, 2 : 3 }),
'arrays are not objects'
);
t.end();
});
test('falsy', function (t) {
t.ok(
!deepEqual([ undefined ], [ null ]),
'null is not undefined!'
);
t.ok(
!deepEqual([ null ], [ undefined ]),
'undefined is not null!'
);
t.ok(
!deepEqual(
{ a : 1, b : 2, c : [ 3, undefined, 5 ] },
{ a : 1, b : 2, c : [ 3, null, 5 ] }
),
'undefined is not null, however deeply!'
);
t.ok(
!deepEqual(
{ a : 1, b : 2, c : [ 3, undefined, 5 ] },
{ a : 1, b : 2, c : [ 3, null, 5 ] }
),
'null is not undefined, however deeply!'
);
t.ok(
!deepEqual(
{ a : 1, b : 2, c : [ 3, undefined, 5 ] },
{ a : 1, b : 2, c : [ 3, null, 5 ] }
),
'null is not undefined, however deeply!'
);
t.end();
});
test('deletedArrayEqual', function (t) {
var xs = [ 1, 2, 3, 4 ];
delete xs[2];
var ys = Object.create(Array.prototype);
ys[0] = 1;
ys[1] = 2;
ys[3] = 4;
t.ok(
deepEqual(xs, ys),
'arrays with deleted elements are only equal to'
+ ' arrays with similarly deleted elements'
);
t.ok(
!deepEqual(xs, [ 1, 2, undefined, 4 ]),
'deleted array elements cannot be undefined'
);
t.ok(
!deepEqual(xs, [ 1, 2, null, 4 ]),
'deleted array elements cannot be null'
);
t.end();
});
test('deletedObjectEqual', function (t) {
var obj = { a : 1, b : 2, c : 3 };
delete obj.c;
t.ok(
deepEqual(obj, { a : 1, b : 2 }),
'deleted object elements should not show up'
);
t.ok(
!deepEqual(obj, { a : 1, b : 2, c : undefined }),
'deleted object elements are not undefined'
);
t.ok(
!deepEqual(obj, { a : 1, b : 2, c : null }),
'deleted object elements are not null'
);
t.end();
});
test('emptyKeyEqual', function (t) {
t.ok(!deepEqual(
{ a : 1 }, { a : 1, '' : 55 }
));
t.end();
});
test('deepArguments', function (t) {
t.ok(
!deepEqual(
[ 4, 5, 6 ],
(function () { return arguments })(4, 5, 6)
),
'arguments are not arrays'
);
t.ok(
deepEqual(
(function () { return arguments })(4, 5, 6),
(function () { return arguments })(4, 5, 6)
),
'arguments should equal'
);
t.end();
});
test('deepUn', function (t) {
t.ok(!deepEqual({ a : 1, b : 2 }, undefined));
t.ok(!deepEqual({ a : 1, b : 2 }, {}));
t.ok(!deepEqual(undefined, { a : 1, b : 2 }));
t.ok(!deepEqual({}, { a : 1, b : 2 }));
t.ok(deepEqual(undefined, undefined));
t.ok(deepEqual(null, null));
t.ok(!deepEqual(undefined, null));
t.end();
});
test('deepLevels', function (t) {
var xs = [ 1, 2, [ 3, 4, [ 5, 6 ] ] ];
t.ok(!deepEqual(xs, []));
t.end();
});
var test = require('tape');
var traverse = require('../');
test('traverse an Error', function (t) {
var obj = new Error("test");
var results = traverse(obj).map(function (node) {});
t.same(results, { message: 'test' });
t.end();
});
var test = require('tape');
var traverse = require('../');
test('has', function (t) {
var obj = { a : 2, b : [ 4, 5, { c : 6 } ] };
t.equal(traverse(obj).has([ 'b', 2, 'c' ]), true)
t.equal(traverse(obj).has([ 'b', 2, 'c', 0 ]), false)
t.equal(traverse(obj).has([ 'b', 2, 'd' ]), false)
t.equal(traverse(obj).has([]), true)
t.equal(traverse(obj).has([ 'a' ]), true)
t.equal(traverse(obj).has([ 'a', 2 ]), false)
t.end();
});
var test = require('tape');
var traverse = require('../');
var EventEmitter = require('events').EventEmitter;
test('check instanceof on node elems', function (t) {
var counts = { emitter : 0 };
traverse([ new EventEmitter, 3, 4, { ev : new EventEmitter }])
.forEach(function (node) {
if (node instanceof EventEmitter) counts.emitter ++;
})
;
t.equal(counts.emitter, 2);
t.end();
});
var test = require('tape');
var traverse = require('../');
test('interface map', function (t) {
var obj = { a : [ 5,6,7 ], b : { c : [8] } };
t.same(
traverse.paths(obj)
.sort()
.map(function (path) { return path.join('/') })
.slice(1)
.join(' ')
,
'a a/0 a/1 a/2 b b/c b/c/0'
);
t.same(
traverse.nodes(obj),
[
{ a: [ 5, 6, 7 ], b: { c: [ 8 ] } },
[ 5, 6, 7 ], 5, 6, 7,
{ c: [ 8 ] }, [ 8 ], 8
]
);
t.same(
traverse.map(obj, function (node) {
if (typeof node == 'number') {
return node + 1000;
}
else if (Array.isArray(node)) {
return node.join(' ');
}
}),
{ a: '5 6 7', b: { c: '8' } }
);
var nodes = 0;
traverse.forEach(obj, function (node) { nodes ++ });
t.same(nodes, 8);
t.end();
});
var test = require('tape');
var traverse = require('../');
test('json test', function (t) {
var id = 54;
var callbacks = {};
var obj = { moo : function () {}, foo : [2,3,4, function () {}] };
var scrubbed = traverse(obj).map(function (x) {
if (typeof x === 'function') {
callbacks[id] = { id : id, f : x, path : this.path };
this.update('[Function]');
id++;
}
});
t.equal(
scrubbed.moo, '[Function]',
'obj.moo replaced with "[Function]"'
);
t.equal(
scrubbed.foo[3], '[Function]',
'obj.foo[3] replaced with "[Function]"'
);
t.same(scrubbed, {
moo : '[Function]',
foo : [ 2, 3, 4, "[Function]" ]
}, 'Full JSON string matches');
t.same(
typeof obj.moo, 'function',
'Original obj.moo still a function'
);
t.same(
typeof obj.foo[3], 'function',
'Original obj.foo[3] still a function'
);
t.same(callbacks, {
54: { id: 54, f : obj.moo, path: [ 'moo' ] },
55: { id: 55, f : obj.foo[3], path: [ 'foo', '3' ] },
}, 'Check the generated callbacks list');
t.end();
});
var test = require('tape');
var traverse = require('../');
test('sort test', function (t) {
var acc = [];
traverse({
a: 30,
b: 22,
id: 9
}).forEach(function (node) {
if ((! Array.isArray(node)) && typeof node === 'object') {
this.before(function(node) {
this.keys = Object.keys(node);
this.keys.sort(function(a, b) {
a = [a === "id" ? 0 : 1, a];
b = [b === "id" ? 0 : 1, b];
return a < b ? -1 : a > b ? 1 : 0;
});
});
}
if (this.isLeaf) acc.push(node);
});
t.equal(
acc.join(' '),
'9 30 22',
'Traversal in a custom order'
);
t.end();
});
var test = require('tape');
var traverse = require('../');
test('leaves test', function (t) {
var acc = [];
traverse({
a : [1,2,3],
b : 4,
c : [5,6],
d : { e : [7,8], f : 9 }
}).forEach(function (x) {
if (this.isLeaf) acc.push(x);
});
t.equal(
acc.join(' '),
'1 2 3 4 5 6 7 8 9',
'Traversal in the right(?) order'
);
t.end();
});
var traverse = require('../../');
module.exports = function (a, b) {
if (arguments.length !== 2) {
throw new Error(
'deepEqual requires exactly two objects to compare against'
);
}
var equal = true;
var node = b;
traverse(a).forEach(function (y) {
var notEqual = (function () {
equal = false;
//this.stop();
return undefined;
}).bind(this);
//if (node === undefined || node === null) return notEqual();
if (!this.isRoot) {
/*
if (!Object.hasOwnProperty.call(node, this.key)) {
return notEqual();
}
*/
if (typeof node !== 'object') return notEqual();
node = node[this.key];
}
var x = node;
this.post(function () {
node = x;
});
var toS = function (o) {
return Object.prototype.toString.call(o);
};
if (this.circular) {
if (traverse(b).get(this.circular.path) !== x) notEqual();
}
else if (typeof x !== typeof y) {
notEqual();
}
else if (x === null || y === null || x === undefined || y === undefined) {
if (x !== y) notEqual();
}
else if (x.__proto__ !== y.__proto__) {
notEqual();
}
else if (x === y) {
// nop
}
else if (typeof x === 'function') {
if (x instanceof RegExp) {
// both regexps on account of the __proto__ check
if (x.toString() != y.toString()) notEqual();
}
else if (x !== y) notEqual();
}
else if (typeof x === 'object') {
if (toS(y) === '[object Arguments]'
|| toS(x) === '[object Arguments]') {
if (toS(x) !== toS(y)) {
notEqual();
}
}
else if (toS(y) === '[object RegExp]'
|| toS(x) === '[object RegExp]') {
if (!x || !y || x.toString() !== y.toString()) notEqual();
}
else if (x instanceof Date || y instanceof Date) {
if (!(x instanceof Date) || !(y instanceof Date)
|| x.getTime() !== y.getTime()) {
notEqual();
}
}
else {
var kx = Object.keys(x);
var ky = Object.keys(y);
if (kx.length !== ky.length) return notEqual();
for (var i = 0; i < kx.length; i++) {
var k = kx[i];
if (!Object.hasOwnProperty.call(y, k)) {
notEqual();
}
}
}
}
});
return equal;
};
var test = require('tape');
var traverse = require('../');
var deepEqual = require('./lib/deep_equal');
test('mutate', function (t) {
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
var res = traverse(obj).forEach(function (x) {
if (typeof x === 'number' && x % 2 === 0) {
this.update(x * 10);
}
});
t.same(obj, res);
t.same(obj, { a : 1, b : 20, c : [ 3, 40 ] });
t.end();
});
test('mutateT', function (t) {
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
var res = traverse.forEach(obj, function (x) {
if (typeof x === 'number' && x % 2 === 0) {
this.update(x * 10);
}
});
t.same(obj, res);
t.same(obj, { a : 1, b : 20, c : [ 3, 40 ] });
t.end();
});
test('map', function (t) {
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
var res = traverse(obj).map(function (x) {
if (typeof x === 'number' && x % 2 === 0) {
this.update(x * 10);
}
});
t.same(obj, { a : 1, b : 2, c : [ 3, 4 ] });
t.same(res, { a : 1, b : 20, c : [ 3, 40 ] });
t.end();
});
test('mapT', function (t) {
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
var res = traverse.map(obj, function (x) {
if (typeof x === 'number' && x % 2 === 0) {
this.update(x * 10);
}
});
t.same(obj, { a : 1, b : 2, c : [ 3, 4 ] });
t.same(res, { a : 1, b : 20, c : [ 3, 40 ] });
t.end();
});
test('clone', function (t) {
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
var res = traverse(obj).clone();
t.same(obj, res);
t.ok(obj !== res);
obj.a ++;
t.same(res.a, 1);
obj.c.push(5);
t.same(res.c, [ 3, 4 ]);
t.end();
});
test('cloneT', function (t) {
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
var res = traverse.clone(obj);
t.same(obj, res);
t.ok(obj !== res);
obj.a ++;
t.same(res.a, 1);
obj.c.push(5);
t.same(res.c, [ 3, 4 ]);
t.end();
});
test('reduce', function (t) {
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
var res = traverse(obj).reduce(function (acc, x) {
if (this.isLeaf) acc.push(x);
return acc;
}, []);
t.same(obj, { a : 1, b : 2, c : [ 3, 4 ] });
t.same(res, [ 1, 2, 3, 4 ]);
t.end();
});
test('reduceInit', function (t) {
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
var res = traverse(obj).reduce(function (acc, x) {
if (this.isRoot) assert.fail('got root');
return acc;
});
t.same(obj, { a : 1, b : 2, c : [ 3, 4 ] });
t.same(res, obj);
t.end();
});
test('remove', function (t) {
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
traverse(obj).forEach(function (x) {
if (this.isLeaf && x % 2 == 0) this.remove();
});
t.same(obj, { a : 1, c : [ 3 ] });
t.end();
});
exports.removeNoStop = function() {
var obj = { a : 1, b : 2, c : { d: 3, e: 4 }, f: 5 };
var keys = [];
traverse(obj).forEach(function (x) {
keys.push(this.key)
if (this.key == 'c') this.remove();
});
t.same(keys, [undefined, 'a', 'b', 'c', 'd', 'e', 'f'])
t.end();
}
exports.removeStop = function() {
var obj = { a : 1, b : 2, c : { d: 3, e: 4 }, f: 5 };
var keys = [];
traverse(obj).forEach(function (x) {
keys.push(this.key)
if (this.key == 'c') this.remove(true);
});
t.same(keys, [undefined, 'a', 'b', 'c', 'f'])
t.end();
}
test('removeMap', function (t) {
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
var res = traverse(obj).map(function (x) {
if (this.isLeaf && x % 2 == 0) this.remove();
});
t.same(obj, { a : 1, b : 2, c : [ 3, 4 ] });
t.same(res, { a : 1, c : [ 3 ] });
t.end();
});
test('delete', function (t) {
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
traverse(obj).forEach(function (x) {
if (this.isLeaf && x % 2 == 0) this.delete();
});
t.ok(!deepEqual(
obj, { a : 1, c : [ 3, undefined ] }
));
t.ok(deepEqual(
obj, { a : 1, c : [ 3 ] }
));
t.ok(!deepEqual(
obj, { a : 1, c : [ 3, null ] }
));
t.end();
});
test('deleteNoStop', function (t) {
var obj = { a : 1, b : 2, c : { d: 3, e: 4 } };
var keys = [];
traverse(obj).forEach(function (x) {
keys.push(this.key)
if (this.key == 'c') this.delete();
});
t.same(keys, [undefined, 'a', 'b', 'c', 'd', 'e'])
t.end();
});
test('deleteStop', function (t) {
var obj = { a : 1, b : 2, c : { d: 3, e: 4 } };
var keys = [];
traverse(obj).forEach(function (x) {
keys.push(this.key)
if (this.key == 'c') this.delete(true);
});
t.same(keys, [undefined, 'a', 'b', 'c'])
t.end();
});
test('deleteRedux', function (t) {
var obj = { a : 1, b : 2, c : [ 3, 4, 5 ] };
traverse(obj).forEach(function (x) {
if (this.isLeaf && x % 2 == 0) this.delete();
});
t.ok(!deepEqual(
obj, { a : 1, c : [ 3, undefined, 5 ] }
));
t.ok(deepEqual(
obj, { a : 1, c : [ 3 ,, 5 ] }
));
t.ok(!deepEqual(
obj, { a : 1, c : [ 3, null, 5 ] }
));
t.ok(!deepEqual(
obj, { a : 1, c : [ 3, 5 ] }
));
t.end();
});
test('deleteMap', function (t) {
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
var res = traverse(obj).map(function (x) {
if (this.isLeaf && x % 2 == 0) this.delete();
});
t.ok(deepEqual(
obj,
{ a : 1, b : 2, c : [ 3, 4 ] }
));
var xs = [ 3, 4 ];
delete xs[1];
t.ok(deepEqual(
res, { a : 1, c : xs }
));
t.ok(deepEqual(
res, { a : 1, c : [ 3, ] }
));
t.ok(deepEqual(
res, { a : 1, c : [ 3 ] }
));
t.end();
});
test('deleteMapRedux', function (t) {
var obj = { a : 1, b : 2, c : [ 3, 4, 5 ] };
var res = traverse(obj).map(function (x) {
if (this.isLeaf && x % 2 == 0) this.delete();
});
t.ok(deepEqual(
obj,
{ a : 1, b : 2, c : [ 3, 4, 5 ] }
));
var xs = [ 3, 4, 5 ];
delete xs[1];
t.ok(deepEqual(
res, { a : 1, c : xs }
));
t.ok(!deepEqual(
res, { a : 1, c : [ 3, 5 ] }
));
t.ok(deepEqual(
res, { a : 1, c : [ 3 ,, 5 ] }
));
t.end();
});
test('objectToString', function (t) {
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
var res = traverse(obj).forEach(function (x) {
if (typeof x === 'object' && !this.isRoot) {
this.update(JSON.stringify(x));
}
});
t.same(obj, res);
t.same(obj, { a : 1, b : 2, c : "[3,4]" });
t.end();
});
test('stringToObject', function (t) {
var obj = { a : 1, b : 2, c : "[3,4]" };
var res = traverse(obj).forEach(function (x) {
if (typeof x === 'string') {
this.update(JSON.parse(x));
}
else if (typeof x === 'number' && x % 2 === 0) {
this.update(x * 10);
}
});
t.deepEqual(obj, res);
t.deepEqual(obj, { a : 1, b : 20, c : [ 3, 40 ] });
t.end();
});
var traverse = require('../');
var test = require('tape');
test('negative update test', function (t) {
var obj = [ 5, 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ];
var fixed = traverse.map(obj, function (x) {
if (x < 0) this.update(x + 128);
});
t.same(fixed,
[ 5, 6, 125, [ 7, 8, 126, 1 ], { f: 10, g: 115 } ],
'Negative values += 128'
);
t.same(obj,
[ 5, 6, -3, [ 7, 8, -2, 1 ], { f: 10, g: -13 } ],
'Original references not modified'
);
t.end();
});
var test = require('tape');
var traverse = require('../');
test('traverse an object with nested functions', function (t) {
t.plan(1);
function Cons (x) {
t.equal(x, 10)
};
traverse(new Cons(10));
});
var test = require('tape');
var traverse = require('../');
test('siblings', function (t) {
var obj = { a : 1, b : 2, c : [ 4, 5, 6 ] };
var res = traverse(obj).reduce(function (acc, x) {
var p = '/' + this.path.join('/');
if (this.parent) {
acc[p] = {
siblings : this.parent.keys,
key : this.key,
index : this.parent.keys.indexOf(this.key)
};
}
else {
acc[p] = {
siblings : [],
key : this.key,
index : -1
}
}
return acc;
}, {});
t.same(res, {
'/' : { siblings : [], key : undefined, index : -1 },
'/a' : { siblings : [ 'a', 'b', 'c' ], key : 'a', index : 0 },
'/b' : { siblings : [ 'a', 'b', 'c' ], key : 'b', index : 1 },
'/c' : { siblings : [ 'a', 'b', 'c' ], key : 'c', index : 2 },
'/c/0' : { siblings : [ '0', '1', '2' ], key : '0', index : 0 },
'/c/1' : { siblings : [ '0', '1', '2' ], key : '1', index : 1 },
'/c/2' : { siblings : [ '0', '1', '2' ], key : '2', index : 2 }
});
t.end();
});
var test = require('tape');
var traverse = require('../');
test('stop', function (t) {
var visits = 0;
traverse('abcdefghij'.split('')).forEach(function (node) {
if (typeof node === 'string') {
visits ++;
if (node === 'e') this.stop()
}
});
t.equal(visits, 5);
t.end();
});
test('stopMap', function (t) {
var s = traverse('abcdefghij'.split('')).map(function (node) {
if (typeof node === 'string') {
if (node === 'e') this.stop()
return node.toUpperCase();
}
}).join('');
t.equal(s, 'ABCDEfghij');
t.end();
});
test('stopReduce', function (t) {
var obj = {
a : [ 4, 5 ],
b : [ 6, [ 7, 8, 9 ] ]
};
var xs = traverse(obj).reduce(function (acc, node) {
if (this.isLeaf) {
if (node === 7) this.stop();
else acc.push(node)
}
return acc;
}, []);
t.same(xs, [ 4, 5, 6 ]);
t.end();
});
var test = require('tape');
var traverse = require('../');
test('stringify', function (t) {
var obj = [ 5, 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ];
var s = '';
traverse(obj).forEach(function (node) {
if (Array.isArray(node)) {
this.before(function () { s += '[' });
this.post(function (child) {
if (!child.isLast) s += ',';
});
this.after(function () { s += ']' });
}
else if (typeof node == 'object') {
this.before(function () { s += '{' });
this.pre(function (x, key) {
s += '"' + key + '"' + ':';
});
this.post(function (child) {
if (!child.isLast) s += ',';
});
this.after(function () { s += '}' });
}
else if (typeof node == 'function') {
s += 'null';
}
else {
s += node.toString();
}
});
t.equal(s, JSON.stringify(obj));
t.end();
});
var traverse = require('../');
var test = require('tape');
test('subexpr', function (t) {
var obj = [ 'a', 4, 'b', 5, 'c', 6 ];
var r = traverse(obj).map(function (x) {
if (typeof x === 'number') {
this.update([ x - 0.1, x, x + 0.1 ], true);
}
});
t.same(obj, [ 'a', 4, 'b', 5, 'c', 6 ]);
t.same(r, [
'a', [ 3.9, 4, 4.1 ],
'b', [ 4.9, 5, 5.1 ],
'c', [ 5.9, 6, 6.1 ],
]);
t.end();
});
test('block', function (t) {
var obj = [ [ 1 ], [ 2 ], [ 3 ] ];
var r = traverse(obj).map(function (x) {
if (Array.isArray(x) && !this.isRoot) {
if (x[0] === 5) this.block()
else this.update([ [ x[0] + 1 ] ])
}
});
t.same(r, [
[ [ [ [ [ 5 ] ] ] ] ],
[ [ [ [ 5 ] ] ] ],
[ [ [ 5 ] ] ],
]);
t.end();
});
var test = require('tape');
var traverse = require('../');
var deepEqual = require('./lib/deep_equal');
test('super_deep', function (t) {
var util = require('util');
var a0 = make();
var a1 = make();
t.ok(deepEqual(a0, a1));
a0.c.d.moo = true;
t.ok(!deepEqual(a0, a1));
a1.c.d.moo = true;
t.ok(deepEqual(a0, a1));
// TODO: this one
//a0.c.a = a1;
//t.ok(!deepEqual(a0, a1));
t.end();
});
function make () {
var a = { self : 'a' };
var b = { self : 'b' };
var c = { self : 'c' };
var d = { self : 'd' };
var e = { self : 'e' };
a.a = a;
a.b = b;
a.c = c;
b.a = a;
b.b = b;
b.c = c;
c.a = a;
c.b = b;
c.c = c;
c.d = d;
d.a = a;
d.b = b;
d.c = c;
d.d = d;
d.e = e;
e.a = a;
e.b = b;
e.c = c;
e.d = d;
e.e = e;
return a;
}
var traverse = require('./');
var test = require('testling');
test('leaves', function (t) {
var obj = {
a : [1,2,3],
b : 4,
c : [5,6],
d : { e : [7,8], f : 9 }
};
var acc = [];
traverse(obj).forEach(function (x) {
if (this.isLeaf) acc.push(x);
});
t.deepEqual(
acc, [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ],
'traversal in the proper order'
);
t.end();
});
<a name="1.13.1"></a>
## 1.13.1 (2019-02-04)
* Fixed typo & removed redundant line ([156bbd5](https://github.com/przemyslawpluta/node-youtube-dl/commit/156bbd5))
<a name="1.13.0"></a>
# 1.13.0 (2019-01-25)
* build: add release process ([8cc1b05](https://github.com/przemyslawpluta/node-youtube-dl/commit/8cc1b05))
* test: update snapshots ([65fb75e](https://github.com/przemyslawpluta/node-youtube-dl/commit/65fb75e))
* add editorconfig ([8a92f0b](https://github.com/przemyslawpluta/node-youtube-dl/commit/8a92f0b))
* add hms to duration, twitch test ([9ea3ff1](https://github.com/przemyslawpluta/node-youtube-dl/commit/9ea3ff1))
* add sensible `execFile` good defaults ([2524d75](https://github.com/przemyslawpluta/node-youtube-dl/commit/2524d75)), closes [#173](https://github.com/przemyslawpluta/node-youtube-dl/issues/173)
* Adding dashes before the video ID ([da8f4dd](https://github.com/przemyslawpluta/node-youtube-dl/commit/da8f4dd))
* changed to _filename in line 33 readme ([87d3891](https://github.com/przemyslawpluta/node-youtube-dl/commit/87d3891))
* Consider copyright videos as not available in order to continue on error ([e19d8d1](https://github.com/przemyslawpluta/node-youtube-dl/commit/e19d8d1))
* Consider not made available videos as not available in order to continue on error ([ae7ea3b](https://github.com/przemyslawpluta/node-youtube-dl/commit/ae7ea3b))
* Correct extension in playlist.js ([5d77436](https://github.com/przemyslawpluta/node-youtube-dl/commit/5d77436))
* Correct test with correct video info ([0ee2609](https://github.com/przemyslawpluta/node-youtube-dl/commit/0ee2609))
* Disable non-functional test ([ca1aa42](https://github.com/przemyslawpluta/node-youtube-dl/commit/ca1aa42))
* download best and combine is ffmpeg available ([2193220](https://github.com/przemyslawpluta/node-youtube-dl/commit/2193220))
* Download correct binary for windows systems ([3874a88](https://github.com/przemyslawpluta/node-youtube-dl/commit/3874a88))
* drop tests for 4,5 and version bump ([3634c67](https://github.com/przemyslawpluta/node-youtube-dl/commit/3634c67))
* Fix encoding issue on windows ([d65114d](https://github.com/przemyslawpluta/node-youtube-dl/commit/d65114d))
* Get and set path from youtube-dl ([161ed2a](https://github.com/przemyslawpluta/node-youtube-dl/commit/161ed2a))
* handle thumbnails download ([a0832dc](https://github.com/przemyslawpluta/node-youtube-dl/commit/a0832dc))
* hms and raw duration ([eb0e9de](https://github.com/przemyslawpluta/node-youtube-dl/commit/eb0e9de))
* meta tweaks ([f685ad7](https://github.com/przemyslawpluta/node-youtube-dl/commit/f685ad7))
* minor typo ([429b1f7](https://github.com/przemyslawpluta/node-youtube-dl/commit/429b1f7))
* missing ; ([05f8f62](https://github.com/przemyslawpluta/node-youtube-dl/commit/05f8f62))
* remove dead code ([4b1ba39](https://github.com/przemyslawpluta/node-youtube-dl/commit/4b1ba39))
* remove deprecated badge ([19a7b33](https://github.com/przemyslawpluta/node-youtube-dl/commit/19a7b33))
* remove lock ([0131daf](https://github.com/przemyslawpluta/node-youtube-dl/commit/0131daf))
* Remove size from download test, not relevant ([e22ee14](https://github.com/przemyslawpluta/node-youtube-dl/commit/e22ee14))
* remove vimeo tests ([1f717cc](https://github.com/przemyslawpluta/node-youtube-dl/commit/1f717cc))
* update dependencies ([bf28967](https://github.com/przemyslawpluta/node-youtube-dl/commit/bf28967))
* update snapshot ([70ec50a](https://github.com/przemyslawpluta/node-youtube-dl/commit/70ec50a))
* Update test about twitch (twitch id are not anymore the video title) ([b9f0317](https://github.com/przemyslawpluta/node-youtube-dl/commit/b9f0317))
* update travis builds ([efe313c](https://github.com/przemyslawpluta/node-youtube-dl/commit/efe313c))
* Updated test case since video title changed on twitch's end ([7c22361](https://github.com/przemyslawpluta/node-youtube-dl/commit/7c22361))
* use const over var ([6ed5a1c](https://github.com/przemyslawpluta/node-youtube-dl/commit/6ed5a1c))
<a name="1.12.1"></a>
## 1.12.1 (2017-09-28)
* cleanup ([68ea1df](https://github.com/przemyslawpluta/node-youtube-dl/commit/68ea1df))
* cleanup ([5efbce3](https://github.com/przemyslawpluta/node-youtube-dl/commit/5efbce3))
* concat args ([25ed267](https://github.com/przemyslawpluta/node-youtube-dl/commit/25ed267))
* correct repo url ([88ec7c8](https://github.com/przemyslawpluta/node-youtube-dl/commit/88ec7c8))
* Document how to increase buffer size ([3bb3e4d](https://github.com/przemyslawpluta/node-youtube-dl/commit/3bb3e4d))
* drop getFormats, update vimeo test ([da47d4d](https://github.com/przemyslawpluta/node-youtube-dl/commit/da47d4d))
* drop io.js tests ([b1fa4fb](https://github.com/przemyslawpluta/node-youtube-dl/commit/b1fa4fb))
* drop soundcloud due to ssl error on travis ([0c7168d](https://github.com/przemyslawpluta/node-youtube-dl/commit/0c7168d))
* drop tests for 0.10 ([473cdf6](https://github.com/przemyslawpluta/node-youtube-dl/commit/473cdf6))
* fix ([a6d6d36](https://github.com/przemyslawpluta/node-youtube-dl/commit/a6d6d36))
* Fix issue with duration not formatting correctly ([d9dd0ec](https://github.com/przemyslawpluta/node-youtube-dl/commit/d9dd0ec))
* fix package name ([5642547](https://github.com/przemyslawpluta/node-youtube-dl/commit/5642547))
* fix tests, update formatting ([796f922](https://github.com/przemyslawpluta/node-youtube-dl/commit/796f922))
* fixed downloader if user passed in a custom bin dir ([2954eed](https://github.com/przemyslawpluta/node-youtube-dl/commit/2954eed))
* Fixed tests assertion, video sizes changed probably due to change in streaming technology and title ([d2f7894](https://github.com/przemyslawpluta/node-youtube-dl/commit/d2f7894))
* hotfix for the electron issue ([ae7608c](https://github.com/przemyslawpluta/node-youtube-dl/commit/ae7608c))
* Make properties configurable ([dab402b](https://github.com/przemyslawpluta/node-youtube-dl/commit/dab402b))
* manage missing video array plus tests ([6f2840e](https://github.com/przemyslawpluta/node-youtube-dl/commit/6f2840e))
* py + node test ([cf2d5e1](https://github.com/przemyslawpluta/node-youtube-dl/commit/cf2d5e1))
* python test ([e6b597a](https://github.com/przemyslawpluta/node-youtube-dl/commit/e6b597a))
* Quickfix for Copy Error in Usage Example ([db27e8a](https://github.com/przemyslawpluta/node-youtube-dl/commit/db27e8a))
* skip error is video has been removed by the user ([5e94b13](https://github.com/przemyslawpluta/node-youtube-dl/commit/5e94b13))
* skip error is video has been removed by the user ([956056b](https://github.com/przemyslawpluta/node-youtube-dl/commit/956056b))
* ssl err test ([0738a25](https://github.com/przemyslawpluta/node-youtube-dl/commit/0738a25))
* test ([80d924a](https://github.com/przemyslawpluta/node-youtube-dl/commit/80d924a))
* travis ssl force ([6b0f0f8](https://github.com/przemyslawpluta/node-youtube-dl/commit/6b0f0f8))
* update audio.js ([17c3fb1](https://github.com/przemyslawpluta/node-youtube-dl/commit/17c3fb1))
* update build status ([1aa9d82](https://github.com/przemyslawpluta/node-youtube-dl/commit/1aa9d82))
* update details ([653f411](https://github.com/przemyslawpluta/node-youtube-dl/commit/653f411))
* update icons ([0399db6](https://github.com/przemyslawpluta/node-youtube-dl/commit/0399db6))
* update mode ([e83b336](https://github.com/przemyslawpluta/node-youtube-dl/commit/e83b336))
* update package ([2867fc5](https://github.com/przemyslawpluta/node-youtube-dl/commit/2867fc5))
* Update README.md ([76cb708](https://github.com/przemyslawpluta/node-youtube-dl/commit/76cb708))
* update tests ([d745285](https://github.com/przemyslawpluta/node-youtube-dl/commit/d745285))
* update travis env ([08fd355](https://github.com/przemyslawpluta/node-youtube-dl/commit/08fd355))
* update travis-ci ([339460b](https://github.com/przemyslawpluta/node-youtube-dl/commit/339460b))
* update youtube-dl permissions ([621b478](https://github.com/przemyslawpluta/node-youtube-dl/commit/621b478))
* updates & fixes ([8bc4839](https://github.com/przemyslawpluta/node-youtube-dl/commit/8bc4839))
* version bump ([a839a5f](https://github.com/przemyslawpluta/node-youtube-dl/commit/a839a5f))
<a name="1.11.1"></a>
## 1.11.1 (2016-04-06)
* add heroku support ([541e710](https://github.com/przemyslawpluta/node-youtube-dl/commit/541e710))
* version bump ([22abe25](https://github.com/przemyslawpluta/node-youtube-dl/commit/22abe25))
<a name="1.11.0"></a>
# 1.11.0 (2016-03-25)
* add getFormats example ([d9b2925](https://github.com/przemyslawpluta/node-youtube-dl/commit/d9b2925))
* add node 4 & 5 for testing ([8683ac1](https://github.com/przemyslawpluta/node-youtube-dl/commit/8683ac1))
* adding ability to continue partially downloaded files. ([e9e540a](https://github.com/przemyslawpluta/node-youtube-dl/commit/e9e540a))
* allow for external bin but keep details internally ([f35daab](https://github.com/przemyslawpluta/node-youtube-dl/commit/f35daab))
* As requested, I was trying to make the code as readable as possible ([38884d1](https://github.com/przemyslawpluta/node-youtube-dl/commit/38884d1))
* callback err ([f49128c](https://github.com/przemyslawpluta/node-youtube-dl/commit/f49128c))
* change bin permissions ([957172b](https://github.com/przemyslawpluta/node-youtube-dl/commit/957172b))
* check for datadir existence ([1817160](https://github.com/przemyslawpluta/node-youtube-dl/commit/1817160))
* choose bin location ([1123d33](https://github.com/przemyslawpluta/node-youtube-dl/commit/1123d33))
* cleanup ([12eb585](https://github.com/przemyslawpluta/node-youtube-dl/commit/12eb585))
* cleanup ([1a8b2f0](https://github.com/przemyslawpluta/node-youtube-dl/commit/1a8b2f0))
* cleanup .gitignore ([bf5b974](https://github.com/przemyslawpluta/node-youtube-dl/commit/bf5b974))
* dependencies bump ([f131dca](https://github.com/przemyslawpluta/node-youtube-dl/commit/f131dca))
* document `ytdl.exec()` with audio example ([2b8333f](https://github.com/przemyslawpluta/node-youtube-dl/commit/2b8333f))
* extract downloader ([f27c45a](https://github.com/przemyslawpluta/node-youtube-dl/commit/f27c45a))
* fix bin path ([6f9ef39](https://github.com/przemyslawpluta/node-youtube-dl/commit/6f9ef39))
* fix license meta in pacakge.json ([3d2f168](https://github.com/przemyslawpluta/node-youtube-dl/commit/3d2f168))
* fix resolution or audio ([d2a3269](https://github.com/przemyslawpluta/node-youtube-dl/commit/d2a3269))
* handle playlists ([acb1571](https://github.com/przemyslawpluta/node-youtube-dl/commit/acb1571))
* install module before download ([f3e0ac7](https://github.com/przemyslawpluta/node-youtube-dl/commit/f3e0ac7))
* missing dependency ([f56cb24](https://github.com/przemyslawpluta/node-youtube-dl/commit/f56cb24))
* move bin path to datadir ([7ef58ef](https://github.com/przemyslawpluta/node-youtube-dl/commit/7ef58ef))
* no longer maintaining ([1aa9076](https://github.com/przemyslawpluta/node-youtube-dl/commit/1aa9076))
* package postinstall ([c1f052f](https://github.com/przemyslawpluta/node-youtube-dl/commit/c1f052f))
* permission change on bin ([c061caa](https://github.com/przemyslawpluta/node-youtube-dl/commit/c061caa))
* permission change on bin cleanup test ([6912150](https://github.com/przemyslawpluta/node-youtube-dl/commit/6912150))
* preventing options being created if it doesn't exist ([894e215](https://github.com/przemyslawpluta/node-youtube-dl/commit/894e215))
* remove unused module ([6fc3f02](https://github.com/przemyslawpluta/node-youtube-dl/commit/6fc3f02))
* resolve to .exe on win ([2c5467e](https://github.com/przemyslawpluta/node-youtube-dl/commit/2c5467e))
* skip over not available videos during playlist download ([45ee26b](https://github.com/przemyslawpluta/node-youtube-dl/commit/45ee26b))
* store example videos in dir to keep things cleaner ([e7cc0d5](https://github.com/przemyslawpluta/node-youtube-dl/commit/e7cc0d5))
* update ([4da180b](https://github.com/przemyslawpluta/node-youtube-dl/commit/4da180b))
* update ([60a0cf4](https://github.com/przemyslawpluta/node-youtube-dl/commit/60a0cf4))
* update path ([b9992cf](https://github.com/przemyslawpluta/node-youtube-dl/commit/b9992cf))
* update readme ([c159427](https://github.com/przemyslawpluta/node-youtube-dl/commit/c159427))
* update readme ([a41b965](https://github.com/przemyslawpluta/node-youtube-dl/commit/a41b965))
* update README ([1565229](https://github.com/przemyslawpluta/node-youtube-dl/commit/1565229))
* update tests ([7be149d](https://github.com/przemyslawpluta/node-youtube-dl/commit/7be149d))
* Updating comment block for inline quotes, replacing double quotes with single quotes ([1646cec](https://github.com/przemyslawpluta/node-youtube-dl/commit/1646cec))
<a name="1.10.5"></a>
## 1.10.5 (2015-05-07)
* 1.10.5 ([d2d4eba](https://github.com/przemyslawpluta/node-youtube-dl/commit/d2d4eba))
* better check for `--format` ([dbaebb3](https://github.com/przemyslawpluta/node-youtube-dl/commit/dbaebb3))
<a name="1.10.4"></a>
## 1.10.4 (2015-05-07)
* 1.10.4 ([06ec68e](https://github.com/przemyslawpluta/node-youtube-dl/commit/06ec68e))
* check for `--format` too ([08ca167](https://github.com/przemyslawpluta/node-youtube-dl/commit/08ca167))
* Specify download format 'best' if none supplied ([edee4d3](https://github.com/przemyslawpluta/node-youtube-dl/commit/edee4d3))
* update examples ([023a502](https://github.com/przemyslawpluta/node-youtube-dl/commit/023a502))
* update tests ([a85779d](https://github.com/przemyslawpluta/node-youtube-dl/commit/a85779d))
<a name="1.10.3"></a>
## 1.10.3 (2015-04-19)
* 1.10.3 ([a70895e](https://github.com/przemyslawpluta/node-youtube-dl/commit/a70895e))
* Fix the broken Host HTTP Header for Dailymotion && Fix Test ([9657b8c](https://github.com/przemyslawpluta/node-youtube-dl/commit/9657b8c))
<a name="1.10.2"></a>
## 1.10.2 (2015-03-24)
* 1.10.2 ([484d1c3](https://github.com/przemyslawpluta/node-youtube-dl/commit/484d1c3))
* a bit of docs ([c3c1b4b](https://github.com/przemyslawpluta/node-youtube-dl/commit/c3c1b4b))
* print warning when getting warnings from stderr ([26bd213](https://github.com/przemyslawpluta/node-youtube-dl/commit/26bd213))
<a name="1.10.1"></a>
## 1.10.1 (2015-02-26)
* 1.10.1 ([498e288](https://github.com/przemyslawpluta/node-youtube-dl/commit/498e288))
* add io.js and 0.12 to test matrix ([17ce70b](https://github.com/przemyslawpluta/node-youtube-dl/commit/17ce70b))
* call binary with python instead of directly, fixes #66 ([833d281](https://github.com/przemyslawpluta/node-youtube-dl/commit/833d281)), closes [#66](https://github.com/przemyslawpluta/node-youtube-dl/issues/66)
* dont test on node v0.8 ([5c1c182](https://github.com/przemyslawpluta/node-youtube-dl/commit/5c1c182))
* quote iojs ([47d1485](https://github.com/przemyslawpluta/node-youtube-dl/commit/47d1485))
* update packages ([413cf53](https://github.com/przemyslawpluta/node-youtube-dl/commit/413cf53))
* use container based environment ([4947618](https://github.com/przemyslawpluta/node-youtube-dl/commit/4947618))
<a name="1.10.0"></a>
# 1.10.0 (2015-02-19)
* 1.10.0 ([d3018e5](https://github.com/przemyslawpluta/node-youtube-dl/commit/d3018e5))
* Multiple URL support (array param) for getInfo() ([1afab0b](https://github.com/przemyslawpluta/node-youtube-dl/commit/1afab0b))
<a name="1.9.0"></a>
# 1.9.0 (2015-02-13)
* 1.9.0 ([e3be488](https://github.com/przemyslawpluta/node-youtube-dl/commit/e3be488))
* add warnings for using deprecated fields ([d2c53ae](https://github.com/przemyslawpluta/node-youtube-dl/commit/d2c53ae))
* Call getInfo from getFormats ([4ecda89](https://github.com/przemyslawpluta/node-youtube-dl/commit/4ecda89))
* document how to keep youtube-dl binary up to date. fixes #61 ([a8eface](https://github.com/przemyslawpluta/node-youtube-dl/commit/a8eface)), closes [#61](https://github.com/przemyslawpluta/node-youtube-dl/issues/61)
* dont check each individual format object ([50c113f](https://github.com/przemyslawpluta/node-youtube-dl/commit/50c113f))
* fix getting playlist info ([cdb37fe](https://github.com/przemyslawpluta/node-youtube-dl/commit/cdb37fe))
* Move formatDuration to util.js ([c309c24](https://github.com/przemyslawpluta/node-youtube-dl/commit/c309c24))
* remove unused old functions ([e4689a6](https://github.com/przemyslawpluta/node-youtube-dl/commit/e4689a6))
* Return the full info provided by youtube-dl ([ace1b11](https://github.com/przemyslawpluta/node-youtube-dl/commit/ace1b11))
* Use the '--dump-json' option for extracting the video information ([b3a9fcd](https://github.com/przemyslawpluta/node-youtube-dl/commit/b3a9fcd))
* Use the '--dump-json' option for getFormats ([e93a8b9](https://github.com/przemyslawpluta/node-youtube-dl/commit/e93a8b9))
<a name="1.8.0"></a>
# 1.8.0 (2015-01-15)
* 1.8.0 ([ab8b3df](https://github.com/przemyslawpluta/node-youtube-dl/commit/ab8b3df))
* Added extractor API incl. tests and example code ([d2b3983](https://github.com/przemyslawpluta/node-youtube-dl/commit/d2b3983))
* dont download video when downloading subtitles ([3cfa382](https://github.com/przemyslawpluta/node-youtube-dl/commit/3cfa382))
* put try/catch around unlinking subtitle file ([a3f5202](https://github.com/przemyslawpluta/node-youtube-dl/commit/a3f5202))
<a name="1.7.0"></a>
# 1.7.0 (2015-01-08)
* 1.7.0 ([777619e](https://github.com/przemyslawpluta/node-youtube-dl/commit/777619e))
* added more cli args to ignore ([8edbd1e](https://github.com/przemyslawpluta/node-youtube-dl/commit/8edbd1e))
* get duration. fixes #53 ([fd7d7c9](https://github.com/przemyslawpluta/node-youtube-dl/commit/fd7d7c9)), closes [#53](https://github.com/przemyslawpluta/node-youtube-dl/issues/53)
* make `args` passed to youtube-dl actually optional ([413d0ab](https://github.com/przemyslawpluta/node-youtube-dl/commit/413d0ab))
<a name="1.6.0"></a>
# 1.6.0 (2014-11-23)
* 1.6.0 ([8d548eb](https://github.com/przemyslawpluta/node-youtube-dl/commit/8d548eb))
* add `getSubs()` function. fixes #48 ([6cb55af](https://github.com/przemyslawpluta/node-youtube-dl/commit/6cb55af)), closes [#48](https://github.com/przemyslawpluta/node-youtube-dl/issues/48)
* better resolution detection ([cff5763](https://github.com/przemyslawpluta/node-youtube-dl/commit/cff5763))
* check size is defined ([0e67ef1](https://github.com/przemyslawpluta/node-youtube-dl/commit/0e67ef1))
* linting ([916e8da](https://github.com/przemyslawpluta/node-youtube-dl/commit/916e8da))
* linting ([1f5e319](https://github.com/przemyslawpluta/node-youtube-dl/commit/1f5e319))
* update formats returned ([d545f10](https://github.com/przemyslawpluta/node-youtube-dl/commit/d545f10))
* updated getFormats regex to handle unknown & ?x formats ([7e33ace](https://github.com/przemyslawpluta/node-youtube-dl/commit/7e33ace))
<a name="1.5.16"></a>
## 1.5.16 (2014-10-24)
* 1.5.16 ([4acfca7](https://github.com/przemyslawpluta/node-youtube-dl/commit/4acfca7))
* filter out from correct args if no subs ([97346fe](https://github.com/przemyslawpluta/node-youtube-dl/commit/97346fe))
* handle new warning style ([3ae2964](https://github.com/przemyslawpluta/node-youtube-dl/commit/3ae2964))
* update test formats ([24f00e5](https://github.com/przemyslawpluta/node-youtube-dl/commit/24f00e5))
<a name="1.5.15"></a>
## 1.5.15 (2014-09-25)
* 1.5.15 ([f315043](https://github.com/przemyslawpluta/node-youtube-dl/commit/f315043))
* fix ([5d07020](https://github.com/przemyslawpluta/node-youtube-dl/commit/5d07020))
<a name="1.5.14"></a>
## 1.5.14 (2014-09-24)
* 1.5.14 ([c7d7c08](https://github.com/przemyslawpluta/node-youtube-dl/commit/c7d7c08))
* expose call function with empty default args as exec ([e12b538](https://github.com/przemyslawpluta/node-youtube-dl/commit/e12b538))
* ignore any errors after successful download. fixes #43 ([58558d8](https://github.com/przemyslawpluta/node-youtube-dl/commit/58558d8)), closes [#43](https://github.com/przemyslawpluta/node-youtube-dl/issues/43)
<a name="1.5.13"></a>
## 1.5.13 (2014-09-07)
* 1.5.13 ([e72b27d](https://github.com/przemyslawpluta/node-youtube-dl/commit/e72b27d))
* fix for missing env variable in win ([4115b5e](https://github.com/przemyslawpluta/node-youtube-dl/commit/4115b5e))
<a name="1.5.12"></a>
## 1.5.12 (2014-09-04)
* 1.5.12 ([8a8c681](https://github.com/przemyslawpluta/node-youtube-dl/commit/8a8c681))
* fix youtube id filtering ([3cb82a9](https://github.com/przemyslawpluta/node-youtube-dl/commit/3cb82a9))
<a name="1.5.11"></a>
## 1.5.11 (2014-08-24)
* 1.5.11 ([09d2951](https://github.com/przemyslawpluta/node-youtube-dl/commit/09d2951))
* support non-youtube (speificially vimeo) videos. fixes #39 ([cd6938b](https://github.com/przemyslawpluta/node-youtube-dl/commit/cd6938b)), closes [#39](https://github.com/przemyslawpluta/node-youtube-dl/issues/39)
<a name="1.5.10"></a>
## 1.5.10 (2014-08-05)
* 1.5.10 ([f9c0c8f](https://github.com/przemyslawpluta/node-youtube-dl/commit/f9c0c8f))
* fix not passing options ([02fa0df](https://github.com/przemyslawpluta/node-youtube-dl/commit/02fa0df))
<a name="1.5.9"></a>
## 1.5.9 (2014-08-02)
* 1.5.9 ([303fb12](https://github.com/przemyslawpluta/node-youtube-dl/commit/303fb12))
* Add more entries to badArgs ([a6821b5](https://github.com/przemyslawpluta/node-youtube-dl/commit/a6821b5))
* fix for failed download with no subtitles ([36fd75a](https://github.com/przemyslawpluta/node-youtube-dl/commit/36fd75a))
* fix for failed download with no subtitles when requested ([69166bf](https://github.com/przemyslawpluta/node-youtube-dl/commit/69166bf))
* fix for failed download with no subtitles when requested ([aeab2dd](https://github.com/przemyslawpluta/node-youtube-dl/commit/aeab2dd))
* fix for failed download with no subtitles when requested ([038b1fd](https://github.com/przemyslawpluta/node-youtube-dl/commit/038b1fd))
* fix for failed download with no subtitles when requested ([19c13af](https://github.com/przemyslawpluta/node-youtube-dl/commit/19c13af))
* fix for failed download with no subtitles when requested ([82a48a4](https://github.com/przemyslawpluta/node-youtube-dl/commit/82a48a4))
* only notify on build changes ([3cf3363](https://github.com/przemyslawpluta/node-youtube-dl/commit/3cf3363))
* update request to v2.37.0 ([11757f3](https://github.com/przemyslawpluta/node-youtube-dl/commit/11757f3))
<a name="1.5.8"></a>
## 1.5.8 (2014-07-04)
* Fix ReferenceError: onerror is not defined ([acb3512](https://github.com/przemyslawpluta/node-youtube-dl/commit/acb3512))
* Fix var name: from er to err ([21bdbee](https://github.com/przemyslawpluta/node-youtube-dl/commit/21bdbee))
* update request ([f97f90b](https://github.com/przemyslawpluta/node-youtube-dl/commit/f97f90b))
* v1.5.7 ([f19215a](https://github.com/przemyslawpluta/node-youtube-dl/commit/f19215a))
* v1.5.8 ([96083ba](https://github.com/przemyslawpluta/node-youtube-dl/commit/96083ba))
<a name="1.5.6"></a>
## 1.5.6 (2014-06-14)
* comment consistency ([7acea1e](https://github.com/przemyslawpluta/node-youtube-dl/commit/7acea1e))
* fix parsing resolutions ([ac48c37](https://github.com/przemyslawpluta/node-youtube-dl/commit/ac48c37))
* fix when not giving `args` to `getInfo()` ([794617d](https://github.com/przemyslawpluta/node-youtube-dl/commit/794617d))
* v1.5.6 ([80999a5](https://github.com/przemyslawpluta/node-youtube-dl/commit/80999a5))
<a name="1.5.5"></a>
## 1.5.5 (2014-05-02)
* can pass execFile options to download ([2986447](https://github.com/przemyslawpluta/node-youtube-dl/commit/2986447))
* dont parse options twice on download ([67eb88d](https://github.com/przemyslawpluta/node-youtube-dl/commit/67eb88d))
* v1.5.5 ([20c3cd2](https://github.com/przemyslawpluta/node-youtube-dl/commit/20c3cd2))
<a name="1.5.4"></a>
## 1.5.4 (2014-05-01)
* chmod bin directory too ([3d1e88f](https://github.com/przemyslawpluta/node-youtube-dl/commit/3d1e88f))
* run download script on preinstall ([c377b4e](https://github.com/przemyslawpluta/node-youtube-dl/commit/c377b4e))
* update vows ([a3be7a9](https://github.com/przemyslawpluta/node-youtube-dl/commit/a3be7a9))
* v1.5.4 ([a0709a4](https://github.com/przemyslawpluta/node-youtube-dl/commit/a0709a4))
* package: add binary ([2050667](https://github.com/przemyslawpluta/node-youtube-dl/commit/2050667))
<a name="1.5.3"></a>
## 1.5.3 (2014-04-26)
* dont global link youtube-dl binary. too much confusion. ([b74ed8f](https://github.com/przemyslawpluta/node-youtube-dl/commit/b74ed8f))
* Remove /v/ from the id to accept url like http://www.youtube.com/v/6tC1yOUvvMo provided by the youtu ([b4a3350](https://github.com/przemyslawpluta/node-youtube-dl/commit/b4a3350))
* Remove useless g flag from Regex ([1239606](https://github.com/przemyslawpluta/node-youtube-dl/commit/1239606))
* some code organization ([085b9f7](https://github.com/przemyslawpluta/node-youtube-dl/commit/085b9f7))
* update ignore rules ([0acf105](https://github.com/przemyslawpluta/node-youtube-dl/commit/0acf105))
* v1.5.3 ([3175bd0](https://github.com/przemyslawpluta/node-youtube-dl/commit/3175bd0))
<a name="1.5.2"></a>
## 1.5.2 (2014-04-25)
* Add a second var ([76d3468](https://github.com/przemyslawpluta/node-youtube-dl/commit/76d3468))
* Fix "Cannot call method 'split' of undefined" bug with last version of youtube-dl (2014.04.21.6) ([864a526](https://github.com/przemyslawpluta/node-youtube-dl/commit/864a526))
* Remove commented old code ([9804155](https://github.com/przemyslawpluta/node-youtube-dl/commit/9804155))
* Remove the extra space ([11aabf9](https://github.com/przemyslawpluta/node-youtube-dl/commit/11aabf9))
* Save the regexp in the outer scope so it's not compiled every time this function runs ([585c526](https://github.com/przemyslawpluta/node-youtube-dl/commit/585c526))
* v1.5.2 ([88be6d7](https://github.com/przemyslawpluta/node-youtube-dl/commit/88be6d7))
<a name="1.5.1"></a>
## 1.5.1 (2014-04-08)
* add Przemyslaw to contributors ([afc4cc9](https://github.com/przemyslawpluta/node-youtube-dl/commit/afc4cc9))
* fix for win py2.x / py3.x ([472a8db](https://github.com/przemyslawpluta/node-youtube-dl/commit/472a8db))
* v1.5.1 ([7a2620d](https://github.com/przemyslawpluta/node-youtube-dl/commit/7a2620d))
<a name="1.5.0"></a>
# 1.5.0 (2014-04-08)
* download first if array of clips ([28ed6bb](https://github.com/przemyslawpluta/node-youtube-dl/commit/28ed6bb))
* handle videos download from youtube playlist ([b7434da](https://github.com/przemyslawpluta/node-youtube-dl/commit/b7434da))
* refactor ([6c5187e](https://github.com/przemyslawpluta/node-youtube-dl/commit/6c5187e))
* test update ([8704b8e](https://github.com/przemyslawpluta/node-youtube-dl/commit/8704b8e))
* typo ([540ee03](https://github.com/przemyslawpluta/node-youtube-dl/commit/540ee03))
* typo ([2647ed5](https://github.com/przemyslawpluta/node-youtube-dl/commit/2647ed5))
* v1.5.0 ([b27d373](https://github.com/przemyslawpluta/node-youtube-dl/commit/b27d373))
<a name="1.4.0"></a>
# 1.4.0 (2014-03-14)
* not needed ([7dcd88f](https://github.com/przemyslawpluta/node-youtube-dl/commit/7dcd88f))
* reflect api changes ([82aeb41](https://github.com/przemyslawpluta/node-youtube-dl/commit/82aeb41))
* update example videos ([3bd98d7](https://github.com/przemyslawpluta/node-youtube-dl/commit/3bd98d7))
* update tests ([c4ab33d](https://github.com/przemyslawpluta/node-youtube-dl/commit/c4ab33d))
* use youtube-dl to get download url, return stream ([3479e52](https://github.com/przemyslawpluta/node-youtube-dl/commit/3479e52))
* v1.4.0 ([e23e5f3](https://github.com/przemyslawpluta/node-youtube-dl/commit/e23e5f3))
<a name="1.3.6"></a>
## 1.3.6 (2014-02-15)
* fix - youtube-dl incorrect download ([8c439b1](https://github.com/przemyslawpluta/node-youtube-dl/commit/8c439b1))
* v1.3.6 ([be7c22f](https://github.com/przemyslawpluta/node-youtube-dl/commit/be7c22f))
<a name="1.3.5"></a>
## 1.3.5 (2014-02-15)
* Fix - win handling getInfo & getFormats ([19ccc54](https://github.com/przemyslawpluta/node-youtube-dl/commit/19ccc54))
* Fix - win handling getInfo & getFormats ([7655ea1](https://github.com/przemyslawpluta/node-youtube-dl/commit/7655ea1))
* v1.3.5 ([6f4eb9c](https://github.com/przemyslawpluta/node-youtube-dl/commit/6f4eb9c))
<a name="1.3.4"></a>
## 1.3.4 (2014-02-14)
* Fix - Incorrect youtube video URL ([954df15](https://github.com/przemyslawpluta/node-youtube-dl/commit/954df15))
* Fix - Incorrect youtube video URL ([17c4214](https://github.com/przemyslawpluta/node-youtube-dl/commit/17c4214))
* Fix - Incorrect youtube video URL ([12dea04](https://github.com/przemyslawpluta/node-youtube-dl/commit/12dea04))
* Fix - Incorrect youtube video URL ([1b10dff](https://github.com/przemyslawpluta/node-youtube-dl/commit/1b10dff))
* Fix - Incorrect youtube video URL ([408e2b1](https://github.com/przemyslawpluta/node-youtube-dl/commit/408e2b1))
* Fix - Incorrect youtube video URL ([c161fa6](https://github.com/przemyslawpluta/node-youtube-dl/commit/c161fa6))
* Fix - Incorrect youtube video URL ([753ae6b](https://github.com/przemyslawpluta/node-youtube-dl/commit/753ae6b))
* Fix - Incorrect youtube video URL ([04f4aaa](https://github.com/przemyslawpluta/node-youtube-dl/commit/04f4aaa))
* Fix - Incorrect youtube video URL ([a5eeb09](https://github.com/przemyslawpluta/node-youtube-dl/commit/a5eeb09))
* Fix - Incorrect youtube video URL ([28dd461](https://github.com/przemyslawpluta/node-youtube-dl/commit/28dd461))
* only write version to file if downloaded successfully ([091f425](https://github.com/przemyslawpluta/node-youtube-dl/commit/091f425))
* v1.3.4 ([6825c7b](https://github.com/przemyslawpluta/node-youtube-dl/commit/6825c7b))
<a name="1.3.3"></a>
## 1.3.3 (2014-02-12)
* spawn ENOENT in win ([48a309d](https://github.com/przemyslawpluta/node-youtube-dl/commit/48a309d))
* spawn ENOENT in win ([b6191c8](https://github.com/przemyslawpluta/node-youtube-dl/commit/b6191c8))
* spawn ENOENT in win ([a816720](https://github.com/przemyslawpluta/node-youtube-dl/commit/a816720))
* spawn ENOENT in win ([b6178e6](https://github.com/przemyslawpluta/node-youtube-dl/commit/b6178e6))
* tiny cleanup ([19a0059](https://github.com/przemyslawpluta/node-youtube-dl/commit/19a0059))
* update get formats regexp ([9df37f0](https://github.com/przemyslawpluta/node-youtube-dl/commit/9df37f0))
* update ugh tests ([db2388c](https://github.com/przemyslawpluta/node-youtube-dl/commit/db2388c))
* v1.3.3 ([f4498fa](https://github.com/przemyslawpluta/node-youtube-dl/commit/f4498fa))
<a name="1.3.2"></a>
## 1.3.2 (2013-10-22)
* improve regexp to download latest version ([9040f81](https://github.com/przemyslawpluta/node-youtube-dl/commit/9040f81))
* removed check for query.v that breaks soundcloud functionality ([11da4f7](https://github.com/przemyslawpluta/node-youtube-dl/commit/11da4f7))
* version bump ([60cce67](https://github.com/przemyslawpluta/node-youtube-dl/commit/60cce67))
<a name="1.3.1"></a>
## 1.3.1 (2013-10-15)
* always download latest version of youtube-dl ([c7de217](https://github.com/przemyslawpluta/node-youtube-dl/commit/c7de217))
* fix reading download state ([174743a](https://github.com/przemyslawpluta/node-youtube-dl/commit/174743a))
* formats change :/ ([e6f172d](https://github.com/przemyslawpluta/node-youtube-dl/commit/e6f172d))
* make sure to delete downloaded file ([be74d80](https://github.com/przemyslawpluta/node-youtube-dl/commit/be74d80))
* only download if new version ([1c8211c](https://github.com/przemyslawpluta/node-youtube-dl/commit/1c8211c))
* specify format to download ([429687c](https://github.com/przemyslawpluta/node-youtube-dl/commit/429687c))
* v1.3.1 ([23128d7](https://github.com/przemyslawpluta/node-youtube-dl/commit/23128d7))
<a name="1.3.0"></a>
# 1.3.0 (2013-09-13)
* add getFormats() ([604fa7b](https://github.com/przemyslawpluta/node-youtube-dl/commit/604fa7b))
* some style changes ([08a2ba5](https://github.com/przemyslawpluta/node-youtube-dl/commit/08a2ba5))
* version bump ([1735865](https://github.com/przemyslawpluta/node-youtube-dl/commit/1735865))
<a name="1.2.12"></a>
## 1.2.12 (2013-08-27)
* add id to download info ([eb92288](https://github.com/przemyslawpluta/node-youtube-dl/commit/eb92288))
* better info test ([e4a1b2f](https://github.com/przemyslawpluta/node-youtube-dl/commit/e4a1b2f))
* take into account multi line descriptions ([63ad7c2](https://github.com/przemyslawpluta/node-youtube-dl/commit/63ad7c2))
* version bump ([8625ff4](https://github.com/przemyslawpluta/node-youtube-dl/commit/8625ff4))
<a name="1.2.11"></a>
## 1.2.11 (2013-08-23)
* add id, itag, and resolution to `info()` ([11c7f68](https://github.com/przemyslawpluta/node-youtube-dl/commit/11c7f68))
* version bump ([c5fc896](https://github.com/przemyslawpluta/node-youtube-dl/commit/c5fc896))
<a name="1.2.10"></a>
## 1.2.10 (2013-08-04)
* cleaner example output ([7fcdf8f](https://github.com/przemyslawpluta/node-youtube-dl/commit/7fcdf8f))
* correctly split lines ([13368d1](https://github.com/przemyslawpluta/node-youtube-dl/commit/13368d1))
* update event-stream ([87983c1](https://github.com/przemyslawpluta/node-youtube-dl/commit/87983c1))
* version bump ([b605c93](https://github.com/przemyslawpluta/node-youtube-dl/commit/b605c93))
<a name="1.2.9"></a>
## 1.2.9 (2013-08-04)
* error checking ([524416b](https://github.com/przemyslawpluta/node-youtube-dl/commit/524416b))
* update youtube-dl version ([f4d21ec](https://github.com/przemyslawpluta/node-youtube-dl/commit/f4d21ec))
* version bump ([4fc9e1c](https://github.com/przemyslawpluta/node-youtube-dl/commit/4fc9e1c))
<a name="1.2.8"></a>
## 1.2.8 (2013-05-17)
* [ci skip] ([8af4a1f](https://github.com/przemyslawpluta/node-youtube-dl/commit/8af4a1f))
* check if progress is printed at least once ([189834d](https://github.com/przemyslawpluta/node-youtube-dl/commit/189834d))
* fix tests ([e0895a4](https://github.com/przemyslawpluta/node-youtube-dl/commit/e0895a4))
* minor cosmetics ([af3a82c](https://github.com/przemyslawpluta/node-youtube-dl/commit/af3a82c))
* more thorough tests ([1d96ad2](https://github.com/przemyslawpluta/node-youtube-dl/commit/1d96ad2))
* Release v1.2.8 ([85ca0da](https://github.com/przemyslawpluta/node-youtube-dl/commit/85ca0da))
* update exists method ([1fbfb00](https://github.com/przemyslawpluta/node-youtube-dl/commit/1fbfb00))
* update node versions ([73e93d1](https://github.com/przemyslawpluta/node-youtube-dl/commit/73e93d1))
* update regexp for download progress ([f64ff44](https://github.com/przemyslawpluta/node-youtube-dl/commit/f64ff44))
* update where youtube-dl is downloaded from ([dfe6234](https://github.com/przemyslawpluta/node-youtube-dl/commit/dfe6234))
<a name="1.2.7"></a>
## 1.2.7 (2012-08-19)
* cleanup ([36e8741](https://github.com/przemyslawpluta/node-youtube-dl/commit/36e8741))
* link to ytdl ([fc09348](https://github.com/przemyslawpluta/node-youtube-dl/commit/fc09348))
* Release v1.2.7 ([dafa422](https://github.com/przemyslawpluta/node-youtube-dl/commit/dafa422))
* version bump ([236a4a7](https://github.com/przemyslawpluta/node-youtube-dl/commit/236a4a7))
<a name="1.2.6"></a>
## 1.2.6 (2012-08-01)
* buffer info call ([c46a993](https://github.com/przemyslawpluta/node-youtube-dl/commit/c46a993))
* make sure to delete downloaded file ([5247bdb](https://github.com/przemyslawpluta/node-youtube-dl/commit/5247bdb))
* separate youtubedl stdout by line ([a1b7294](https://github.com/przemyslawpluta/node-youtube-dl/commit/a1b7294))
* version bump ([4f30db8](https://github.com/przemyslawpluta/node-youtube-dl/commit/4f30db8))
<a name="1.2.5"></a>
## 1.2.5 (2012-07-07)
* [fix] path.existsSync was moved to fs.existsSync ([aadc85a](https://github.com/przemyslawpluta/node-youtube-dl/commit/aadc85a))
* added node v0.8 ([a0dc4d8](https://github.com/przemyslawpluta/node-youtube-dl/commit/a0dc4d8))
* existsSync ([876d969](https://github.com/przemyslawpluta/node-youtube-dl/commit/876d969))
* fix existsSync ([24b7db7](https://github.com/przemyslawpluta/node-youtube-dl/commit/24b7db7))
* removed engines ([1e3c85e](https://github.com/przemyslawpluta/node-youtube-dl/commit/1e3c85e))
* use `fs.exists` ([658c651](https://github.com/przemyslawpluta/node-youtube-dl/commit/658c651))
* version bump ([6d678d8](https://github.com/przemyslawpluta/node-youtube-dl/commit/6d678d8))
<a name="1.2.4"></a>
## 1.2.4 (2012-03-10)
* more efficient youtube-dl download ([574cd7f](https://github.com/przemyslawpluta/node-youtube-dl/commit/574cd7f))
* ver bump ([fe10efb](https://github.com/przemyslawpluta/node-youtube-dl/commit/fe10efb))
* ver bump ([3fb0f0e](https://github.com/przemyslawpluta/node-youtube-dl/commit/3fb0f0e))
<a name="1.2.3"></a>
## 1.2.3 (2012-03-04)
* used `__dirname` instead of `./` to save download ([b5fb4bf](https://github.com/przemyslawpluta/node-youtube-dl/commit/b5fb4bf))
* used `path.join` to make it more cross-platform ([05c2ba3](https://github.com/przemyslawpluta/node-youtube-dl/commit/05c2ba3))
<a name="1.2.2"></a>
## 1.2.2 (2012-02-06)
* Better error reporting ([e853b64](https://github.com/przemyslawpluta/node-youtube-dl/commit/e853b64))
<a name="1.2.1"></a>
## 1.2.1 (2012-01-04)
* added test dir ([1695d60](https://github.com/przemyslawpluta/node-youtube-dl/commit/1695d60))
* added test script ([39ecfd6](https://github.com/przemyslawpluta/node-youtube-dl/commit/39ecfd6))
* better formatting ([16ad412](https://github.com/przemyslawpluta/node-youtube-dl/commit/16ad412))
* better versioning ([40d175e](https://github.com/przemyslawpluta/node-youtube-dl/commit/40d175e))
* cleared file ([c30ae25](https://github.com/przemyslawpluta/node-youtube-dl/commit/c30ae25))
* javascript syntax ([42c9fd9](https://github.com/przemyslawpluta/node-youtube-dl/commit/42c9fd9))
* organized readme ([c6069fd](https://github.com/przemyslawpluta/node-youtube-dl/commit/c6069fd))
* removed v0.5 ([ef5e15c](https://github.com/przemyslawpluta/node-youtube-dl/commit/ef5e15c))
* restored ([2ab9779](https://github.com/przemyslawpluta/node-youtube-dl/commit/2ab9779))
* travis ci ([548d808](https://github.com/przemyslawpluta/node-youtube-dl/commit/548d808))
* Written back to Javascript ([0063944](https://github.com/przemyslawpluta/node-youtube-dl/commit/0063944))
<a name="1.2.0"></a>
# 1.2.0 (2011-09-16)
* added filename to data returned ([49909ca](https://github.com/przemyslawpluta/node-youtube-dl/commit/49909ca))
* added tests ([1377915](https://github.com/przemyslawpluta/node-youtube-dl/commit/1377915))
* fixed installation issue ([d05b14c](https://github.com/przemyslawpluta/node-youtube-dl/commit/d05b14c))
* fixed symlink installation issue ([68199c0](https://github.com/przemyslawpluta/node-youtube-dl/commit/68199c0))
<a name="1.1.0"></a>
# 1.1.0 (2011-08-27)
* now uses emitter ([7063855](https://github.com/przemyslawpluta/node-youtube-dl/commit/7063855))
* update ([5c6ff08](https://github.com/przemyslawpluta/node-youtube-dl/commit/5c6ff08))
<a name="1.0.4"></a>
## 1.0.4 (2011-08-07)
* added *.mp4 ([6b7a1dc](https://github.com/przemyslawpluta/node-youtube-dl/commit/6b7a1dc))
* added scripts folder to tasks ([bfa584b](https://github.com/przemyslawpluta/node-youtube-dl/commit/bfa584b))
* added scripts to watch task ([0afc347](https://github.com/przemyslawpluta/node-youtube-dl/commit/0afc347))
* better organized ([dfd57c6](https://github.com/przemyslawpluta/node-youtube-dl/commit/dfd57c6))
* commit ([059d81b](https://github.com/przemyslawpluta/node-youtube-dl/commit/059d81b))
* convenience ([2cb471e](https://github.com/przemyslawpluta/node-youtube-dl/commit/2cb471e))
* fixed error in info function ([ea6ceda](https://github.com/przemyslawpluta/node-youtube-dl/commit/ea6ceda))
* fixed main ([572509b](https://github.com/przemyslawpluta/node-youtube-dl/commit/572509b))
* minimalist ([bb5c5fb](https://github.com/przemyslawpluta/node-youtube-dl/commit/bb5c5fb))
* now requires coffee-script to run ([8be7f53](https://github.com/przemyslawpluta/node-youtube-dl/commit/8be7f53))
* organized ([aeaf9c8](https://github.com/przemyslawpluta/node-youtube-dl/commit/aeaf9c8))
* organized ([2544054](https://github.com/przemyslawpluta/node-youtube-dl/commit/2544054))
* organized ([cbea725](https://github.com/przemyslawpluta/node-youtube-dl/commit/cbea725))
* removed coffeescript from installation ([b5bc9d8](https://github.com/przemyslawpluta/node-youtube-dl/commit/b5bc9d8))
* updated version number ([df8861a](https://github.com/przemyslawpluta/node-youtube-dl/commit/df8861a))
* when finished downloading, statistics data will be passed ([77a99e5](https://github.com/przemyslawpluta/node-youtube-dl/commit/77a99e5))
Copyright (C) 2011 by Roly Fentanes
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
# youtube-dl
[![Build Status](https://travis-ci.org/przemyslawpluta/node-youtube-dl.svg?branch=master)](https://travis-ci.org/przemyslawpluta/node-youtube-dl) [![npm version](https://badge.fury.io/js/youtube-dl.svg)](https://badge.fury.io/js/youtube-dl)
Download videos from youtube in node.js using [youtube-dl](http://rg3.github.com/youtube-dl/).
If you're only interested in downloading only from youtube, you should consider using [pure Javascript youtube downloading module](https://github.com/fent/node-ytdl).
## Installation
With [npm](https://www.npmjs.com/) do:
``` sh
npm install @microlink/youtube-dl
```
## Usage
### Downloading videos
``` js
var fs = require('fs');
var youtubedl = require('youtube-dl');
var video = youtubedl('http://www.youtube.com/watch?v=90AiXO1pAiA',
// Optional arguments passed to youtube-dl.
['--format=18'],
// Additional options can be given for calling `child_process.execFile()`.
{ cwd: __dirname });
// Will be called when the download starts.
video.on('info', function(info) {
console.log('Download started');
console.log('filename: ' + info._filename);
console.log('size: ' + info.size);
});
video.pipe(fs.createWriteStream('myvideo.mp4'));
```
It will produce an output that looks like the following when ran.
```bash
Got video info
saving to T-ara - Number Nine - MV - 티아라-Seku9G1kT0c.mp4
100.00%
```
### Resuming partially downloaded videos
``` js
var youtubedl = require('./');
var fs = require('fs');
var output = 'myvideo.mp4';
var downloaded = 0;
if (fs.existsSync(output)) {
downloaded = fs.statSync(output).size;
}
var video = youtubedl('https://www.youtube.com/watch?v=179MiZSibco',
// Optional arguments passed to youtube-dl.
['--format=18'],
// start will be sent as a range header
{ start: downloaded, cwd: __dirname });
// Will be called when the download starts.
video.on('info', function(info) {
console.log('Download started');
console.log('filename: ' + info._filename);
// info.size will be the amount to download, add
var total = info.size + downloaded;
console.log('size: ' + total);
if (downloaded > 0) {
// size will be the amount already downloaded
console.log('resuming from: ' + downloaded);
// display the remaining bytes to download
console.log('remaining bytes: ' + info.size);
}
});
video.pipe(fs.createWriteStream('myvideo.mp4', { flags: 'a' }));
// Will be called if download was already completed and there is nothing more to download.
video.on('complete', function complete(info) {
'use strict';
console.log('filename: ' + info._filename + ' already downloaded.');
});
video.on('end', function() {
console.log('finished downloading!');
});
```
It will produce an output that looks like the following when ran.
**Output:**
``` sh
[~/nodejs/node-youtube-dl/example]$ node resume.js
Download started
filename: 1 1 1-179MiZSibco.mp4
size: 5109213
^C
```
``` sh
[~/nodejs/node-youtube-dl/example]$ node resume.js
Download started
filename: 1 1 1-179MiZSibco.mp4
size: 5109213
resuming from: 917504
remaining bytes: 4191709
finished downloading
```
### Getting video information
``` js
var youtubedl = require('youtube-dl');
var url = 'http://www.youtube.com/watch?v=WKsjaOqDXgg';
// Optional arguments passed to youtube-dl.
var options = ['--username=user', '--password=hunter2'];
youtubedl.getInfo(url, options, function(err, info) {
if (err) throw err;
console.log('id:', info.id);
console.log('title:', info.title);
console.log('url:', info.url);
console.log('thumbnail:', info.thumbnail);
console.log('description:', info.description);
console.log('filename:', info._filename);
console.log('format id:', info.format_id);
});
```
Running that will produce something like
``` sh
id: WKsjaOqDXgg
title: Ace Rimmer to the Rescue
url: http://r5---sn-p5qlsn7e.c.youtube.com/videoplayback?ms=au&ip=160.79.125.18&cp=U0hWTFVQVl9FTENONl9NSlpDOjgtU1VsODlkVmRH&id=58ab2368ea835e08&source=youtube&expire=1377558202&factor=1.25&key=yt1&ipbits=8&mt=1377534150&itag=34&sver=3&upn=-rGWz2vYpN4&fexp=912306%2C927900%2C919395%2C926518%2C936203%2C913819%2C929117%2C929121%2C929906%2C929907%2C929922%2C929127%2C929129%2C929131%2C929930%2C925726%2C925720%2C925722%2C925718%2C929917%2C906945%2C929919%2C929933%2C912521%2C932306%2C913428%2C904830%2C919373%2C930803%2C908536%2C904122%2C938701%2C936308%2C909549%2C900816%2C912711%2C904494%2C904497%2C900375%2C906001&sparams=algorithm%2Cburst%2Ccp%2Cfactor%2Cid%2Cip%2Cipbits%2Citag%2Csource%2Cupn%2Cexpire&mv=m&burst=40&algorithm=throttle-factor&signature=ABD3A847684AD9B39331E567568D3FA0DCFA4776.7895521E130A042FB3625A17242CE3C02A4460B7&ratebypass=yes
thumbnail: https://i1.ytimg.com/vi/WKsjaOqDXgg/hqdefault.jpg
description: An old Red Dwarf eposide where Ace Rimmer saves the Princess Bonjella.
filename: Ace Rimmer to the Rescue-WKsjaOqDXgg.flv
format id: 34
```
You can use an array of urls to produce an array of response objects with matching array index (e.g. the 1st response object will match the first url etc...)
``` js
var youtubedl = require('youtube-dl');
var url1 = 'http://www.youtube.com/watch?v=WKsjaOqDXgg';
var url2 = 'https://vimeo.com/6586873';
youtubedl.getInfo([url1, url2], function(err, info) {
if (err) throw err;
console.log('title for the url1:', info[0].title);
console.log('title for the url2:', info[1].title);
});
```
### Downloading subtitles
``` js
var youtubedl = require('youtube-dl');
var url = 'https://youtu.be/PizwcirYuGY';
var options = {
// Write automatic subtitle file (youtube only)
auto: false,
// Downloads all the available subtitles.
all: false,
// Languages of subtitles to download, separated by commas.
lang: 'en',
// The directory to save the downloaded files in.
cwd: __dirname,
};
youtubedl.getSubs(url, options, function(err, files) {
if (err) throw err;
console.log('subtitle files downloaded:', files);
});
```
### Downloading thumbnails
``` js
var youtubedl = require('youtube-dl');
var url = 'https://youtu.be/PizwcirYuGY';
var options = {
// Downloads available thumbnail.
all: false,
// The directory to save the downloaded files in.
cwd: __dirname,
};
youtubedl.getThumbs(url, options, function(err, files) {
if (err) throw err;
console.log('thumbnail file downloaded:', files);
});
```
For more usage info on youtube-dl and the arguments you can pass to it, do `youtube-dl -h` or go to the [youtube-dl documentation][].
### Downloading playlists
``` js
var path = require('path');
var fs = require('fs');
var ytdl = require('youtube-dl');
function playlist(url) {
'use strict';
var video = ytdl(url);
video.on('error', function error(err) {
console.log('error 2:', err);
});
var size = 0;
video.on('info', function(info) {
size = info.size;
var output = path.join(__dirname + '/', size + '.mp4');
video.pipe(fs.createWriteStream(output));
});
var pos = 0;
video.on('data', function data(chunk) {
pos += chunk.length;
// `size` should not be 0 here.
if (size) {
var percent = (pos / size * 100).toFixed(2);
process.stdout.cursorTo(0);
process.stdout.clearLine(1);
process.stdout.write(percent + '%');
}
});
video.on('next', playlist);
}
playlist('https://www.youtube.com/playlist?list=PLEFA9E9D96CB7F807');
```
### Getting the list of extractors
``` js
var youtubedl = require('youtube-dl');
youtubedl.getExtractors(true, function(err, list) {
console.log('Found ' + list.length + ' extractors');
for (var i = 0; i < list.length; i++) {
console.log(list[i]);
}
});
```
Will print something like
``` sh
Found 521 extractors
1up.com
220.ro
24video
3sat
```
### Call the `youtube-dl` binary directly
This module doesn't have `youtube-dl` download the video. Instead, it uses the `url` key from the `--dump-json` CLI option to create a node stream. That way, it can be used like any other node stream.
If that, or none of the above support your use case, you can use `ytdl.exec()` to call `youtube-dl` however you like.
``` js
ytdl.exec(url, ['-x', '--audio-format', 'mp3'], {}, function(err, output) {
if (err) throw err;
console.log(output.join('\n'));
});
```
### Update
Since the youtube-dl binary is updated regularly, you can run `npm run update` to check for and download any updates for it. You can also require `../lib/downloader` in your app if you'd like to place `youtube-dl` binary in a specific directory and control when it gets updates.
``` js
var downloader = require('../lib/downloader');
downloader('path/to-binary', function error(err, done) {
'use strict';
if (err) { return console.log(err.stack); }
console.log(done);
});
```
### Tests
Tests are written with [vows](http://vowsjs.org/)
``` sh
npm test
```
## License
MIT
[youtube-dl]: http://rg3.github.com/youtube-dl/
[youtube-dl documentation]: http://rg3.github.com/youtube-dl/documentation.html
{"version":"2019.05.20","path":null,"exec":"youtube-dl.exe"}
\ No newline at end of file
No preview for this file type
var fs = require('fs');
var path = require('path');
var mkdirp = require('mkdirp');
var request = require('request');
// First, look for the download link.
/*jshint maxlen:false */
var dir, filePath;
var isWin = (process.platform === 'win32' || process.env.NODE_PLATFORM === 'windows') ? true : false;
var defaultBin = path.join(__dirname, '..', 'bin');
var defaultPath = path.join(defaultBin, 'details');
var url = 'https://yt-dl.org/downloads/latest/youtube-dl';
function download(url, callback) {
'use strict';
var status = null;
// download the correct version of the binary based on the platform
url = exec(url);
request.get(url, { followRedirect: false }, function (err, res) {
if (res.statusCode !== 302) {
return callback(new Error('Did not get redirect for the latest version link. Status: ' + res.statusCode));
}
var url = res.headers.location;
var downloadFile = request.get(url);
var newVersion = /yt-dl\.org\/downloads\/(\d{4}\.\d\d\.\d\d(\.\d)?)\/youtube-dl/.exec(url)[1];
downloadFile.on('response', function response(res) {
if (res.statusCode !== 200) {
status = new Error('Response Error: ' + res.statusCode);
return;
}
downloadFile.pipe(fs.createWriteStream(filePath, { mode: 493 }));
});
downloadFile.on('error', function error(err) { callback(err); });
downloadFile.on('end', function end() { callback(status, newVersion); });
});
}
function exec(path) {
'use strict';
return (isWin) ? path + '.exe' : path;
}
function createBase(binDir) {
'use strict';
dir = (binDir) ? binDir : defaultBin;
mkdirp.sync(dir);
if (binDir) { mkdirp.sync(defaultBin); }
filePath = path.join(dir, exec('youtube-dl'));
}
function downloader(binDir, callback) {
'use strict';
if (typeof binDir === 'function') {
callback = binDir;
binDir = null;
}
createBase(binDir);
download(url, function error(err, newVersion) {
if (err) { return callback(err); }
fs.writeFileSync(defaultPath, JSON.stringify({ version: newVersion, path: ((binDir) ? filePath : binDir), exec: exec('youtube-dl') }), 'utf8');
callback(null, 'Downloaded youtube-dl ' + newVersion);
});
}
module.exports = downloader;
// Arguments we dont want users to use with youtube-dl
// because they will break the module.
var badArgs = [
'-h', '--help',
'-v', '--version',
'-U', '--update',
'-q', '--quiet',
'-s', '--simulate',
'-g', '--get-url',
'-e', '--get-title',
'--get-id',
'--get-thumbnail',
'--get-description',
'--get-duration',
'--get-filename',
'--get-format',
'-j', '--dump-json',
'--newline',
'--no-progress',
'--console-title',
'-v', '--verbose',
'--dump-intermediate-pages',
'--write-pages',
'--print-traffic',
];
/**
* Helps parse options used in youtube-dl command.
*
* @param {Array.<String>}
* @return {Array.<String>}
*/
exports.parseOpts = function (args) {
var pos;
for (var i = 0, len = badArgs.length; i < len; i++) {
if ((pos = args.indexOf(badArgs[i])) !== -1) {
args.splice(pos, 1);
}
}
return args;
};
/**
* Converts seconds to format hh:mm:ss
*
* @param {Number} seconds
* @return {String}
*/
exports.formatDuration = function (seconds) {
var parts = [];
parts.push(seconds % 60);
var minutes = Math.floor(seconds / 60);
if (minutes > 0) {
parts.push(minutes % 60);
var hours = Math.floor(minutes / 60);
if (hours > 0) {
parts.push(hours);
}
}
return parts.reverse().join(':');
};
'use strict';
const execFile = require('child_process').execFile;
const streamify = require('streamify');
const request = require('request');
const hms = require('hh-mm-ss');
const path = require('path');
const http = require('http');
const url = require('url');
const fs = require('fs');
const util = require('./util');
const TEN_MEGABYTES = 1000 * 1000 * 10;
const execFileOpts = { maxBuffer: TEN_MEGABYTES }
const detailsPath = path.join(__dirname, '..', 'bin/details')
const ytdlBinary = (() => {
if (fs.existsSync(detailsPath)) {
const details = JSON.parse(fs.readFileSync(detailsPath));
return details.path ? details.path : path.resolve(__dirname, '..', 'bin', details.exec);
}
if (!fs.existsSync(ytdlBinary)) {
console.error('ERROR: unable to locate youtube-dl details in ' + path.dirname(ytdlBinary));
process.exit(1);
}
})()
const isWin = (process.platform === 'win32' || process.env.NODE_PLATFORM === 'windows') ? true : false;
const isDebug = /^\[debug\] /;
const isWarning = /^WARNING: /;
const isYouTubeRegex = /^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.be)\//;
const isNoSubsRegex = /WARNING: video doesn't have subtitles|no closed captions found/;
const videoNotAvailable = new RegExp(
'This video is not available|' +
'This video has been removed by the user|' +
'Please sign in to view this video|' +
'This video is no longer available|' +
'The uploader has not made this video available|' +
'This video contains content from'
);
const subsRegex = /--write-sub|--write-srt|--srt-lang|--all-subs/;
function youtubeDl(args, options, callback) {
let passOver = false;
execFile(ytdlBinary, args, { ...execFileOpts, ...options }, function done(err, stdout, stderr) {
if (err) {
if (videoNotAvailable.test(err.message)) passOver = true;
if (!passOver) return callback(err);
}
if (stderr && !passOver) {
// Try once to download video if no subtitles available
if (!options.nosubs && isNoSubsRegex.test(stderr)) {
let i;
let cleanupOpt = args2;
for (i = cleanupOpt.length - 1; i >= 0; i--) {
if (subsRegex.test(cleanupOpt[i])) { cleanupOpt.splice(i, 1); }
}
options.nosubs = true;
return call(video, args1, cleanupOpt, options, callback);
}
if (isDebug.test(stderr) && args.indexOf('--verbose') > -1) {
console.log('\n' + stderr);
} else if (isWarning.test(stderr)) {
console.warn(stderr);
} else {
return callback(new Error(stderr.slice(7)));
}
}
if (passOver && stdout === '' && urls.length > 1) {
urls.shift();
return call(urls, args1, args2, options, callback);
}
return callback(null, stdout.trim().split(/\r?\n/));
})
}
/**
* Processes data
*
* @param {Object} data
* @param {Object} options
* @param {Object} stream
*/
function processData(data, options, stream) {
const item = !data.length ? data : data.shift();
// fix for pause/resume downloads
const headers = { 'Host': url.parse(item.url).hostname };
if (options && options.start > 0) headers.Range = 'bytes=' + options.start + '-';
const req = request({ url: item.url, headers: headers });
req.on('response', function response(res) {
const size = parseInt(res.headers['content-length'], 10);
if (size) item.size = size;
if (options && options.start > 0 && res.statusCode === 416) {
// the file that is being resumed is complete.
return stream.emit('complete', item);
}
if (res.statusCode !== 200 && res.statusCode !== 206) {
return stream.emit('error', new Error('status code ' + res.statusCode));
}
stream.emit('info', item);
stream.on('end', function end() {
if (data.length) stream.emit('next', data);
});
});
return stream.resolve(req);
}
/**
* Downloads a video.
*
* @param {String} videoUrl
* @param {!Array.<String>} args
* @param {!Object} options
*/
const ytdl = module.exports = function (videoUrl, args, options) {
const stream = streamify({ superCtor: http.ClientResponse, readable: true, writable: false });
if (typeof videoUrl !== 'string') {
processData(videoUrl, options, stream);
return stream;
}
ytdl.getInfo(videoUrl, args, options, function getInfo(err, data) {
return err ? stream.emit('error', err) : processData(data, options, stream);
});
return stream;
};
/**
* Calls youtube-dl with some arguments and the `callback`
* gets called with the output.
*
* @param {String|Array.<String>}
* @param {Array.<String>} args
* @param {Array.<String>} args2
* @param {Object} options
* @param {Function(!Error, String)} callback
*/
function call(urls, args1, args2, options = {}, callback) {
let args = args1;
if (args2) args = args.concat(args2);
// set encoding on windows to support unicode titles
if (isWin) {
// check if encoding is already set
let hasEncoding = false;
for (let i = 0; i < args.length; i++) {
if (args[i] === '--encoding') {
hasEncoding = true;
break;
}
}
if (!hasEncoding) {
args.push('--encoding');
args.push('utf8');
}
}
if (urls !== null) {
if (typeof urls === 'string') {
urls = [urls];
}
for (let i = 0; i < urls.length; i++) {
const video = urls[i];
if (isYouTubeRegex.test(video)) {
// Get possible IDs.
const details = url.parse(video, true);
let id = details.query.v || '';
if (id) {
args.push('http://www.youtube.com/watch?v=' + id);
} else {
// Get possible IDs for youtu.be from urladdr.
id = details.pathname.slice(1).replace(/^v\//, '');
if (id) {
args.push(video);
args.unshift('-i');
}
}
} else {
if (i === 0)
args.push('--');
args.push(video);
}
}
}
return youtubeDl(args, options, callback)
}
/**
* Calls youtube-dl with some arguments and the `callback`
* gets called with the output.
*
* @param {String} url
* @param {Array.<String>} args
* @param {Object} options
* @param {Function(!Error, String)} callback
*/
ytdl.exec = function exec(url, args, options, callback) {
return call(url, [], args, options, callback);
};
/**
* @param {Object} data
* @returns {Object}
*/
function parseInfo(data) {
const info = JSON.parse(data);
// Add and process some entries to keep backwards compatibility
Object.defineProperty(info, 'filename', {
get: function get() {
console.warn('`info.filename` is deprecated, use `info._filename`');
return info._filename;
}
});
Object.defineProperty(info, 'itag', {
get: function get() {
console.warn('`info.itag` is deprecated, use `info.format_id`');
return info.format_id;
}
});
Object.defineProperty(info, 'resolution', {
get: function get() {
console.warn('`info.resolution` is deprecated, use `info.format`');
return info.format.split(' - ')[1];
}
});
info._duration_raw = info.duration;
info._duration_hms = (info.duration) ? hms.fromS(info.duration, 'hh:mm:ss') : info.duration;
info.duration = (info.duration) ? util.formatDuration(info.duration) : info.duration;
return info;
}
/**
* Set path from youtube-dl.
*
* @param {String} path
*/
ytdl.setYtdlBinary = function setYtdlBinary(path) {
ytdlBinary = path;
};
/**
* Get path from youtube-dl.
*
* @param {String} path
*/
ytdl.getYtdlBinary = function getYtdlBinary() {
return ytdlBinary;
};
/**
* Gets info from a video.
*
* @param {String} url
* @param {Array.<String>} args
* @param {Object} options
* @param {Function(!Error, Object)} callback
*/
ytdl.getInfo = function getInfo(url, args, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
} else if (typeof args === 'function') {
callback = args;
options = {};
args = [];
}
const defaultArgs = ['--dump-json'];
if (!args || args.indexOf('-f') < 0 && args.indexOf('--format') < 0 &&
args.every(function (a) {
return a.indexOf('--format=') !== 0;
})) {
defaultArgs.push('-f');
defaultArgs.push('best');
}
call(url, defaultArgs, args, options, function done(err, data) {
if (err) return callback(err);
let info;
try {
info = data.map(parseInfo);
} catch (err) {
return callback(err);
}
return callback(null, info.length === 1 ? info[0] : info);
});
};
/**
* @param {String} url
* @param {Object} options
* {Boolean} auto
* {Boolean} all
* {String} lang
* {String} cwd
* @param {Function(!Error, Object)} callback
*/
ytdl.getSubs = function getSubs(url, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
const args = ['--skip-download'];
args.push('--write' + (options.auto ? '-auto' : '') + '-sub');
if (options.all) {
args.push('--all-subs');
}
if (options.lang) {
args.push('--sub-lang=' + options.lang);
}
if (!options.warrning) {
args.push('--no-warnings');
}
call(url, args, [], { cwd: options.cwd }, function (err, data) {
if (err) return callback(err);
const files = [];
for (let i = 0, len = data.length; i < len; i++) {
const line = data[i];
if (line.indexOf('[info] Writing video subtitles to: ') === 0) {
files.push(line.slice(35));
}
}
return callback(null, files);
});
};
/**
* @param {String} url
* @param {Object} options
* {Boolean} all
* {String} cwd
* @param {Function(!Error, Object)} callback
*/
ytdl.getThumbs = function getThumbs(url, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
const args = ['--skip-download'];
if (options.all) {
args.push('--write-all-thumbnails');
} else {
args.push('--write-thumbnail');
}
if (!options.warrning) {
args.push('--no-warnings');
}
call(url, args, [], { cwd: options.cwd }, function (err, data) {
if (err) return callback(err);
const files = [];
for (let i = 0, len = data.length; i < len; i++) {
const line = data[i];
const info = 'Writing thumbnail to: ';
if (line.indexOf(info) !== -1) {
files.push(line.slice(line.indexOf(info) + info.length));
}
}
return callback(null, files);
});
};
/**
* @param {!Boolean} descriptions
* @param {!Object} options
* @param {Function(!Error, Object)} callback
*/
ytdl.getExtractors = function getExtractors(descriptions, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
} else if (typeof descriptions === 'function') {
callback = descriptions;
options = {};
descriptions = false;
}
const args = descriptions ? ['--extractor-descriptions'] : ['--list-extractors'];
return call(null, args, null, options, callback);
};
{
"_from": "youtube-dl",
"_id": "youtube-dl@1.13.1",
"_inBundle": false,
"_integrity": "sha512-89mUKwOavaojNKQlyzW+A7Dph5G/oPYs6T/PTMcvgdRQ5E2+uDQgYPxWHQDMBhHOkxQaxvxQTiTPKQLdg0OI4w==",
"_location": "/youtube-dl",
"_phantomChildren": {},
"_requested": {
"type": "tag",
"registry": true,
"raw": "youtube-dl",
"name": "youtube-dl",
"escapedName": "youtube-dl",
"rawSpec": "",
"saveSpec": null,
"fetchSpec": "latest"
},
"_requiredBy": [
"#USER",
"/"
],
"_resolved": "https://registry.npmjs.org/youtube-dl/-/youtube-dl-1.13.1.tgz",
"_shasum": "2da47c0dad3c5391e2172b7811da46501b82edc4",
"_spec": "youtube-dl",
"_where": "C:\\Users\\user\\Desktop\\오소git\\오소플젝\\Youtube_MPL",
"author": {
"name": "Roly Fentanes",
"url": "https://github.com/fent"
},
"bugs": {
"url": "https://github.com/przemyslawpluta/node-youtube-dl/issues"
},
"bundleDependencies": false,
"contributors": [
{
"name": "Roly Fentanes",
"email": "roly426@gmail.com"
},
{
"name": "przemyslawpluta",
"email": "przemekpluta@hotmail.com"
},
{
"name": "Jay Salvat",
"email": "jay@jaysalvat.com"
},
{
"name": "Kiko Beats",
"email": "josefrancisco.verdu@gmail.com"
},
{
"name": "Jaime Marquínez Ferrándiz",
"email": "jaime.marquinez.ferrandiz@gmail.com"
},
{
"name": "Jay Baker",
"email": "logikal@gmail.com"
},
{
"name": "Jack Li",
"email": "jack.lee2980@gmail.com"
},
{
"name": "Sergey M․",
"email": "dstftw@gmail.com"
},
{
"name": "optikfluffel",
"email": "optik@fluffel.io"
},
{
"name": "EragonJ",
"email": "eragonj@eragonj.me"
},
{
"name": "t3rr0r",
"email": "mail@t3rr0r.com"
},
{
"name": "tifroz",
"email": "hhardel@gmail.com"
},
{
"name": "Jeremy Louie",
"email": "jeremy@jeremylouie.com"
},
{
"name": "Calvin",
"email": "calvin@sealtelecom.com.br"
},
{
"name": "walheresq",
"email": "walheresq@hotmail.com"
},
{
"name": "▟ ▖▟ ▖",
"email": "dodo.the.last@gmail.com"
},
{
"name": "Davide Pastore",
"email": "pasdavide@gmail.com"
},
{
"name": "Farrin Reid",
"email": "blakmatrix@gmail.com"
},
{
"name": "Jason Penny",
"email": "jason@jooraccess.com"
},
{
"name": "Juan C. Olivares",
"email": "cristobal@cxsoftware.com"
},
{
"name": "Lopez Hugo",
"email": "hugo.lpz@gmail.com"
},
{
"name": "Meral",
"email": "meral.harbes@gmail.com"
},
{
"name": "Michael Nguyen",
"email": "tehtotalpwnage@gmail.com"
},
{
"name": "Nicolas Gotchac",
"email": "ngotchac@gmail.com"
},
{
"name": "Parikshit Hooda",
"email": "phooda804@live.com"
},
{
"name": "Pietro",
"email": "pietro.passarelli@gmail.com"
},
{
"name": "Sagi Nadir",
"email": "saginadir@gmail.com"
},
{
"name": "btmdave",
"email": "dave@bluetopmedia.com"
},
{
"name": "coderaiser",
"email": "mnemonic.enemy@gmail.com"
}
],
"dependencies": {
"hh-mm-ss": "~1.2.0",
"mkdirp": "~0.5.1",
"request": "~2.88.0",
"streamify": "~0.2.9"
},
"deprecated": false,
"description": "youtube-dl driver for node",
"devDependencies": {
"vows": "latest"
},
"files": [
"lib",
"scripts"
],
"homepage": "https://github.com/przemyslawpluta/node-youtube-dl#readme",
"keywords": [
"download",
"video",
"youtube"
],
"license": "MIT",
"main": "./lib/youtube-dl.js",
"name": "youtube-dl",
"repository": {
"type": "git",
"url": "git://github.com/przemyslawpluta/node-youtube-dl.git"
},
"scripts": {
"postinstall": "node ./scripts/download.js",
"test": "vows ./test/*.js --spec",
"update": "node ./scripts/download.js"
},
"version": "1.13.1"
}
var downloader = require('../lib/downloader');
downloader(function error(err, done) {
'use strict';
if (err) { return console.log(err.stack); }
console.log(done);
});
language: node_js
node_js:
- node
The MIT License (MIT)
Copyright (c) Feross Aboukhadijeh
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# zero-fill [![build](https://img.shields.io/travis/feross/zero-fill/master.svg)](https://travis-ci.org/feross/zero-fill) [![version](https://img.shields.io/npm/v/zero-fill.svg)](https://npmjs.org/package/zero-fill)
### Zero-fill a number to the given size.
![zero](https://raw.githubusercontent.com/feross/zero-fill/master/img.png)
[![browser support](https://ci.testling.com/feross/zero-fill.png)](https://ci.testling.com/feross/zero-fill)
## install
```
npm install zero-fill
```
## usage
```js
var zeroFill = require('zero-fill')
zeroFill(4, 1) // '0001'
zeroFill(10, 55) // '0000000055'
zeroFill(1, 1) // '1'
```
Partial application:
```js
zeroFill(4)(1) // '0001'
```
Custom padding character:
```js
zeroFill(4, 55, ' ') // ' 55'
zeroFill(4, 500, ' ') // ' 500'
```
## license
MIT. Copyright (c) [Feross Aboukhadijeh](http://feross.org).
/**
* Given a number, return a zero-filled string.
* From http://stackoverflow.com/questions/1267283/
* @param {number} width
* @param {number} number
* @return {string}
*/
module.exports = function zeroFill (width, number, pad) {
if (number === undefined) {
return function (number, pad) {
return zeroFill(width, number, pad)
}
}
if (pad === undefined) pad = '0'
width -= number.toString().length
if (width > 0) return new Array(width + (/\./.test(number) ? 2 : 1)).join(pad) + number
return number + ''
}
{
"_from": "zero-fill@^2.2.3",
"_id": "zero-fill@2.2.3",
"_inBundle": false,
"_integrity": "sha1-o97wa6XjmuZEhQu0yirUEStIVek=",
"_location": "/zero-fill",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "zero-fill@^2.2.3",
"name": "zero-fill",
"escapedName": "zero-fill",
"rawSpec": "^2.2.3",
"saveSpec": null,
"fetchSpec": "^2.2.3"
},
"_requiredBy": [
"/hh-mm-ss"
],
"_resolved": "https://registry.npmjs.org/zero-fill/-/zero-fill-2.2.3.tgz",
"_shasum": "a3def06ba5e39ae644850bb4ca2ad4112b4855e9",
"_spec": "zero-fill@^2.2.3",
"_where": "C:\\Users\\user\\Desktop\\오소git\\오소플젝\\Youtube_MPL\\node_modules\\hh-mm-ss",
"author": {
"name": "Feross Aboukhadijeh",
"email": "feross@feross.org",
"url": "http://feross.org/"
},
"bugs": {
"url": "https://github.com/feross/zero-fill/issues"
},
"bundleDependencies": false,
"dependencies": {},
"deprecated": false,
"description": "Zero-fill a number to the given size.",
"devDependencies": {
"standard": "^6.0.4",
"tape": "^4.4.0"
},
"homepage": "https://github.com/feross/zero-fill#readme",
"keywords": [
"zero",
"zero fill",
"fill",
"zerofill",
"pad",
"0",
"zero pad",
"zeropad",
"string",
"number"
],
"license": "MIT",
"main": "index.js",
"name": "zero-fill",
"repository": {
"type": "git",
"url": "git://github.com/feross/zero-fill.git"
},
"scripts": {
"test": "standard && tape test/*.js"
},
"version": "2.2.3"
}
var zeroFill = require('../')
var test = require('tape')
test('basic use', function (t) {
t.equal(zeroFill(4, 1), '0001')
t.equal(zeroFill(10, 1), '0000000001')
t.equal(zeroFill(10, 55), '0000000055')
t.equal(zeroFill(1, 1), '1')
t.end()
})
test('width edge cases', function (t) {
t.equal(zeroFill(1, 20), '20', 'do not trim string if width is too small')
t.equal(zeroFill(0, 20), '20', 'zero width')
t.equal(zeroFill(0, 1), '1', 'zero width')
t.end()
})
test('partial application', function (t) {
t.equal(zeroFill(4)(1), '0001')
t.equal(zeroFill(10)(1), '0000000001')
t.equal(zeroFill(10)(55), '0000000055')
t.equal(zeroFill(1)(1), '1')
t.equal(zeroFill(3)(1, ' '), ' 1') // custom pad character
t.end()
})
test('custom pad character', function (t) {
t.equal(zeroFill(4, 1, ' '), ' 1')
t.equal(zeroFill(10, 1, 'x'), 'xxxxxxxxx1')
t.equal(zeroFill(10, 55, 'x'), 'xxxxxxxx55')
t.equal(zeroFill(1, 1, 'x'), '1')
t.end()
})
......@@ -2,6 +2,17 @@
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"@microlink/youtube-dl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@microlink/youtube-dl/-/youtube-dl-2.0.0.tgz",
"integrity": "sha512-B2DqRrDHFMu1MsBTq6ZAKR4BtKgvOK91Ci9EQiMVbSGC1/3UIPxpIYP4Py4kzcS94B++zVSMirhnCgX//5Qs4w==",
"requires": {
"hh-mm-ss": "~1.2.0",
"mkdirp": "~0.5.1",
"request": "~2.88.0",
"streamify": "~0.2.9"
}
},
"ajv": {
"version": "6.10.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz",
......@@ -146,6 +157,22 @@
"har-schema": "^2.0.0"
}
},
"hashish": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/hashish/-/hashish-0.0.4.tgz",
"integrity": "sha1-bWC8b/r3Ebav1g5CbQd5iAFOZVQ=",
"requires": {
"traverse": ">=0.2.4"
}
},
"hh-mm-ss": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/hh-mm-ss/-/hh-mm-ss-1.2.0.tgz",
"integrity": "sha512-f4I9Hz1dLpX/3mrEs7yq30+FiuO3tt5NWAqAGeBTaoeoBfB8vhcQ3BphuDc5DjZb/K809agqrAaFlP0jhEU/8w==",
"requires": {
"zero-fill": "^2.2.3"
}
},
"http-signature": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
......@@ -210,6 +237,19 @@
"mime-db": "1.40.0"
}
},
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"requires": {
"minimist": "0.0.8"
}
},
"oauth-sign": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
......@@ -288,6 +328,14 @@
"tweetnacl": "~0.14.0"
}
},
"streamify": {
"version": "0.2.9",
"resolved": "https://registry.npmjs.org/streamify/-/streamify-0.2.9.tgz",
"integrity": "sha512-8pUxeLEef9UO1FxtTt5iikAiyzGI4SZRnGuJ3sz8axZ5Xk+/7ezEV5kuJQsMEFxw7AKYw3xp0Ow+20mmSaJbQQ==",
"requires": {
"hashish": "~0.0.4"
}
},
"tough-cookie": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
......@@ -304,6 +352,11 @@
}
}
},
"traverse": {
"version": "0.6.6",
"resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz",
"integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc="
},
"tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
......@@ -339,6 +392,22 @@
"core-util-is": "1.0.2",
"extsprintf": "^1.2.0"
}
},
"youtube-dl": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/youtube-dl/-/youtube-dl-1.13.1.tgz",
"integrity": "sha512-89mUKwOavaojNKQlyzW+A7Dph5G/oPYs6T/PTMcvgdRQ5E2+uDQgYPxWHQDMBhHOkxQaxvxQTiTPKQLdg0OI4w==",
"requires": {
"hh-mm-ss": "~1.2.0",
"mkdirp": "~0.5.1",
"request": "~2.88.0",
"streamify": "~0.2.9"
}
},
"zero-fill": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/zero-fill/-/zero-fill-2.2.3.tgz",
"integrity": "sha1-o97wa6XjmuZEhQu0yirUEStIVek="
}
}
}
......