hlsdownloader 3.0.2 → 3.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -15
- package/build/index.js +1 -1
- package/package.json +63 -54
package/README.md
CHANGED
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
[ ](https://npmjs.com/package/hlsdownloader)
|
|
25
25
|
[ ](https://npm-stat.com/charts.html?package=hlsdownloader)
|
|
26
26
|
[ ](https://bundlephobia.com/package/hlsdownloader@latest)
|
|
27
|
+
[](https://snyk.io/test/github/nurrony/hlsdownloader)
|
|
27
28
|
<br /> <br />
|
|
28
29
|
|
|
29
30
|
</div>
|
|
@@ -34,21 +35,6 @@
|
|
|
34
35
|
> ⚠️
|
|
35
36
|
> <strong>HLSDownloader `v2.x.x` is no longer maintained and we will not accept any backport requests.</strong>
|
|
36
37
|
|
|
37
|
-
## Table of Contents
|
|
38
|
-
|
|
39
|
-
- [Features](#features)
|
|
40
|
-
- [Prerequisites](#prerequisites)
|
|
41
|
-
- [Installation](#installation)
|
|
42
|
-
- [How to use](#how-to-use)
|
|
43
|
-
- [Advance Usage](#advance-usage)
|
|
44
|
-
- [Running Tests](#running-tests)
|
|
45
|
-
- [Generate Documentations](#generate-documentations)
|
|
46
|
-
- [Authors](#authors)
|
|
47
|
-
- [Contributing](#contributing)
|
|
48
|
-
- [Show your support](#show-your-support)
|
|
49
|
-
- [Special Thanks to](#special-thanks-to)
|
|
50
|
-
- [License](#license)
|
|
51
|
-
|
|
52
38
|
## Features
|
|
53
39
|
|
|
54
40
|
- Retryable
|
package/build/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var R=Object.defineProperty;var a=(e,t)=>R(e,"name",{value:t,configurable:!0});import{createWriteStream as k}from"fs";import{access as x,constants as D,mkdir as E,unlink as v}from"fs/promises";import u from"ky";import U from"p-limit";import{dirname as I,join as f}from"path";import{Readable as C}from"stream";import{URL as T}from"url";var m=class extends Error{static{a(this,"InvalidPlaylist")}constructor(t){super(t),this.name=this.constructor.name,Error.captureStackTrace(this,this.constructor)}},p=m;var d=class extends Error{static{a(this,"ProtocolNotSupported")}constructor(t){super(t),this.name=this.constructor.name,Error.captureStackTrace(this,this.constructor)}},y=d;var P=a((e,t=["http:","https:","ftp:","sftp:"])=>{try{let{protocol:s}=new URL(e);if(s&&!t.includes(`${s}`))throw new y(`${s} is not supported. Supported protocols are ${t.join(", ")}`);return!0}catch(s){throw s}},"isValidUrl"),g=a(e=>e.substring(0,1).replace("/","")+e.substring(1),"stripFirstSlash"),b=a(e=>e.match(/^#EXTM3U/im)!==null,"isValidPlaylist"),O=a(e=>new URL(e),"parseUrl"),S=a((e,...t)=>{let s=new Set(t.flat());return Object.fromEntries(Object.entries(e).filter(([r])=>!s.has(r)))},"omit");var l={isValidPlaylist:b,isValidUrl:P,omit:S,parseUrl:O,stripFirstSlash:g};var V=".m3u8",w=class e{static{a(this,"Downloader")}static defaultKyOptions={retry:{limit:0}};pool=U(1);overwrite=!1;static unSupportedOptions=["uri","url","json","form","body","method","setHost","isStream","parseJson","prefixUrl","cookieJar","playlistURL","concurrency","allowGetBody","stringifyJson","methodRewriting"];items=[];errors=[];concurrency=1;kyOptions={};playlistURL="";destination="";constructor({playlistURL:t,destination:s,concurrency:r=1,overwrite:i,...n}={
|
|
1
|
+
var R=Object.defineProperty;var a=(e,t)=>R(e,"name",{value:t,configurable:!0});import{createWriteStream as k}from"fs";import{access as x,constants as D,mkdir as E,unlink as v}from"fs/promises";import u from"ky";import U from"p-limit";import{dirname as I,join as f}from"path";import{Readable as C}from"stream";import{URL as T}from"url";var m=class extends Error{static{a(this,"InvalidPlaylist")}constructor(t){super(t),this.name=this.constructor.name,Error.captureStackTrace(this,this.constructor)}},p=m;var d=class extends Error{static{a(this,"ProtocolNotSupported")}constructor(t){super(t),this.name=this.constructor.name,Error.captureStackTrace(this,this.constructor)}},y=d;var P=a((e,t=["http:","https:","ftp:","sftp:"])=>{try{let{protocol:s}=new URL(e);if(s&&!t.includes(`${s}`))throw new y(`${s} is not supported. Supported protocols are ${t.join(", ")}`);return!0}catch(s){throw s}},"isValidUrl"),g=a(e=>e.substring(0,1).replace("/","")+e.substring(1),"stripFirstSlash"),b=a(e=>e.match(/^#EXTM3U/im)!==null,"isValidPlaylist"),O=a(e=>new URL(e),"parseUrl"),S=a((e,...t)=>{let s=new Set(t.flat());return Object.fromEntries(Object.entries(e).filter(([r])=>!s.has(r)))},"omit");var l={isValidPlaylist:b,isValidUrl:P,omit:S,parseUrl:O,stripFirstSlash:g};var V=".m3u8",w=class e{static{a(this,"Downloader")}static defaultKyOptions={retry:{limit:0}};pool=U(1);overwrite=!1;static unSupportedOptions=["uri","url","json","form","body","method","setHost","isStream","parseJson","prefixUrl","cookieJar","playlistURL","concurrency","allowGetBody","stringifyJson","methodRewriting"];items=[];errors=[];concurrency=1;kyOptions={};playlistURL="";destination="";constructor({playlistURL:t,destination:s,concurrency:r=1,overwrite:i=!1,...n}={concurrency:1,destination:"",playlistURL:"",overwrite:!1,options:{}}){try{l.isValidUrl(t),this.items=[t],this.playlistURL=t,this.concurrency=r,this.overwrite=i??!1,this.destination=s??"",this.pool=U(r??1),this.kyOptions=this.mergeOptions(n),this.fetchItems=this.fetchItems.bind(this),this.downloadItem=this.downloadItem.bind(this),this.mergeOptions=this.mergeOptions.bind(this),this.fetchPlaylist=this.fetchPlaylist.bind(this),this.startDownload=this.startDownload.bind(this),this.downloadItems=this.downloadItems.bind(this),this.shouldOverwrite=this.shouldOverwrite.bind(this),this.createDirectory=this.createDirectory.bind(this),this.parsePlaylist=this.parsePlaylist.bind(this),this.processPlaylistItems=this.processPlaylistItems.bind(this),this.formatPlaylistContent=this.formatPlaylistContent.bind(this)}catch(h){throw h}}async startDownload(){let{url:t,body:s}=await this.fetchPlaylist(this.playlistURL);if(this.errors.length>0)return{errors:this.errors,message:"Unsuccessful download"};let r=this.parsePlaylist(t,s);this.items=[...this.items,...r];let i=r.filter(o=>o.toLowerCase().endsWith(V)),n=await Promise.allSettled(i.map(o=>this.fetchPlaylist(o)));return r=this.formatPlaylistContent(n).map(o=>this.parsePlaylist(o?.url,o?.body)).flat(),this.items=[...this.items,...r],await this.processPlaylistItems(),this.errors.length>0?{errors:this.errors,total:this.items.length,message:"Download ended with some errors"}:{total:this.items.length,playlistURL:this.playlistURL,message:"Downloaded successfully"}}mergeOptions(t){return Object.assign(e.defaultKyOptions,l.omit(t,...e.unSupportedOptions))}parsePlaylist(t,s){return s.replace(/^#[\s\S].*/gim,"").split(/\r?\n/).reduce((r,i)=>{if(i!==""){let n=new T(i,t).href;r.push(n)}return r},[])}async fetchPlaylist(t){try{let s=await u.get(t,{...this.kyOptions}).text();if(!l.isValidPlaylist(s)){let{name:r,message:i}=new p("Invalid playlist");return this.errors.push({url:t,name:r,message:i}),{url:"",body:""}}return{url:t,body:s}}catch({name:s,message:r}){return this.errors.push({url:t,name:s,message:r}),{url:"",body:""}}}formatPlaylistContent(t){return t.reduce((s,{status:r,value:i})=>(r.toLowerCase()==="fulfilled"&&i&&s.push(i),s),[])}async processPlaylistItems(){return this.destination&&this.downloadItems()||this.fetchItems()}async downloadItem(t){try{let s=await u.get(t,{...this.kyOptions}),r=await this.createDirectory(t),i=C.fromWeb(s.body);return new Promise((n,h)=>{let o=k(r);i.pipe(o),i.on("error",c=>{i.destroy(),o.destroy(),v(r),h(c)}),o.on("finish",()=>{o.close(),n("success")}),o.on("error",c=>{o.destroy(),i.destroy(),h(c)})})}catch({name:s,message:r}){this.errors.push({name:s,message:r,url:t})}}async downloadItems(){try{if(!await this.shouldOverwrite(this.playlistURL)){let s=new Error("directory already exists");throw s.name="EEXIST",s}await this.createDirectory(this.playlistURL);let t=this.items.map(s=>this.pool(this.downloadItem,s));return Promise.allSettled(t)}catch(t){this.errors.push({url:this.playlistURL,name:t.name,message:t.message})}}async fetchItems(){return Promise.allSettled(this.items.map(t=>this.pool(async()=>{try{return await u.get(t,{...this.kyOptions})}catch({name:s,message:r}){this.errors.push({url:t,name:s,message:r})}})))}async createDirectory(t){let{pathname:s}=l.parseUrl(t),r=f(this.destination,I(s));return await E(r,{recursive:!0}),f(this.destination,l.stripFirstSlash(s))}async shouldOverwrite(t){try{let{pathname:s}=l.parseUrl(t),r=f(this.destination,I(s));return await x(r,D.F_OK),this.overwrite}catch(s){if(s.code==="ENOENT")return!0;throw s}}},L=w;var at=L;export{at as default};
|
package/package.json
CHANGED
|
@@ -1,91 +1,100 @@
|
|
|
1
1
|
{
|
|
2
2
|
"author": {
|
|
3
|
-
"name": "Nur Rony",
|
|
4
3
|
"email": "pro.nmrony@gmail.com",
|
|
4
|
+
"name": "Nur Rony",
|
|
5
5
|
"url": "https://nurrony.github.io"
|
|
6
6
|
},
|
|
7
7
|
"bugs": {
|
|
8
8
|
"url": "https://github.com/nurrony/hlsdownloader/issues"
|
|
9
9
|
},
|
|
10
|
-
"
|
|
10
|
+
"config": {
|
|
11
|
+
"commitizen": {
|
|
12
|
+
"path": "cz-conventional-changelog"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"ky": "^1.2.1",
|
|
17
|
+
"p-limit": "^5.0.0"
|
|
18
|
+
},
|
|
11
19
|
"description": "Downloads HLS Playlist file and TS chunks",
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@commitlint/cli": "^18.4.3",
|
|
22
|
+
"@commitlint/config-conventional": "^18.4.3",
|
|
23
|
+
"@types/jest": "^29.5.11",
|
|
24
|
+
"clean-jsdoc-theme": "^4.2.17",
|
|
25
|
+
"esbuild": "^0.19.9",
|
|
26
|
+
"eslint": "^8.56.0",
|
|
27
|
+
"husky": "^8.0.0",
|
|
28
|
+
"jest": "^29.7.0",
|
|
29
|
+
"jsdoc": "^4.0.2",
|
|
30
|
+
"prettier": "^3.1.1",
|
|
31
|
+
"rimraf": "^5.0.5",
|
|
32
|
+
"semantic-release": "22.0.12"
|
|
33
|
+
},
|
|
12
34
|
"engines": {
|
|
13
35
|
"node": ">=18",
|
|
14
36
|
"npm": ">=9"
|
|
15
37
|
},
|
|
38
|
+
"exports": {
|
|
39
|
+
"default": "./build/index.js"
|
|
40
|
+
},
|
|
41
|
+
"files": [
|
|
42
|
+
"build"
|
|
43
|
+
],
|
|
16
44
|
"homepage": "https://nurrony.github.io/hlsdownloader",
|
|
45
|
+
"hooks": {
|
|
46
|
+
"pre-commit": "npm run commitlint ${1} && npm run lint:fix && npm run lint && npm test"
|
|
47
|
+
},
|
|
17
48
|
"keywords": [
|
|
49
|
+
"cdn-priming",
|
|
50
|
+
"chunk",
|
|
51
|
+
"download",
|
|
52
|
+
"download-playlists",
|
|
53
|
+
"downloader",
|
|
18
54
|
"HLS",
|
|
55
|
+
"hlsdownloader",
|
|
56
|
+
"live",
|
|
57
|
+
"livestream",
|
|
19
58
|
"m3u8",
|
|
59
|
+
"m3u8downloader",
|
|
20
60
|
"playlist",
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"m3u8downloader"
|
|
24
|
-
],
|
|
25
|
-
"files": [
|
|
26
|
-
"build"
|
|
61
|
+
"streaming",
|
|
62
|
+
"streaming-video"
|
|
27
63
|
],
|
|
28
|
-
"main": "./build/index.js",
|
|
29
|
-
"exports": {
|
|
30
|
-
"default": "./build/index.js"
|
|
31
|
-
},
|
|
32
64
|
"license": "MIT",
|
|
65
|
+
"main": "./build/index.js",
|
|
33
66
|
"name": "hlsdownloader",
|
|
67
|
+
"release": {
|
|
68
|
+
"branches": [
|
|
69
|
+
"master"
|
|
70
|
+
],
|
|
71
|
+
"debug": true
|
|
72
|
+
},
|
|
34
73
|
"repository": {
|
|
35
74
|
"type": "git+https",
|
|
36
75
|
"url": "git+https://github.com/nurrony/hlsdownloader.git"
|
|
37
76
|
},
|
|
38
77
|
"scripts": {
|
|
39
|
-
"semantic-release": "semantic-release",
|
|
40
|
-
"prepublishOnly": "npm run build",
|
|
41
78
|
"build": "npm run lint:fix && npm run lint && npm test && npm run build:clean && npm run compile && echo '📦 Build artifact has been generated successfully.'",
|
|
42
|
-
"coverage": "NODE_OPTIONS=--experimental-vm-modules npx jest --coverage",
|
|
43
|
-
"prepare": "husky install",
|
|
44
79
|
"build:clean": "rimraf -fr build && echo '🧹 Build artifacts has been cleaned.'",
|
|
80
|
+
"commitlint": "NODE_OPTIONS=--experimental-vm-modules npx commitlint --edit && echo '🔖 Commit message guidelines are followed properly.'",
|
|
45
81
|
"compile": "npx esbuild --outdir=build --platform=node --format=esm --target=node18 --packages=external --bundle --minify --tree-shaking=true --keep-names src/index.js",
|
|
46
|
-
"
|
|
82
|
+
"coverage": "NODE_OPTIONS=--experimental-vm-modules npx jest --coverage",
|
|
47
83
|
"docs:clean": "rimraf -fr ./docs && echo '🧹 All docs has been cleaned.'",
|
|
84
|
+
"docs:gen": "npm run docs:clean && NODE_OPTIONS=--experimental-vm-modules jsdoc -c jsdoc.json && echo '📄 Docs has been generated successfully.'",
|
|
85
|
+
"example": "NODE_OPTIONS=--experimental-vm-modules node example.mjs",
|
|
48
86
|
"lint": "eslint . --ext .js && echo '💄 Coding style guideline has been followed properly.'",
|
|
49
87
|
"lint:fix": "eslint . --ext .js --fix && echo '🔧 Coding style has been fixed as per guideline.'",
|
|
88
|
+
"prepare": "husky install",
|
|
89
|
+
"prepublishOnly": "npm run build",
|
|
50
90
|
"prod:start": "node index.js",
|
|
51
|
-
"
|
|
91
|
+
"semantic-release": "semantic-release",
|
|
52
92
|
"test": "npm run test:coverage:clean && NODE_OPTIONS=--experimental-vm-modules npx jest",
|
|
53
|
-
"
|
|
93
|
+
"test:coverage:clean": "rimraf -fr ./coverage && echo '🧹 All test coverage reports has been cleaned.'",
|
|
54
94
|
"test:watch": "NODE_OPTIONS=--experimental-vm-modules npx jest --no-cache --watch",
|
|
55
|
-
"version": "echo $npm_package_version"
|
|
56
|
-
"commitlint": "NODE_OPTIONS=--experimental-vm-modules npx commitlint --edit && echo '🔖 Commit message guidelines are followed properly.'"
|
|
57
|
-
},
|
|
58
|
-
"config": {
|
|
59
|
-
"commitizen": {
|
|
60
|
-
"path": "cz-conventional-changelog"
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
"release": {
|
|
64
|
-
"debug": true,
|
|
65
|
-
"branches": [
|
|
66
|
-
"master"
|
|
67
|
-
]
|
|
95
|
+
"version": "echo $npm_package_version"
|
|
68
96
|
},
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
|
|
72
|
-
"@commitlint/config-conventional": "^18.4.3",
|
|
73
|
-
"@types/jest": "^29.5.11",
|
|
74
|
-
"clean-jsdoc-theme": "^4.2.17",
|
|
75
|
-
"esbuild": "^0.19.9",
|
|
76
|
-
"eslint": "^8.56.0",
|
|
77
|
-
"husky": "^8.0.0",
|
|
78
|
-
"jest": "^29.7.0",
|
|
79
|
-
"jsdoc": "^4.0.2",
|
|
80
|
-
"prettier": "^3.1.1",
|
|
81
|
-
"rimraf": "^5.0.5",
|
|
82
|
-
"semantic-release": "22.0.12"
|
|
83
|
-
},
|
|
84
|
-
"hooks": {
|
|
85
|
-
"pre-commit": "npm run commitlint ${1} && npm run lint:fix && npm run lint && npm test"
|
|
86
|
-
},
|
|
87
|
-
"dependencies": {
|
|
88
|
-
"ky": "^1.1.3",
|
|
89
|
-
"p-limit": "^5.0.0"
|
|
90
|
-
}
|
|
97
|
+
"snyk": true,
|
|
98
|
+
"type": "module",
|
|
99
|
+
"version": "3.0.4"
|
|
91
100
|
}
|