ionic-youtube-streams
Advanced tools
Comparing version 1.0.7 to 1.0.8
export declare const Name: (name: string) => string; | ||
export declare function info(videoId: string): Promise<any>; | ||
export declare function sortByType(videoId: string, type: string): Promise<any>; |
@@ -6,4 +6,8 @@ "use strict"; | ||
function info(videoId) { | ||
return search_1.searchVideo(videoId); | ||
return search_1.searchVideo(videoId, 'video'); | ||
} | ||
exports.info = info; | ||
function sortByType(videoId, type) { | ||
return search_1.searchVideo(videoId, type); | ||
} | ||
exports.sortByType = sortByType; |
@@ -6,7 +6,7 @@ import { HTTP } from '@ionic-native/http/ngx'; | ||
cache: Map<any, any>; | ||
getTokens(html5playerfile: any): Promise<any>; | ||
getTokens(html5playerfile: any, options: any): Promise<string[]>; | ||
extractActions(body: any): string[] | null; | ||
decipherFormats(formats: any, tokens: any, debug: any): void; | ||
decipherFormats(formats: any, html5player: any, options: any): Promise<any>; | ||
decipher: (tokens: any, sig: any) => any; | ||
setDownloadURL(format: any, sig: any, debug: any): void; | ||
setDownloadURL(format: any, sig: any): void; | ||
} |
@@ -38,5 +38,12 @@ "use strict"; | ||
}; | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; | ||
result["default"] = mod; | ||
return result; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var url = require("url"); | ||
var querystring = require("querystring"); | ||
var url = __importStar(require("url")); | ||
var querystring = __importStar(require("querystring")); | ||
var jsVarStr = '[a-zA-Z_\\$][a-zA-Z_0-9]*'; | ||
@@ -113,3 +120,3 @@ var jsSingleQuoteStr = "'[^'\\\\]*(:?\\\\[\\s\\S][^'\\\\]*)*'"; | ||
} | ||
CiphService.prototype.getTokens = function (html5playerfile) { | ||
CiphService.prototype.getTokens = function (html5playerfile, options) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
@@ -121,6 +128,4 @@ var cachedTokens, response, tokens; | ||
cachedTokens = this.cache.get(html5playerfile); | ||
if (!cachedTokens) return [3 /*break*/, 1]; | ||
return [2 /*return*/, cachedTokens]; | ||
case 1: return [4 /*yield*/, this.httpClient.get(html5playerfile, {}, {})]; | ||
case 2: | ||
return [4 /*yield*/, this.httpClient.get(html5playerfile, {}, {})]; | ||
case 1: | ||
response = _a.sent(); | ||
@@ -188,16 +193,30 @@ tokens = this.extractActions(response.data); | ||
}; | ||
CiphService.prototype.decipherFormats = function (formats, tokens, debug) { | ||
var _this = this; | ||
formats.forEach(function (format) { | ||
var cipher = format.signatureCipher || format.cipher; | ||
if (cipher) { | ||
Object.assign(format, querystring.parse(cipher)); | ||
delete format.signatureCipher; | ||
delete format.cipher; | ||
} | ||
var sig = tokens && format.s ? _this.decipher(tokens, format.s) : null; | ||
_this.setDownloadURL(format, sig, debug); | ||
CiphService.prototype.decipherFormats = function (formats, html5player, options) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var decipheredFormats, tokens; | ||
var _this = this; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
decipheredFormats = {}; | ||
return [4 /*yield*/, this.getTokens(html5player, options)]; | ||
case 1: | ||
tokens = _a.sent(); | ||
formats.forEach(function (format) { | ||
var cipher = format.signatureCipher || format.cipher; | ||
if (cipher) { | ||
Object.assign(format, querystring.parse(cipher)); | ||
delete format.signatureCipher; | ||
delete format.cipher; | ||
} | ||
var sig = tokens && format.s ? _this.decipher(tokens, format.s) : null; | ||
_this.setDownloadURL(format, sig); | ||
decipheredFormats[format.url] = format; | ||
}); | ||
return [2 /*return*/, decipheredFormats]; | ||
} | ||
}); | ||
}); | ||
}; | ||
CiphService.prototype.setDownloadURL = function (format, sig, debug) { | ||
CiphService.prototype.setDownloadURL = function (format, sig) { | ||
var decodedUrl; | ||
@@ -208,6 +227,2 @@ if (format.url) { | ||
else { | ||
if (debug) { | ||
// tslint:disable-next-line:no-console | ||
console.warn('Download url not found for itag ' + format.itag); | ||
} | ||
return; | ||
@@ -219,6 +234,2 @@ } | ||
catch (err) { | ||
if (debug) { | ||
// tslint:disable-next-line:no-console | ||
console.warn('Could not decode url: ' + err.message); | ||
} | ||
return; | ||
@@ -239,8 +250,3 @@ } | ||
// See https://github.com/fent/node-ytdl-core/issues/417 | ||
if (format.sp) { | ||
query[format.sp] = sig; | ||
} | ||
else { | ||
query.signature = sig; | ||
} | ||
query[format.sp || 'signature'] = sig; | ||
} | ||
@@ -247,0 +253,0 @@ format.url = url.format(parsedUrl); |
@@ -1,1 +0,1 @@ | ||
export declare function searchVideo(youtubeId: string): Promise<any>; | ||
export declare function searchVideo(this: any, youtubeId: string, sortType: string): Promise<any>; |
@@ -38,90 +38,87 @@ "use strict"; | ||
}; | ||
var __spreadArrays = (this && this.__spreadArrays) || function () { | ||
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; | ||
for (var r = Array(s), k = 0, i = 0; i < il; i++) | ||
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) | ||
r[k] = a[j]; | ||
return r; | ||
}; | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; | ||
result["default"] = mod; | ||
return result; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var urllib = require("url"); | ||
var tube_service_1 = require("./tube.service"); | ||
var urllib = __importStar(require("url")); | ||
var basic_info_service_1 = require("./basic-info.service"); | ||
var cip_service_1 = require("./cip.service"); | ||
var ngx_1 = require("@ionic-native/http/ngx"); | ||
var mergeFormats = function (info, formatsMap) { | ||
info.formats.forEach(function (f) { | ||
formatsMap[f.itag] = f; | ||
}); | ||
info.formats = Object.values(formatsMap); | ||
}; | ||
function searchVideo(youtubeId) { | ||
var utils_service_1 = require("./functions/utils.service"); | ||
var watch_html_service_1 = require("./functions/watch-html.service"); | ||
var format_utils_service_1 = require("./format-utils.service"); | ||
function searchVideo(youtubeId, sortType) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var httpClient, tubeService, ciphService, params, watchPageURL, ytApi, response, body, info, playErr, url, responseEmbeded, jsonStr, config, infoResponse, html5playerfile, tokens, funcs; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
var httpClient, options, basicInfoService, info, funcs, utilsService, watchHtmlService, _a, _b, _c, _d, html5player, ciphService, _e, _f, formatUtils, results; | ||
return __generator(this, function (_g) { | ||
switch (_g.label) { | ||
case 0: | ||
httpClient = new ngx_1.HTTP(); | ||
tubeService = new tube_service_1.YTubeService(httpClient); | ||
ciphService = new cip_service_1.CiphService(httpClient); | ||
params = '?hl=en'; | ||
watchPageURL = tubeService.VIDEO_URL + youtubeId + params + '&bpctr=' + Math.ceil(Date.now() / 1000); | ||
ytApi = watchPageURL + "&pbj=1"; | ||
return [4 /*yield*/, httpClient.get(ytApi, {}, { | ||
'User-Agent': '', | ||
'x-youtube-client-name': '1', | ||
'x-youtube-client-version': '2.20191008.04.01', | ||
'x-youtube-identity-token': '', | ||
})]; | ||
options = {}; | ||
basicInfoService = new basic_info_service_1.BasicInfoService(httpClient); | ||
return [4 /*yield*/, basicInfoService.getBasicInfo(youtubeId, {})]; | ||
case 1: | ||
response = _a.sent(); | ||
body = response.data; | ||
try { | ||
info = JSON.parse(body).reduce(function (part, curr) { return Object.assign(curr, part); }, {}); | ||
} | ||
catch (err) { | ||
throw Error("Error parsing info: " + err.message); | ||
} | ||
playErr = tubeService.playError(info, 'ERROR'); | ||
if (playErr) { | ||
throw playErr; | ||
} | ||
if (!!info.player) return [3 /*break*/, 3]; | ||
url = tubeService.EMBED_URL + youtubeId + '?hl=en'; | ||
return [4 /*yield*/, httpClient.get(url, {}, {})]; | ||
info = _g.sent(); | ||
funcs = []; | ||
if (!info.formats.length) return [3 /*break*/, 5]; | ||
utilsService = new utils_service_1.UtilsService(); | ||
watchHtmlService = new watch_html_service_1.WatchHtmlService(httpClient); | ||
_a = info; | ||
_b = info.html5player; | ||
if (_b) return [3 /*break*/, 3]; | ||
_d = (_c = utilsService).getHTML5player; | ||
return [4 /*yield*/, watchHtmlService.getHTMLWatchPageBody(youtubeId, options, utilsService)]; | ||
case 2: | ||
responseEmbeded = _a.sent(); | ||
jsonStr = tubeService.between(responseEmbeded.data, /(['"])PLAYER_(CONFIG|VARS)\1:\s?/, '</script>'); | ||
config = void 0; | ||
if (!jsonStr) { | ||
throw Error('Could not find player config'); | ||
_b = _d.apply(_c, [_g.sent()]); | ||
_g.label = 3; | ||
case 3: | ||
_a.html5player = _b; | ||
if (!info.html5player) { | ||
throw Error('Unable to find html5player file'); | ||
} | ||
try { | ||
config = JSON.parse(tubeService.cutAfterJSON(jsonStr)); | ||
} | ||
catch (err) { | ||
throw Error("Error parsing config: " + err.message); | ||
} | ||
// @ts-ignore | ||
playErr = tubeService.playError(info, 'LOGIN_REQUIRED'); | ||
if ((!config.args || (!config.args.player_response && !config.args.embedded_player_response)) && | ||
!config.embedded_player_response && playErr) { | ||
throw playErr; | ||
} | ||
// @ts-ignore | ||
info.player = config; | ||
_a.label = 3; | ||
case 3: return [4 /*yield*/, tubeService.gotConfig(youtubeId, null, info, body)]; | ||
html5player = urllib.resolve(utilsService.VIDEO_URL, info.html5player); | ||
ciphService = new cip_service_1.CiphService(httpClient); | ||
_f = (_e = funcs).push; | ||
return [4 /*yield*/, ciphService.decipherFormats(info.formats, html5player, options)]; | ||
case 4: | ||
infoResponse = _a.sent(); | ||
if (!(infoResponse.formats.length > 0)) return [3 /*break*/, 6]; | ||
html5playerfile = urllib.resolve(tubeService.VIDEO_URL, infoResponse.html5player); | ||
return [4 /*yield*/, ciphService.getTokens(html5playerfile)]; | ||
_f.apply(_e, [_g.sent()]); | ||
_g.label = 5; | ||
case 5: | ||
tokens = _a.sent(); | ||
ciphService.decipherFormats(infoResponse.formats, tokens, false); | ||
funcs = []; | ||
tubeService.parallel(funcs, function (err, results) { | ||
if (results[0]) { | ||
mergeFormats(infoResponse, results[0]); | ||
formatUtils = new format_utils_service_1.FormatUtilsService(); | ||
return [4 /*yield*/, Promise.all(funcs)]; | ||
case 6: | ||
results = _g.sent(); | ||
info.formats = Object.values(Object.assign.apply(Object, __spreadArrays([{}], results))); | ||
info.formats = info.formats.map(formatUtils.addFormatMeta); | ||
if (sortType === 'video') { | ||
try { | ||
info.formats.sort(formatUtils.sortFormatsByVideo); | ||
} | ||
if (results[1]) { | ||
mergeFormats(infoResponse, results[1]); | ||
catch (e) { | ||
// tslint:disable-next-line:no-console | ||
console.log(e); | ||
} | ||
infoResponse.full = true; | ||
}); | ||
return [2 /*return*/, infoResponse]; | ||
case 6: return [2 /*return*/, null]; | ||
} | ||
else { | ||
try { | ||
info.formats.sort(formatUtils.sortFormatsByAudio); | ||
} | ||
catch (e) { | ||
// tslint:disable-next-line:no-console | ||
console.log(e); | ||
} | ||
} | ||
info.full = true; | ||
return [2 /*return*/, info]; | ||
} | ||
@@ -128,0 +125,0 @@ }); |
{ | ||
"name": "ionic-youtube-streams", | ||
"version": "1.0.7", | ||
"version": "1.0.8", | ||
"description": "Fetch meta information about YouTube videos including stream urls in ionic apps", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
238366
26
1780
2551
1