mirror of
https://github.com/Rafostar/clapper.git
synced 2025-08-29 23:32:04 +02:00
Increase amount of playable YouTube videos by deciphering the ones that require to do so. Many thanks to "node-ytdl-core" devs for JS regular expressions needed for YouTube player parsing.
152 lines
4.9 KiB
JavaScript
152 lines
4.9 KiB
JavaScript
/* Copyright (C) 2012-present by fent
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
const jsVarStr = '[a-zA-Z_\\$][a-zA-Z_0-9]*';
|
|
const jsSingleQuoteStr = `'[^'\\\\]*(:?\\\\[\\s\\S][^'\\\\]*)*'`;
|
|
const jsDoubleQuoteStr = `"[^"\\\\]*(:?\\\\[\\s\\S][^"\\\\]*)*"`;
|
|
const jsQuoteStr = `(?:${jsSingleQuoteStr}|${jsDoubleQuoteStr})`;
|
|
const jsKeyStr = `(?:${jsVarStr}|${jsQuoteStr})`;
|
|
const jsPropStr = `(?:\\.${jsVarStr}|\\[${jsQuoteStr}\\])`;
|
|
const jsEmptyStr = `(?:''|"")`;
|
|
const reverseStr = ':function\\(a\\)\\{' +
|
|
'(?:return )?a\\.reverse\\(\\)' +
|
|
'\\}';
|
|
const sliceStr = ':function\\(a,b\\)\\{' +
|
|
'return a\\.slice\\(b\\)' +
|
|
'\\}';
|
|
const spliceStr = ':function\\(a,b\\)\\{' +
|
|
'a\\.splice\\(0,b\\)' +
|
|
'\\}';
|
|
const swapStr = ':function\\(a,b\\)\\{' +
|
|
'var c=a\\[0\\];a\\[0\\]=a\\[b(?:%a\\.length)?\\];a\\[b(?:%a\\.length)?\\]=c(?:;return a)?' +
|
|
'\\}';
|
|
const actionsObjRegexp = new RegExp(
|
|
`var (${jsVarStr})=\\{((?:(?:${
|
|
jsKeyStr}${reverseStr}|${
|
|
jsKeyStr}${sliceStr}|${
|
|
jsKeyStr}${spliceStr}|${
|
|
jsKeyStr}${swapStr
|
|
}),?\\r?\\n?)+)\\};`);
|
|
const actionsFuncRegexp = new RegExp(`${`function(?: ${jsVarStr})?\\(a\\)\\{` +
|
|
`a=a\\.split\\(${jsEmptyStr}\\);\\s*` +
|
|
`((?:(?:a=)?${jsVarStr}`}${
|
|
jsPropStr
|
|
}\\(a,\\d+\\);)+)` +
|
|
`return a\\.join\\(${jsEmptyStr}\\)` +
|
|
`\\}`);
|
|
const reverseRegexp = new RegExp(`(?:^|,)(${jsKeyStr})${reverseStr}`, 'm');
|
|
const sliceRegexp = new RegExp(`(?:^|,)(${jsKeyStr})${sliceStr}`, 'm');
|
|
const spliceRegexp = new RegExp(`(?:^|,)(${jsKeyStr})${spliceStr}`, 'm');
|
|
const swapRegexp = new RegExp(`(?:^|,)(${jsKeyStr})${swapStr}`, 'm');
|
|
|
|
const swapHeadAndPosition = (arr, position) => {
|
|
const first = arr[0];
|
|
arr[0] = arr[position % arr.length];
|
|
arr[position] = first;
|
|
|
|
return arr;
|
|
}
|
|
|
|
function decipher(sig, tokens) {
|
|
sig = sig.split('');
|
|
tokens = tokens.split(',');
|
|
|
|
for(let i = 0, len = tokens.length; i < len; i++) {
|
|
let token = tokens[i], pos;
|
|
switch (token[0]) {
|
|
case 'r':
|
|
sig = sig.reverse();
|
|
break;
|
|
case 'w':
|
|
pos = ~~token.slice(1);
|
|
sig = swapHeadAndPosition(sig, pos);
|
|
break;
|
|
case 's':
|
|
pos = ~~token.slice(1);
|
|
sig = sig.slice(pos);
|
|
break;
|
|
case 'p':
|
|
pos = ~~token.slice(1);
|
|
sig.splice(0, pos);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return sig.join('');
|
|
};
|
|
|
|
function extractActions(body) {
|
|
const objResult = actionsObjRegexp.exec(body);
|
|
const funcResult = actionsFuncRegexp.exec(body);
|
|
|
|
if(!objResult || !funcResult)
|
|
return null;
|
|
|
|
const obj = objResult[1].replace(/\$/g, '\\$');
|
|
const objBody = objResult[2].replace(/\$/g, '\\$');
|
|
const funcBody = funcResult[1].replace(/\$/g, '\\$');
|
|
|
|
let result = reverseRegexp.exec(objBody);
|
|
const reverseKey = result && result[1]
|
|
.replace(/\$/g, '\\$')
|
|
.replace(/\$|^'|^"|'$|"$/g, '');
|
|
result = sliceRegexp.exec(objBody);
|
|
const sliceKey = result && result[1]
|
|
.replace(/\$/g, '\\$')
|
|
.replace(/\$|^'|^"|'$|"$/g, '');
|
|
result = spliceRegexp.exec(objBody);
|
|
const spliceKey = result && result[1]
|
|
.replace(/\$/g, '\\$')
|
|
.replace(/\$|^'|^"|'$|"$/g, '');
|
|
result = swapRegexp.exec(objBody);
|
|
const swapKey = result && result[1]
|
|
.replace(/\$/g, '\\$')
|
|
.replace(/\$|^'|^"|'$|"$/g, '');
|
|
|
|
const keys = `(${[reverseKey, sliceKey, spliceKey, swapKey].join('|')})`;
|
|
const myreg = `(?:a=)?${obj
|
|
}(?:\\.${keys}|\\['${keys}'\\]|\\["${keys}"\\])` +
|
|
`\\(a,(\\d+)\\)`;
|
|
const tokenizeRegexp = new RegExp(myreg, 'g');
|
|
const tokens = [];
|
|
|
|
while((result = tokenizeRegexp.exec(funcBody)) !== null) {
|
|
const key = result[1] || result[2] || result[3];
|
|
const pos = result[4];
|
|
switch (key) {
|
|
case swapKey:
|
|
tokens.push(`w${result[4]}`);
|
|
break;
|
|
case reverseKey:
|
|
tokens.push('r');
|
|
break;
|
|
case sliceKey:
|
|
tokens.push(`s${result[4]}`);
|
|
break;
|
|
case spliceKey:
|
|
tokens.push(`p${result[4]}`);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return tokens.join(',');
|
|
}
|