refactor: simplify the player class

This commit is contained in:
LuanRT
2022-05-05 04:17:11 -03:00
parent b773f5668c
commit 4943685e57
4 changed files with 128 additions and 77 deletions

View File

@@ -6,44 +6,85 @@ const Utils = require('../utils/Utils');
const Constants = require('../utils/Constants');
class Player {
constructor(session) {
this.session = session;
this.player_name = Utils.getStringBetweenStrings(this.session.player_url, '/player/', '/');
this.tmp_cache_dir = __dirname.slice(0, -8) + 'cache';
#player_id;
#player_url;
#player_path;
#ntoken_decipher_sc;
#signature_decipher_sc;
#signature_timestamp;
#cache_dir;
constructor(id) {
this.#player_id = id;
this.#cache_dir = __dirname.slice(0, -8) + 'cache';
this.#player_url = Constants.URLS.YT_BASE + '/s/player/' + this.#player_id + '/player_ias.vflset/en_US/base.js';
this.#player_path = `${this.#cache_dir}/${this.#player_id}.js`;
}
async init() {
if (Fs.existsSync(`${this.tmp_cache_dir}/${this.player_name}.js`)) {
const player_data = Fs.readFileSync(`${this.tmp_cache_dir}/${this.player_name}.js`).toString();
this.sig_decipher_sc = this.#getSigDecipherCode(player_data);
this.ntoken_sc = this.#getNEncoder(player_data);
if (this.isCached()) {
const player_data = Fs.readFileSync(this.#player_path).toString();
this.#signature_timestamp = this.#extractSigTimestamp(player_data);
this.#signature_decipher_sc = this.#extractSigDecipherSc(player_data);
this.#ntoken_decipher_sc = this.#extractNTokenSc(player_data);
} else {
const response = await Axios.get(`${Constants.URLS.YT_BASE}${this.session.player_url}`, { path: this.session.playerUrl, headers: { 'content-type': 'text/javascript', 'user-agent': Utils.getRandomUserAgent('desktop').userAgent } }).catch((error) => error);
if (response instanceof Error) throw new Error('Could not download player script: ' + response.message);
const response = await Axios.get(this.#player_url, { headers: { 'content-type': 'text/javascript', 'user-agent': Utils.getRandomUserAgent('desktop').userAgent } }).catch((error) => error);
if (response instanceof Error) throw new Utils.InnertubeError('Could not download js player', { player_id });
this.#signature_timestamp = this.#extractSigTimestamp(response.data);
this.#signature_decipher_sc = this.#extractSigDecipherSc(response.data);
this.#ntoken_decipher_sc = this.#extractNTokenSc(response.data);
try {
// Deletes old players
Fs.existsSync(this.tmp_cache_dir) && Fs.rmSync(this.tmp_cache_dir, { recursive: true });
// Caches the current player so we don't have to download it all the time.
Fs.mkdirSync(this.tmp_cache_dir, { recursive: true });
Fs.writeFileSync(`${this.tmp_cache_dir}/${this.player_name}.js`, response.data);
// Delete the old player
Fs.existsSync(this.#cache_dir) &&
Fs.rmSync(this.#cache_dir, { recursive: true });
// Cache the current player
Fs.mkdirSync(this.#cache_dir, { recursive: true });
Fs.writeFileSync(this.#player_path, response.data);
} catch (err) {}
this.sig_decipher_sc = this.#getSigDecipherCode(response.data);
this.ntoken_sc = this.#getNEncoder(response.data);
}
return this;
}
#getSigDecipherCode(data) {
get url() {
return this.#player_url;
}
get sts() {
return this.#signature_timestamp;
}
get ntoken_decipher() {
return this.#ntoken_decipher_sc;
}
get signature_decipher() {
return this.#signature_decipher_sc;
}
#extractSigTimestamp(data) {
return parseInt(Utils.getStringBetweenStrings(data, 'signatureTimestamp:', ','));
}
#extractSigDecipherSc(data) {
const sig_alg_sc = Utils.getStringBetweenStrings(data, 'this.audioTracks};var', '};');
const sig_data = Utils.getStringBetweenStrings(data, 'function(a){a=a.split("")', 'return a.join("")}');
return sig_alg_sc + sig_data;
}
#getNEncoder(data) {
#extractNTokenSc(data) {
return `var b=a.split("")${Utils.getStringBetweenStrings(data, 'b=a.split("")', '}return b.join("")}')}} return b.join("");`;
}
isCached() {
return Fs.existsSync(this.#player_path);
}
}
module.exports = Player;

View File

@@ -52,14 +52,17 @@ class NToken {
transformations[data.index](transformations[param_index[0]], transformations[param_index[1]], base64_dia);
});
} catch (err) {
console.error(`Could not transform n-token (${this.n}), download may be throttled:`, err.message);
console.error(new Utils.ParsingError('Could not transform n-token, download may be throttled.', {
original_token: this.n,
stack: err.stack
}));
return this.n;
}
return n_token.join('');
}
#getFunc(el) {
return el.match(Constants.FUNCS_REGEX);
return el.match(Constants.NTOKEN_REGEX.FUNCTIONS);
}
/**

View File

@@ -1,75 +1,90 @@
'use strict';
const Constants = require('../utils/Constants');
const QueryString = require('querystring');
class Signature {
constructor(url, player) {
constructor(url, sig_decipher_sc) {
this.url = url;
this.player = player;
this.func_regex = /(.{2}):function\(.*?\){(.*?)}/g;
this.actions_regex = /;.{2}\.(.{2})\(.*?,(.*?)\)/g;
this.sig_decipher_sc = sig_decipher_sc;
}
/**
* Deciphers signature.
* @returns {string}
*/
decipher() {
let actions;
const args = QueryString.parse(this.url);
const signature = args.s.split('');
const functions = this.#getFunctions();
function splice(arr, end) {
arr.splice(0, end);
}
function swap(arr, index) {
let origArrI = arr[0];
arr[0] = arr[index % arr.length];
arr[index % arr.length] = origArrI;
}
function reverse(arr) {
arr.reverse();
}
let actions;
let signature = args.s.split('');
while ((actions = this.actions_regex.exec(this.player.sig_decipher_sc)) !== null) {
switch (actions[1]) {
/**
* Decides what function should be used to modify the
* the signature.
*/
while ((actions = Constants.SIG_REGEX.ACTIONS.exec(this.sig_decipher_sc)) !== null) {
const action = actions.groups;
switch (action.name) {
case functions[0]:
reverse(signature, actions[2]);
this.#reverse(signature);
break;
case functions[1]:
splice(signature, actions[2]);
this.#splice(signature, action.param);
break;
case functions[2]:
swap(signature, actions[2]);
this.#swap(signature, action.param);
break;
default:
}
}
const url_components = new URL(args.url);
args.sp ? url_components.searchParams.set(args.sp, signature.join('')) : url_components.searchParams.set('signature', signature.join(''));
args.sp ?
url_components.searchParams.set(args.sp, signature.join('')) :
url_components.searchParams.set('signature', signature.join(''));
return url_components.toString();
}
/**
* Extracts the functions used to modify the signature
* and returns them in the correct order.
*
* @returns {Array.<string>}
*/
#getFunctions() {
let func;
let func_name = [];
while ((func = this.func_regex.exec(this.player.sig_decipher_sc)) !== null) {
if (func[0].includes('reverse()')) {
func_name[0] = func[1];
let functions = [];
while ((func = Constants.SIG_REGEX.FUNCTIONS.exec(this.sig_decipher_sc)) !== null) {
if (func[0].includes('reverse')) {
functions[0] = func[1];
} else if (func[0].includes('splice')) {
func_name[1] = func[1];
functions[1] = func[1];
} else {
func_name[2] = func[1];
functions[2] = func[1];
}
}
return func_name;
return functions;
}
#swap(arr, index) {
let origArrI = arr[0];
arr[0] = arr[index % arr.length];
arr[index % arr.length] = origArrI;
}
#splice(arr, end) {
arr.splice(0, end);
}
#reverse(arr) {
arr.reverse();
}
}

View File

@@ -40,18 +40,6 @@ module.exports = {
VERSION: '17.17.32'
}
},
DEFAULT_HEADERS: (config) => {
return {
headers: {
'Cookie': config?.cookie || '',
'user-agent': Utils.getRandomUserAgent('desktop').userAgent,
'Referer': 'https://www.google.com/',
'Accept': 'text/html',
'Accept-Language': `en-${config?.gl || 'US'}`,
'Accept-Encoding': 'gzip'
}
};
},
STREAM_HEADERS: {
'Accept': '*/*',
'User-Agent': Utils.getRandomUserAgent('desktop').userAgent,
@@ -94,11 +82,15 @@ module.exports = {
NORMAL: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'.split(''),
REVERSE: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_'.split('')
},
SIG_REGEX: {
ACTIONS: /;.{2}\.(?<name>.{2})\(.*?,(?<param>.*?)\)/g,
FUNCTIONS: /(?<name>.{2}):function\(.*?\){(.*?)}/g
},
NTOKEN_REGEX: {
CALLS: /c\[(.*?)\]\((.+?)\)/g,
PLACEHOLDERS: /c\[(.*?)\]=c/g,
FUNCTIONS: /d\.push\(e\)|d\.reverse\(\)|d\[0\]\)\[0\]\)|f=d\[0];d\[0\]|d\.length;d\.splice\(e,1\)|function\(\){for\(var|function\(d,e,f\){var|function\(d\){for\(var|reverse\(\)\.forEach|unshift\(d\.pop\(\)\)|function\(d,e\){for\(var f/
},
FUNCS_REGEX: /d\.push\(e\)|d\.reverse\(\)|d\[0\]\)\[0\]\)|f=d\[0];d\[0\]|d\.length;d\.splice\(e,1\)|function\(\){for\(var|function\(d,e,f\){var|function\(d\){for\(var|reverse\(\)\.forEach|unshift\(d\.pop\(\)\)|function\(d,e\){for\(var f/,
FUNCS: {
PUSH: 'd.push(e)',
REVERSE_1: 'd.reverse()',
@@ -112,4 +104,4 @@ module.exports = {
TRANSLATE_1: 'function(d,e){for(var f',
TRANSLATE_2: 'function(d,e,f){var'
}
};
};