From b91c83c9f92018a58df118dcadd63e9542e31a52 Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Mon, 16 Aug 2021 18:01:28 +0530 Subject: [PATCH 1/9] Package updated --- package-lock.json | 132 ---------------------------------------------- package.json | 3 -- 2 files changed, 135 deletions(-) diff --git a/package-lock.json b/package-lock.json index 976dde9..67dbce5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,9 +10,6 @@ "license": "MIT", "dependencies": { "got": "^11.8.2" - }, - "devDependencies": { - "@types/node-fetch": "^2.5.12" } }, "node_modules/@sindresorhus/is": { @@ -66,16 +63,6 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-16.4.13.tgz", "integrity": "sha512-bLL69sKtd25w7p1nvg9pigE4gtKVpGTPojBFLMkGHXuUgap2sLqQt2qUnqmVCDfzGUL0DRNZP+1prIZJbMeAXg==" }, - "node_modules/@types/node-fetch": { - "version": "2.5.12", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.12.tgz", - "integrity": "sha512-MKgC4dlq4kKNa/mYrwpKfzQMB5X3ee5U6fSprkKpToBqBmX4nFZL9cW5jl6sWn+xpRJ7ypWh2yyqqr8UUCstSw==", - "dev": true, - "dependencies": { - "@types/node": "*", - "form-data": "^3.0.0" - } - }, "node_modules/@types/responselike": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", @@ -84,12 +71,6 @@ "@types/node": "*" } }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, "node_modules/cacheable-lookup": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", @@ -123,18 +104,6 @@ "mimic-response": "^1.0.0" } }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/decompress-response": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", @@ -168,15 +137,6 @@ "node": ">=10" } }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -185,20 +145,6 @@ "once": "^1.4.0" } }, - "node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/get-stream": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", @@ -275,27 +221,6 @@ "node": ">=8" } }, - "node_modules/mime-db": { - "version": "1.49.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz", - "integrity": "sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.32", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.32.tgz", - "integrity": "sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==", - "dev": true, - "dependencies": { - "mime-db": "1.49.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/mimic-response": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", @@ -413,16 +338,6 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-16.4.13.tgz", "integrity": "sha512-bLL69sKtd25w7p1nvg9pigE4gtKVpGTPojBFLMkGHXuUgap2sLqQt2qUnqmVCDfzGUL0DRNZP+1prIZJbMeAXg==" }, - "@types/node-fetch": { - "version": "2.5.12", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.12.tgz", - "integrity": "sha512-MKgC4dlq4kKNa/mYrwpKfzQMB5X3ee5U6fSprkKpToBqBmX4nFZL9cW5jl6sWn+xpRJ7ypWh2yyqqr8UUCstSw==", - "dev": true, - "requires": { - "@types/node": "*", - "form-data": "^3.0.0" - } - }, "@types/responselike": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", @@ -431,12 +346,6 @@ "@types/node": "*" } }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, "cacheable-lookup": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", @@ -464,15 +373,6 @@ "mimic-response": "^1.0.0" } }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, "decompress-response": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", @@ -493,12 +393,6 @@ "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==" }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, "end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -507,17 +401,6 @@ "once": "^1.4.0" } }, - "form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, "get-stream": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", @@ -576,21 +459,6 @@ "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" }, - "mime-db": { - "version": "1.49.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz", - "integrity": "sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==", - "dev": true - }, - "mime-types": { - "version": "2.1.32", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.32.tgz", - "integrity": "sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==", - "dev": true, - "requires": { - "mime-db": "1.49.0" - } - }, "mimic-response": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", diff --git a/package.json b/package.json index 1999ec3..26aa97c 100644 --- a/package.json +++ b/package.json @@ -33,8 +33,5 @@ ], "dependencies": { "got": "^11.8.2" - }, - "devDependencies": { - "@types/node-fetch": "^2.5.12" } } From fbd4d2aaf997aca0e4a6e32d225aead063657050 Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Tue, 17 Aug 2021 11:39:04 +0530 Subject: [PATCH 2/9] Retry FIX --- package-lock.json | 4 ++-- package.json | 2 +- play-dl/YouTube/stream.ts | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 67dbce5..4b4e244 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "play-dl", - "version": "0.1.0", + "version": "0.1.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "play-dl", - "version": "0.1.0", + "version": "0.1.1", "license": "MIT", "dependencies": { "got": "^11.8.2" diff --git a/package.json b/package.json index 26aa97c..6769990 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "play-dl", - "version": "0.1.0", + "version": "0.1.1", "description": "YouTube, SoundCloud, Spotify downloader", "main": "dist/index.js", "typings": "dist/index.d.ts", diff --git a/play-dl/YouTube/stream.ts b/play-dl/YouTube/stream.ts index 7150527..5aa38de 100644 --- a/play-dl/YouTube/stream.ts +++ b/play-dl/YouTube/stream.ts @@ -83,5 +83,7 @@ export async function stream(url : string, options? : StreamOptions){ final.push(info.format[info.format.length - 1]) } - return got.stream(final[0].url) + return got.stream(final[0].url, { + retry : 5, + }) } \ No newline at end of file From 06ebe8e9c7ca14c874fc9f93e1efb7868a4caf1e Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Tue, 17 Aug 2021 11:50:50 +0530 Subject: [PATCH 3/9] Added some reconnection - logic --- package-lock.json | 4 ++-- package.json | 2 +- play-dl/YouTube/stream.ts | 5 +++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4b4e244..b025d43 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "play-dl", - "version": "0.1.1", + "version": "0.1.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "play-dl", - "version": "0.1.1", + "version": "0.1.2", "license": "MIT", "dependencies": { "got": "^11.8.2" diff --git a/package.json b/package.json index 6769990..16796e8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "play-dl", - "version": "0.1.1", + "version": "0.1.2", "description": "YouTube, SoundCloud, Spotify downloader", "main": "dist/index.js", "typings": "dist/index.d.ts", diff --git a/play-dl/YouTube/stream.ts b/play-dl/YouTube/stream.ts index 5aa38de..43427f6 100644 --- a/play-dl/YouTube/stream.ts +++ b/play-dl/YouTube/stream.ts @@ -85,5 +85,10 @@ export async function stream(url : string, options? : StreamOptions){ return got.stream(final[0].url, { retry : 5, + headers: { + 'Connection': 'keep-alive', + 'Accept-Encoding': '', + 'Accept-Language': 'en-US,en;q=0.8' + } }) } \ No newline at end of file From 102ec0a59546e1c754b5ba5ba941156b2ac5fb0d Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Tue, 17 Aug 2021 12:52:49 +0530 Subject: [PATCH 4/9] Reconnect FIX --- package-lock.json | 4 ++-- package.json | 2 +- play-dl/YouTube/stream.ts | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index b025d43..ea9f4a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "play-dl", - "version": "0.1.2", + "version": "0.1.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "play-dl", - "version": "0.1.2", + "version": "0.1.3", "license": "MIT", "dependencies": { "got": "^11.8.2" diff --git a/package.json b/package.json index 16796e8..d6578eb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "play-dl", - "version": "0.1.2", + "version": "0.1.3", "description": "YouTube, SoundCloud, Spotify downloader", "main": "dist/index.js", "typings": "dist/index.d.ts", diff --git a/play-dl/YouTube/stream.ts b/play-dl/YouTube/stream.ts index 43427f6..f6e9b55 100644 --- a/play-dl/YouTube/stream.ts +++ b/play-dl/YouTube/stream.ts @@ -89,6 +89,7 @@ export async function stream(url : string, options? : StreamOptions){ 'Connection': 'keep-alive', 'Accept-Encoding': '', 'Accept-Language': 'en-US,en;q=0.8' - } + }, + http2 : true }) } \ No newline at end of file From 53cc95586168f4777d2c78d1997569a549ac2315 Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Tue, 17 Aug 2021 14:14:29 +0530 Subject: [PATCH 5/9] Agent added --- package-lock.json | 91 ++++++++++++++++++++++++++++++++++++++- package.json | 3 +- play-dl/YouTube/stream.ts | 5 ++- 3 files changed, 95 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index ea9f4a8..6145af9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,14 +1,15 @@ { "name": "play-dl", - "version": "0.1.3", + "version": "0.1.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "play-dl", - "version": "0.1.3", + "version": "0.1.4", "license": "MIT", "dependencies": { + "agentkeepalive": "^4.1.4", "got": "^11.8.2" } }, @@ -71,6 +72,19 @@ "@types/node": "*" } }, + "node_modules/agentkeepalive": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.1.4.tgz", + "integrity": "sha512-+V/rGa3EuU74H6wR04plBb7Ks10FbtUQgRj/FQOG7uUIEuaINI+AiqJR1k6t3SVNs7o7ZjIdus6706qqzVq8jQ==", + "dependencies": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/cacheable-lookup": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", @@ -104,6 +118,22 @@ "mimic-response": "^1.0.0" } }, + "node_modules/debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/decompress-response": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", @@ -137,6 +167,14 @@ "node": ">=10" } }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -200,6 +238,14 @@ "node": ">=10.19.0" } }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", + "dependencies": { + "ms": "^2.0.0" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -229,6 +275,11 @@ "node": ">=4" } }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "node_modules/normalize-url": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", @@ -346,6 +397,16 @@ "@types/node": "*" } }, + "agentkeepalive": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.1.4.tgz", + "integrity": "sha512-+V/rGa3EuU74H6wR04plBb7Ks10FbtUQgRj/FQOG7uUIEuaINI+AiqJR1k6t3SVNs7o7ZjIdus6706qqzVq8jQ==", + "requires": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + } + }, "cacheable-lookup": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", @@ -373,6 +434,14 @@ "mimic-response": "^1.0.0" } }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "requires": { + "ms": "2.1.2" + } + }, "decompress-response": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", @@ -393,6 +462,11 @@ "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==" }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, "end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -441,6 +515,14 @@ "resolve-alpn": "^1.0.0" } }, + "humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", + "requires": { + "ms": "^2.0.0" + } + }, "json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -464,6 +546,11 @@ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "normalize-url": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", diff --git a/package.json b/package.json index d6578eb..b3d0199 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "play-dl", - "version": "0.1.3", + "version": "0.1.4", "description": "YouTube, SoundCloud, Spotify downloader", "main": "dist/index.js", "typings": "dist/index.d.ts", @@ -32,6 +32,7 @@ "dist/*" ], "dependencies": { + "agentkeepalive": "^4.1.4", "got": "^11.8.2" } } diff --git a/play-dl/YouTube/stream.ts b/play-dl/YouTube/stream.ts index f6e9b55..b462312 100644 --- a/play-dl/YouTube/stream.ts +++ b/play-dl/YouTube/stream.ts @@ -1,6 +1,6 @@ import got from "got" import { video_info } from "." - +import agent from 'agentkeepalive' interface FilterOptions { averagebitrate? : number; @@ -90,6 +90,9 @@ export async function stream(url : string, options? : StreamOptions){ 'Accept-Encoding': '', 'Accept-Language': 'en-US,en;q=0.8' }, + agent : { + https : new agent.HttpsAgent() + }, http2 : true }) } \ No newline at end of file From 0e979067ee08f66f5ed5f739e0977fb4616688be Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Tue, 17 Aug 2021 15:04:16 +0530 Subject: [PATCH 6/9] Added some more for reconnection in Linux --- package-lock.json | 4 ++-- package.json | 2 +- play-dl/YouTube/stream.ts | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6145af9..4f84b69 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "play-dl", - "version": "0.1.4", + "version": "0.1.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "play-dl", - "version": "0.1.4", + "version": "0.1.5", "license": "MIT", "dependencies": { "agentkeepalive": "^4.1.4", diff --git a/package.json b/package.json index b3d0199..2ec2d9b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "play-dl", - "version": "0.1.4", + "version": "0.1.5", "description": "YouTube, SoundCloud, Spotify downloader", "main": "dist/index.js", "typings": "dist/index.d.ts", diff --git a/play-dl/YouTube/stream.ts b/play-dl/YouTube/stream.ts index b462312..be2f728 100644 --- a/play-dl/YouTube/stream.ts +++ b/play-dl/YouTube/stream.ts @@ -88,7 +88,8 @@ export async function stream(url : string, options? : StreamOptions){ headers: { 'Connection': 'keep-alive', 'Accept-Encoding': '', - 'Accept-Language': 'en-US,en;q=0.8' + 'Accept-Language': 'en-US,en;q=0.8', + 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36' }, agent : { https : new agent.HttpsAgent() From a712ef732a559c52720ce74f8db46ba4a47894d9 Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Tue, 17 Aug 2021 21:16:58 +0530 Subject: [PATCH 7/9] Stream Fixed --- package-lock.json | 91 +-------------------------------- package.json | 3 +- play-dl/YouTube/stream.ts | 13 +++-- play-dl/YouTube/utils/cipher.ts | 4 +- 4 files changed, 14 insertions(+), 97 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4f84b69..697e707 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,14 @@ { "name": "play-dl", - "version": "0.1.5", + "version": "0.1.6", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "play-dl", - "version": "0.1.5", + "version": "0.1.6", "license": "MIT", "dependencies": { - "agentkeepalive": "^4.1.4", "got": "^11.8.2" } }, @@ -72,19 +71,6 @@ "@types/node": "*" } }, - "node_modules/agentkeepalive": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.1.4.tgz", - "integrity": "sha512-+V/rGa3EuU74H6wR04plBb7Ks10FbtUQgRj/FQOG7uUIEuaINI+AiqJR1k6t3SVNs7o7ZjIdus6706qqzVq8jQ==", - "dependencies": { - "debug": "^4.1.0", - "depd": "^1.1.2", - "humanize-ms": "^1.2.1" - }, - "engines": { - "node": ">= 8.0.0" - } - }, "node_modules/cacheable-lookup": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", @@ -118,22 +104,6 @@ "mimic-response": "^1.0.0" } }, - "node_modules/debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/decompress-response": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", @@ -167,14 +137,6 @@ "node": ">=10" } }, - "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -238,14 +200,6 @@ "node": ">=10.19.0" } }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", - "dependencies": { - "ms": "^2.0.0" - } - }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -275,11 +229,6 @@ "node": ">=4" } }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, "node_modules/normalize-url": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", @@ -397,16 +346,6 @@ "@types/node": "*" } }, - "agentkeepalive": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.1.4.tgz", - "integrity": "sha512-+V/rGa3EuU74H6wR04plBb7Ks10FbtUQgRj/FQOG7uUIEuaINI+AiqJR1k6t3SVNs7o7ZjIdus6706qqzVq8jQ==", - "requires": { - "debug": "^4.1.0", - "depd": "^1.1.2", - "humanize-ms": "^1.2.1" - } - }, "cacheable-lookup": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", @@ -434,14 +373,6 @@ "mimic-response": "^1.0.0" } }, - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "requires": { - "ms": "2.1.2" - } - }, "decompress-response": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", @@ -462,11 +393,6 @@ "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==" }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" - }, "end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -515,14 +441,6 @@ "resolve-alpn": "^1.0.0" } }, - "humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", - "requires": { - "ms": "^2.0.0" - } - }, "json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -546,11 +464,6 @@ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, "normalize-url": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", diff --git a/package.json b/package.json index 2ec2d9b..341bf67 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "play-dl", - "version": "0.1.5", + "version": "0.1.6", "description": "YouTube, SoundCloud, Spotify downloader", "main": "dist/index.js", "typings": "dist/index.d.ts", @@ -32,7 +32,6 @@ "dist/*" ], "dependencies": { - "agentkeepalive": "^4.1.4", "got": "^11.8.2" } } diff --git a/play-dl/YouTube/stream.ts b/play-dl/YouTube/stream.ts index be2f728..4607c9b 100644 --- a/play-dl/YouTube/stream.ts +++ b/play-dl/YouTube/stream.ts @@ -1,6 +1,7 @@ import got from "got" import { video_info } from "." -import agent from 'agentkeepalive' +import { PassThrough } from 'stream' +import https from 'https' interface FilterOptions { averagebitrate? : number; @@ -44,7 +45,7 @@ function parseFormats(formats : any[]): { audio: any[], video:any[] } { function filter_songs(formats : any[], options : FilterOptions) { } -export async function stream(url : string, options? : StreamOptions){ +export async function stream(url : string, options? : StreamOptions): Promise{ let info = await video_info(url) let final: any[] = []; @@ -83,7 +84,7 @@ export async function stream(url : string, options? : StreamOptions){ final.push(info.format[info.format.length - 1]) } - return got.stream(final[0].url, { + let stream = got.stream(final[0].url, { retry : 5, headers: { 'Connection': 'keep-alive', @@ -92,8 +93,12 @@ export async function stream(url : string, options? : StreamOptions){ 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36' }, agent : { - https : new agent.HttpsAgent() + https : new https.Agent({ keepAlive : true }) }, http2 : true }) + let playing_stream = new PassThrough({ highWaterMark: 10 * 1000 * 1000 }) + + stream.pipe(playing_stream) + return playing_stream } \ No newline at end of file diff --git a/play-dl/YouTube/utils/cipher.ts b/play-dl/YouTube/utils/cipher.ts index 0c2cb98..214b692 100644 --- a/play-dl/YouTube/utils/cipher.ts +++ b/play-dl/YouTube/utils/cipher.ts @@ -1,6 +1,6 @@ -import { URL } from 'node:url' +import { URL } from 'url' import { url_get } from './request' -import querystring from 'node:querystring' +import querystring from 'querystring' interface formatOptions { url? : string; From 5783275bf664a950e7d2f31a1a2a5c1149154dc8 Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Wed, 18 Aug 2021 17:11:37 +0530 Subject: [PATCH 8/9] Thumbnail Fix --- play-dl/YouTube/stream.ts | 127 +++++++++++++++-------------- play-dl/YouTube/utils/extractor.ts | 6 +- 2 files changed, 68 insertions(+), 65 deletions(-) diff --git a/play-dl/YouTube/stream.ts b/play-dl/YouTube/stream.ts index 4607c9b..a254ca6 100644 --- a/play-dl/YouTube/stream.ts +++ b/play-dl/YouTube/stream.ts @@ -3,88 +3,75 @@ import { video_info } from "." import { PassThrough } from 'stream' import https from 'https' -interface FilterOptions { - averagebitrate? : number; - videoQuality? : "144p" | "240p" | "360p" | "480p" | "720p" | "1080p"; - audioQuality? : "AUDIO_QUALITY_LOW" | "AUDIO_QUALITY_MEDIUM"; - audioSampleRate? : number; - audioChannels? : number; - audioCodec? : string; - audioContainer? : string; - hasAudio? : boolean; - hasVideo? : boolean; - isLive? : boolean; -} interface StreamOptions { - filter : "bestaudio" | "bestvideo" + filter : "bestaudio" | "bestvideo" | "live" } -function parseFormats(formats : any[]): { audio: any[], video:any[] } { - let audio: any[] = [] - let video: any[] = [] +function parseAudioFormats(formats : any[]){ + let result: any[] = [] formats.forEach((format) => { let type = format.mimeType as string if(type.startsWith('audio')){ - format.audioCodec = type.split('codecs="')[1].split('"')[0] - format.audioContainer = type.split('audio/')[1].split(';')[0] - format.hasAudio = true - format.hasVideo = false - audio.push(format) - } - else if(type.startsWith('video')){ - format.videoQuality = format.qualityLabel - format.hasAudio = false - format.hasVideo = true - video.push(format) + format.codec = type.split('codecs="')[1].split('"')[0] + format.container = type.split('audio/')[1].split(';')[0] + result.push(format) } }) - return { audio, video } + return result } -function filter_songs(formats : any[], options : FilterOptions) { +function parseVideoFormats(formats : any[]){ + let result: any[] = [] + formats.forEach((format) => { + let type = format.mimeType as string + if(type.startsWith('audio')){ + format.codec = type.split('codecs="')[1].split('"')[0] + format.container = type.split('audio/')[1].split(';')[0] + result.push(format) + } + }) + return result } export async function stream(url : string, options? : StreamOptions): Promise{ let info = await video_info(url) let final: any[] = []; - if(options?.filter === 'bestaudio'){ - info.format.forEach((format) => { - let type = format.mimeType as string - if(type.startsWith('audio/webm')){ - return final.push(format) - } - else return - }) + if(info.video_details.live === true && options) { + options.filter = "live" + } - if(final.length === 0){ - info.format.forEach((format) => { - let type = format.mimeType as string - if(type.startsWith('audio/')){ - return final.push(format) + if(options?.filter){ + switch(options.filter){ + case "bestaudio": + let audioFormat = parseAudioFormats(info.format) + if(audioFormat.length === 0) await stream(url, { filter : "bestvideo" }) + let opusFormats = filterFormat(audioFormat, "opus") + if(opusFormats.length === 0){ + final.push(audioFormat[audioFormat.length - 1]) } - else return - }) + else{ + final.push(opusFormats[opusFormats.length - 1]) + } + break + case "bestvideo" : + let videoFormat = parseVideoFormats(info.format) + if(videoFormat.length === 0) throw new Error('Can\'t Find Video Formats ') + let qual_1080 = filterVideo(videoFormat, "1080p") + if(qual_1080.length === 0) { + let qual_720 = filterVideo(videoFormat, "720p") + if(qual_720.length === 0) final.push(videoFormat[0]) + else final.push(qual_720) + break + } + else final.push(qual_1080) + break + } } - else if(options?.filter === 'bestvideo'){ - info.format.forEach((format) => { - let type = format.mimeType as string - if(type.startsWith('video/')){ - if(parseInt(format.qualityLabel) > 480) final.push(format) - else return - } - else return - }) - - if(final.length === 0) throw new Error("Video Format > 480p is not found") - } - else{ - final.push(info.format[info.format.length - 1]) - } - - let stream = got.stream(final[0].url, { + if(final.length === 0) final.push(info.format[info.format.length - 1]) + let piping_stream = got.stream(final[0].url, { retry : 5, headers: { 'Connection': 'keep-alive', @@ -99,6 +86,22 @@ export async function stream(url : string, options? : StreamOptions): Promise { + if(format.codec === codec) result.push(format) + }) + return result +} + +function filterVideo(formats : any[], quality : string) { + let result: any[] = [] + formats.forEach((format) => { + if(format.qualityLabel === quality) result.push(format) + }) + return result } \ No newline at end of file diff --git a/play-dl/YouTube/utils/extractor.ts b/play-dl/YouTube/utils/extractor.ts index 58bad70..c5350cf 100644 --- a/play-dl/YouTube/utils/extractor.ts +++ b/play-dl/YouTube/utils/extractor.ts @@ -16,8 +16,6 @@ export async function video_basic_info(url : string){ if(player_response.playabilityStatus.status === 'ERROR') throw new Error(`While getting info from url \n ${player_response.playabilityStatus.reason}`) let html5player = 'https://www.youtube.com' + body.split('"jsUrl":"')[1].split('"')[0] let format = [] - format.push(player_response.streamingData.formats[0]) - format.push(...player_response.streamingData.adaptiveFormats) let vid = player_response.videoDetails let microformat = player_response.microformat.playerMicroformatRenderer let video_details = { @@ -30,7 +28,7 @@ export async function video_basic_info(url : string){ thumbnail : { width : vid.thumbnail.thumbnails[vid.thumbnail.thumbnails.length - 1].width, height : vid.thumbnail.thumbnails[vid.thumbnail.thumbnails.length - 1].height, - url : `https://i.ytimg.com/vi/${vid.videoId}/maxresdefault.jpg` + url : vid.thumbnail.thumbnails[vid.thumbnail.thumbnails.length - 1].url, }, channel : { name : vid.author, @@ -43,6 +41,8 @@ export async function video_basic_info(url : string){ live : vid.isLiveContent, private : vid.isPrivate } + if(!video_details.live) format.push(player_response.streamingData.formats[0]) + format.push(...player_response.streamingData.adaptiveFormats) return { html5player, format, From ad1ad2b918d46499b09cc329feb3afc2d761f140 Mon Sep 17 00:00:00 2001 From: killer069 <65385476+killer069@users.noreply.github.com> Date: Fri, 20 Aug 2021 12:06:12 +0530 Subject: [PATCH 9/9] LiveStream Support --- package-lock.json | 4 +- package.json | 2 +- play-dl/YouTube/classes/LiveStream.ts | 139 +++++++++++++++++++++++++ play-dl/YouTube/index.ts | 4 +- play-dl/YouTube/stream.ts | 142 +++++++++++++++++--------- play-dl/YouTube/utils/extractor.ts | 33 +++++- play-dl/YouTube/utils/request.ts | 1 - play-dl/index.ts | 4 +- 8 files changed, 269 insertions(+), 60 deletions(-) create mode 100644 play-dl/YouTube/classes/LiveStream.ts diff --git a/package-lock.json b/package-lock.json index 697e707..78e1b4a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "play-dl", - "version": "0.1.6", + "version": "0.1.7", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "play-dl", - "version": "0.1.6", + "version": "0.1.7", "license": "MIT", "dependencies": { "got": "^11.8.2" diff --git a/package.json b/package.json index 341bf67..c213cd7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "play-dl", - "version": "0.1.6", + "version": "0.1.7", "description": "YouTube, SoundCloud, Spotify downloader", "main": "dist/index.js", "typings": "dist/index.d.ts", diff --git a/play-dl/YouTube/classes/LiveStream.ts b/play-dl/YouTube/classes/LiveStream.ts new file mode 100644 index 0000000..706641d --- /dev/null +++ b/play-dl/YouTube/classes/LiveStream.ts @@ -0,0 +1,139 @@ +import { PassThrough } from 'stream' +import got from 'got' + +export interface FormatInterface{ + url : string; + targetDurationSec : number; + maxDvrDurationSec : number +} + +export class LiveStreaming{ + smooth : boolean; + private __stream : PassThrough + private format : FormatInterface + private interval : number + private packet_count : number + private timer : NodeJS.Timer | null + private segments_urls : string[] + constructor(format : FormatInterface, smooth : boolean){ + this.smooth = smooth || false + this.format = format + this.__stream = new PassThrough({ highWaterMark : 10 * 1000 * 1000 }) + this.segments_urls = [] + this.packet_count = 0 + this.interval = 0 + this.timer = null + this.__stream.on('close', () => { + this.cleanup() + }) + if(this.smooth === true) this.__stream.pause() + this.start() + } + + async manifest_getter(){ + let response = await got(this.format.url) + this.segments_urls = response.body.split('\n').filter((x) => x.startsWith('https')) + } + + get stream(){ + return this.__stream + } + + private cleanup(){ + clearInterval(this.timer as NodeJS.Timer) + this.segments_urls = [] + this.packet_count = 0 + } + + async start(){ + if(this.__stream.destroyed) this.cleanup() + await this.manifest_getter() + if(this.packet_count === 0) this.packet_count = Number(this.segments_urls[0].split('index.m3u8/sq/')[1].split('/')[0]) + for await (let url of this.segments_urls){ + await (async () => { + return new Promise(async (resolve, reject) => { + if(Number(url.split('index.m3u8/sq/')[1].split('/')[0]) !== this.packet_count){ + resolve('') + return + } + let stream = this.got_stream(url) + stream.on('data', (chunk) => this.__stream.write(chunk)) + stream.on('end', () => { + this.packet_count++ + resolve('') + }) + }) + })() + } + this.interval = (this.segments_urls.length / 2) * 1000 + this.timer = setTimeout(async () => { + if(this.smooth === true){ + this.__stream.resume() + this.smooth = false + } + await this.start() + }, this.interval) + } + + private got_stream(url: string){ + return got.stream(url) + } +} + +export class LiveEnded{ + private __stream : PassThrough + private format : FormatInterface + private packet_count : number + private segments_urls : string[] + constructor(format : FormatInterface){ + this.format = format + this.__stream = new PassThrough({ highWaterMark : 10 * 1000 * 1000 }) + this.segments_urls = [] + this.packet_count = 0 + this.__stream.on('close', () => { + this.cleanup() + }) + this.start() + } + + async manifest_getter(){ + let response = await got(this.format.url) + this.segments_urls = response.body.split('\n').filter((x) => x.startsWith('https')) + } + + get stream(){ + return this.__stream + } + + private cleanup(){ + this.segments_urls = [] + this.packet_count = 0 + } + + async start(){ + if(this.__stream.destroyed) this.cleanup() + await this.manifest_getter() + if(this.packet_count === 0) this.packet_count = Number(this.segments_urls[0].split('index.m3u8/sq/')[1].split('/')[0]) + for await (let url of this.segments_urls){ + await (async () => { + return new Promise(async (resolve, reject) => { + if(Number(url.split('index.m3u8/sq/')[1].split('/')[0]) !== this.packet_count){ + resolve('') + return + } + let stream = this.got_stream(url) + stream.on('data', (chunk) => this.__stream.write(chunk)) + stream.on('end', () => { + this.packet_count++ + resolve('') + }) + }) + })() + } + } + + private got_stream(url: string){ + return got.stream(url) + } +} + diff --git a/play-dl/YouTube/index.ts b/play-dl/YouTube/index.ts index 9459d6a..8cfd2ce 100644 --- a/play-dl/YouTube/index.ts +++ b/play-dl/YouTube/index.ts @@ -1,5 +1,3 @@ -import { stream } from './stream' - export { search } from './search' -export { stream } +export { stream, stream_from_info, stream_type } from './stream' export * from './utils' \ No newline at end of file diff --git a/play-dl/YouTube/stream.ts b/play-dl/YouTube/stream.ts index a254ca6..4964d8b 100644 --- a/play-dl/YouTube/stream.ts +++ b/play-dl/YouTube/stream.ts @@ -2,10 +2,29 @@ import got from "got" import { video_info } from "." import { PassThrough } from 'stream' import https from 'https' +import { FormatInterface, LiveEnded, LiveStreaming } from "./classes/LiveStream" +enum StreamType{ + Arbitrary = 'arbitrary', + Raw = 'raw', + OggOpus = 'ogg/opus', + WebmOpus = 'webm/opus', + Opus = 'opus', +} interface StreamOptions { - filter : "bestaudio" | "bestvideo" | "live" + smooth : boolean +} + +interface InfoData{ + LiveStreamData : { + isLive : boolean + dashManifestUrl : string + hlsManifestUrl : string + } + html5player : string + format : any[] + video_details : any } function parseAudioFormats(formats : any[]){ @@ -21,55 +40,61 @@ function parseAudioFormats(formats : any[]){ return result } -function parseVideoFormats(formats : any[]){ - let result: any[] = [] - formats.forEach((format) => { - let type = format.mimeType as string - if(type.startsWith('audio')){ - format.codec = type.split('codecs="')[1].split('"')[0] - format.container = type.split('audio/')[1].split(';')[0] - result.push(format) - } - }) - return result -} - -export async function stream(url : string, options? : StreamOptions): Promise{ +export async function stream(url : string, options : StreamOptions = { smooth : false }): Promise{ let info = await video_info(url) let final: any[] = []; - - if(info.video_details.live === true && options) { - options.filter = "live" + + if(info.LiveStreamData.isLive === true && info.LiveStreamData.hlsManifestUrl !== null) { + return await live_stream(info as InfoData, options.smooth) } - if(options?.filter){ - switch(options.filter){ - case "bestaudio": - let audioFormat = parseAudioFormats(info.format) - if(audioFormat.length === 0) await stream(url, { filter : "bestvideo" }) - let opusFormats = filterFormat(audioFormat, "opus") - if(opusFormats.length === 0){ - final.push(audioFormat[audioFormat.length - 1]) - } - else{ - final.push(opusFormats[opusFormats.length - 1]) - } - break - case "bestvideo" : - let videoFormat = parseVideoFormats(info.format) - if(videoFormat.length === 0) throw new Error('Can\'t Find Video Formats ') - let qual_1080 = filterVideo(videoFormat, "1080p") - if(qual_1080.length === 0) { - let qual_720 = filterVideo(videoFormat, "720p") - if(qual_720.length === 0) final.push(videoFormat[0]) - else final.push(qual_720) - break - } - else final.push(qual_1080) - break - - } + let audioFormat = parseAudioFormats(info.format) + let opusFormats = filterFormat(audioFormat, "opus") + + if(opusFormats.length === 0){ + final.push(audioFormat[audioFormat.length - 1]) } + else{ + final.push(opusFormats[opusFormats.length - 1]) + } + + if(final.length === 0) final.push(info.format[info.format.length - 1]) + let piping_stream = got.stream(final[0].url, { + retry : 5, + headers: { + 'Connection': 'keep-alive', + 'Accept-Encoding': '', + 'Accept-Language': 'en-US,en;q=0.8', + 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36' + }, + agent : { + https : new https.Agent({ keepAlive : true }) + }, + http2 : true + }) + let playing_stream = new PassThrough({ highWaterMark: 10 * 1000 * 1000 }) + + piping_stream.pipe(playing_stream) + return playing_stream +} + +export async function stream_from_info(info : InfoData, options : StreamOptions){ + let final: any[] = []; + + if(info.LiveStreamData.isLive === true) { + return await live_stream(info as InfoData, options.smooth) + } + + let audioFormat = parseAudioFormats(info.format) + let opusFormats = filterFormat(audioFormat, "opus") + + if(opusFormats.length === 0){ + final.push(audioFormat[audioFormat.length - 1]) + } + else{ + final.push(opusFormats[opusFormats.length - 1]) + } + if(final.length === 0) final.push(info.format[info.format.length - 1]) let piping_stream = got.stream(final[0].url, { retry : 5, @@ -98,10 +123,27 @@ function filterFormat(formats : any[], codec : string){ return result } -function filterVideo(formats : any[], quality : string) { - let result: any[] = [] - formats.forEach((format) => { - if(format.qualityLabel === quality) result.push(format) +export function stream_type(info:InfoData): StreamType{ + if(info.LiveStreamData.isLive === true && info.LiveStreamData.hlsManifestUrl !== null) return StreamType.Arbitrary + else return StreamType.WebmOpus +} + +async function live_stream(info : InfoData, smooth : boolean): Promise{ + let res_144 : FormatInterface = { + url : '', + targetDurationSec : 0, + maxDvrDurationSec : 0 + } + info.format.forEach((format) => { + if(format.qualityLabel === '144p') res_144 = format + else return }) - return result + let stream : LiveStreaming | LiveEnded + if(info.video_details.duration === '0') { + stream = new LiveStreaming((res_144.url.length !== 0) ? res_144 : info.format[info.format.length - 1], smooth) + } + else { + stream = new LiveEnded((res_144.url.length !== 0) ? res_144 : info.format[info.format.length - 1]) + } + return stream.stream } \ No newline at end of file diff --git a/play-dl/YouTube/utils/extractor.ts b/play-dl/YouTube/utils/extractor.ts index c5350cf..e616a28 100644 --- a/play-dl/YouTube/utils/extractor.ts +++ b/play-dl/YouTube/utils/extractor.ts @@ -12,8 +12,9 @@ export async function video_basic_info(url : string){ let video_id = url.split('watch?v=')[1].split('&')[0] let new_url = 'https://www.youtube.com/watch?v=' + video_id let body = await url_get(new_url) - let player_response = JSON.parse(body.split("var ytInitialPlayerResponse = ")[1].split(";")[0]) + let player_response = JSON.parse(body.split("var ytInitialPlayerResponse = ")[1].split("}};")[0] + '}}') if(player_response.playabilityStatus.status === 'ERROR') throw new Error(`While getting info from url \n ${player_response.playabilityStatus.reason}`) + if(player_response.playabilityStatus.status === 'LOGIN_REQUIRED') throw new Error(`While getting info from url \n ${player_response.playabilityStatus.messages[0]}`) let html5player = 'https://www.youtube.com' + body.split('"jsUrl":"')[1].split('"')[0] let format = [] let vid = player_response.videoDetails @@ -43,7 +44,13 @@ export async function video_basic_info(url : string){ } if(!video_details.live) format.push(player_response.streamingData.formats[0]) format.push(...player_response.streamingData.adaptiveFormats) + let LiveStreamData = { + isLive : video_details.live, + dashManifestUrl : (player_response.streamingData?.dashManifestUrl) ? player_response.streamingData?.dashManifestUrl : null, + hlsManifestUrl : (player_response.streamingData?.hlsManifestUrl) ? player_response.streamingData?.hlsManifestUrl : null + } return { + LiveStreamData, html5player, format, video_details @@ -56,11 +63,35 @@ export async function video_info(url : string) { data.format = await format_decipher(data.format, data.html5player) return data } + else if(data.LiveStreamData.isLive === true && data.LiveStreamData.hlsManifestUrl !== null){ + let m3u8 = await url_get(data.LiveStreamData.hlsManifestUrl) + data.format = await parseM3U8(m3u8, data.format) + return data + } else { return data } } +async function parseM3U8(m3u8_data : string, formats : any[]): Promise{ + let lines = m3u8_data.split('\n') + formats.forEach((format) => { + if(!format.qualityLabel) return + let reso = format.width + 'x' + format.height + let index = -1; + let line_count = 0 + lines.forEach((line) => { + index = line.search(reso) + if(index !== -1) { + format.url = lines[line_count+1] + } + line_count++ + index = -1 + }) + }) + return formats +} + export async function playlist_info(url : string) { if (!url || typeof url !== "string") throw new Error(`Expected playlist url, received ${typeof url}!`); if(url.search('(\\?|\\&)list\\=') === -1) throw new Error('This is not a PlayList URL') diff --git a/play-dl/YouTube/utils/request.ts b/play-dl/YouTube/utils/request.ts index 2041b0b..999c8f7 100644 --- a/play-dl/YouTube/utils/request.ts +++ b/play-dl/YouTube/utils/request.ts @@ -3,7 +3,6 @@ import got, { OptionsOfTextResponseBody } from 'got/dist/source' export async function url_get (url : string, options? : OptionsOfTextResponseBody) : Promise{ return new Promise(async(resolve, reject) => { let response = await got(url, options) - if(response.statusCode === 200) { resolve(response.body) } diff --git a/play-dl/index.ts b/play-dl/index.ts index 47a0e0d..7e28b2f 100644 --- a/play-dl/index.ts +++ b/play-dl/index.ts @@ -1,4 +1,4 @@ //This File is in testing stage, everything will change in this -import { playlist_info, video_basic_info, video_info, search, stream } from "./YouTube"; +import { playlist_info, video_basic_info, video_info, search, stream, stream_from_info, stream_type } from "./YouTube"; -export var youtube = { playlist_info, video_basic_info, video_info, search , stream} +export let youtube = { playlist_info, video_basic_info, video_info, search , stream, stream_from_info, stream_type}