diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c0edceb..7dacde7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -380,11 +380,11 @@ jobs: name: player-js - name: Run Deno tests run: | - xargs -n 1 -P 8 deno test \ + xargs -n 1 -P 10 deno test \ --no-prompt \ --no-check \ --allow-read=src/yt/solver/test/players/ \ - --filter <<<"$(printf -- ' %s \n' main tcc tce es5 es6 tv tv_es6 phone)" + --filter <<<"$(printf -- '-%s-\n' main tcc tce es5 es6 tv tv_es6 phone es6_tcc es6_tce)" bun_build: name: Test Bun build diff --git a/src/yt/solver/sig.ts b/src/yt/solver/sig.ts index dbbed04..c700b45 100644 --- a/src/yt/solver/sig.ts +++ b/src/yt/solver/sig.ts @@ -2,33 +2,34 @@ import { type ESTree } from "meriyah"; import { matchesStructure } from "../../utils.ts"; import { type DeepPartial } from "../../types.ts"; -const nsigExpression: DeepPartial = { - type: "VariableDeclaration", - kind: "var", - declarations: [ +const nsig: DeepPartial = { + type: "CallExpression", + callee: { + or: [{ type: "Identifier" }, { type: "SequenceExpression" }], + }, + arguments: [ + {}, { - type: "VariableDeclarator", - init: { - type: "CallExpression", - callee: { - type: "Identifier", - }, - arguments: [ - { - type: "Literal", - }, - { - type: "CallExpression", - callee: { - type: "Identifier", - name: "decodeURIComponent", - }, - }, - ], + type: "CallExpression", + callee: { + type: "Identifier", + name: "decodeURIComponent", }, + arguments: [{}], }, ], }; +const nsigAssignment: DeepPartial = { + type: "AssignmentExpression", + left: { type: "Identifier" }, + operator: "=", + right: nsig, +}; +const nsigDeclarator: DeepPartial = { + type: "VariableDeclarator", + id: { type: "Identifier" }, + init: nsig, +}; const logicalExpression: DeepPartial = { type: "ExpressionStatement", @@ -53,6 +54,17 @@ const logicalExpression: DeepPartial = { }, arguments: { or: [ + [ + { + type: "CallExpression", + callee: { + type: "Identifier", + name: "decodeURIComponent", + }, + arguments: [{ type: "Identifier" }], + optional: false, + }, + ], [ { type: "Literal" }, { @@ -66,6 +78,8 @@ const logicalExpression: DeepPartial = { }, ], [ + { type: "Literal" }, + { type: "Literal" }, { type: "CallExpression", callee: { @@ -98,17 +112,15 @@ const identifier: DeepPartial = { type: "AssignmentExpression", operator: "=", left: { - type: "Identifier", + or: [{ type: "Identifier" }, { type: "MemberExpression" }], }, right: { type: "FunctionExpression", - params: [{}, {}, {}], }, }, }, { type: "FunctionDeclaration", - params: [{}, {}, {}], }, { type: "VariableDeclaration", @@ -118,7 +130,6 @@ const identifier: DeepPartial = { type: "VariableDeclarator", init: { type: "FunctionExpression", - params: [{}, {}, {}], }, }, ], @@ -137,22 +148,19 @@ export function extract( node.type === "ExpressionStatement" && node.expression.type === "AssignmentExpression" && node.expression.right.type === "FunctionExpression" && - node.expression.right.params.length === 3 + node.expression.right.params.length >= 3 ) { blocks.push(node.expression.right.body!); } else if (node.type === "VariableDeclaration") { for (const decl of node.declarations) { if ( decl.init?.type === "FunctionExpression" && - decl.init.params.length === 3 + decl.init.params.length >= 3 ) { blocks.push(decl.init.body!); } } - } else if ( - node.type === "FunctionDeclaration" && - node.params.length === 3 - ) { + } else if (node.type === "FunctionDeclaration" && node.params.length >= 3) { blocks.push(node.body!); } else { return null; @@ -179,6 +187,7 @@ export function extract( for (const stmt of block.body) { if (matchesStructure(stmt, logicalExpression)) { + // legacy matching if ( stmt.type === "ExpressionStatement" && stmt.expression.type === "LogicalExpression" && @@ -188,34 +197,61 @@ export function extract( stmt.expression.right.expressions[0].right.type === "CallExpression" ) { call = stmt.expression.right.expressions[0].right; - break; } } else if (stmt.type === "IfStatement") { + // if (...) { var a, b = (0, c)(1, decodeURIComponent(...))} let consequent = stmt.consequent; while (consequent.type === "LabeledStatement") { consequent = consequent.body; } + if (consequent.type !== "BlockStatement") { + continue; + } - if (consequent.type === "BlockStatement") { - for (const n of consequent.body) { - if (!matchesStructure(n, nsigExpression)) { - continue; - } - + for (const n of consequent.body) { + if (n.type !== "VariableDeclaration") { + continue; + } + for (const decl of n.declarations) { if ( - n.type === "VariableDeclaration" && - n.declarations[0]?.init?.type === "CallExpression" + matchesStructure(decl, nsigDeclarator) && + decl.init?.type === "CallExpression" ) { - call = n.declarations[0].init; + call = decl.init; + break; + } + } + if (call) { + break; + } + } + } else if (stmt.type === "ExpressionStatement") { + // (...) && ((...), (c = (...)(decodeURIComponent(...)))) + if ( + stmt.expression.type !== "LogicalExpression" || + stmt.expression.operator !== "&&" || + stmt.expression.right.type !== "SequenceExpression" + ) { + continue; + } + for (const expr of stmt.expression.right.expressions) { + if (matchesStructure(expr, nsigAssignment) && expr.type) { + if ( + expr.type === "AssignmentExpression" && + expr.right.type === "CallExpression" + ) { + call = expr.right; break; } } } - if (call) break; + } + if (call) { + break; } } - if (call?.callee.type !== "Identifier") { + if (!call) { continue; } @@ -230,16 +266,12 @@ export function extract( ], body: { type: "CallExpression", - callee: { - type: "Identifier", - name: call.callee.name, - }, + callee: call.callee, arguments: call.arguments.map((arg): ESTree.Expression => { if ( arg.type === "CallExpression" && arg.callee.type === "Identifier" && - arg.callee.name === "decodeURIComponent" && - arg.arguments[0]?.type === "Identifier" + arg.callee.name === "decodeURIComponent" ) { return { type: "Identifier", name: "sig" }; } diff --git a/src/yt/solver/solvers.test.ts b/src/yt/solver/solvers.test.ts index 7ed25f8..39459a6 100644 --- a/src/yt/solver/solvers.test.ts +++ b/src/yt/solver/solvers.test.ts @@ -8,7 +8,7 @@ const io = await getIO(); for (const test of tests) { for (const variant of test.variants ?? players.keys()) { const path = getCachePath(test.player, variant); - await io.test(` ${test.player} ${variant} `, async (assert, subtest) => { + await io.test(`-${test.player}-${variant}-`, async (assert, subtest) => { const content = await io.read(path); const solvers = getFromPrepared(preprocessPlayer(content)); for (const mode of ["n", "sig"] as const) { diff --git a/src/yt/solver/test/tests.ts b/src/yt/solver/test/tests.ts index d4c8eae..85afd6e 100644 --- a/src/yt/solver/test/tests.ts +++ b/src/yt/solver/test/tests.ts @@ -286,8 +286,6 @@ export const tests: { { // tce variant broke sig solving; n and other variants are added only for regression testing player: "c1c87fb0", - // TODO: fix other variants in other PR - variants: ["main", "tcc", "es5", "es6", "tv", "tv_es6", "phone"], n: [ // Synthetic test { input: "ZdZIqFPQK-Ty8wId", expected: "jCHBK5GuAFNa2" }, @@ -319,6 +317,172 @@ export const tests: { }, ], }, + { + // sig: tce: deep if: multiple matching but giving same solution + player: "42c5570b", + n: [ + // Synthetic test + { input: "ZdZIqFPQK-Ty8wId", expected: "CRoXjB-R-R" }, + ], + sig: [ + // Synthetic test + { + input: + "gN7a-hudCuAuPH6fByOk1_GNXN0yNMHShjZXS2VOgsEItAJz0tipeavEOmNdYN-wUtcEqD3bCXjc0iyKfAyZxCBGgIARwsSdQfJ2CJtt", + expected: + "EN7a-hudCuAuPH6fByOk1_GNXN0yNMHShjZXS2VOgsEItAJz0tipeavcOmNdYN-wUtgEqD3bCXjc0iyKfAyZxCBGgIARwsSdQfJ2CJtt", + }, + ], + }, + { + // sig: tce: deep if + player: "ed3f6ea5", + n: [ + // Synthetic test + { input: "ZdZIqFPQK-Ty8wId", expected: "CRoXjB-R-R" }, + ], + sig: [ + // Synthetic test + { + input: + "gN7a-hudCuAuPH6fByOk1_GNXN0yNMHShjZXS2VOgsEItAJz0tipeavEOmNdYN-wUtcEqD3bCXjc0iyKfAyZxCBGgIARwsSdQfJ2CJtt", + expected: + "EN7a-hudCuAuPH6fByOk1_GNXN0yNMHShjZXS2VOgsEItAJz0tipeavcOmNdYN-wUtgEqD3bCXjc0iyKfAyZxCBGgIARwsSdQfJ2CJtt", + }, + ], + }, + { + // sig: tce: deep if: another, similar structure using && instead of if + player: "d6afc319", + n: [ + // Synthetic test + { input: "ZdZIqFPQK-Ty8wId", expected: "5RA1UjcYMe33HCQ" }, + ], + sig: [ + // Synthetic test + { + input: + "gN7a-hudCuAuPH6fByOk1_GNXN0yNMHShjZXS2VOgsEItAJz0tipeavEOmNdYN-wUtcEqD3bCXjc0iyKfAyZxCBGgIARwsSdQfJ2CJtt", + expected: + "7a-hudCuAuPH6fByOk1_GNXN0yNMHShjZXt2VOgsEItAJz0tipeavEOmNdYN-wUtcEqD3bCXjc0iyKfAyZxCBGgIARwsSdQfJ2CJtS", + }, + ], + }, + { + // sig: tce: deep if + player: "8da75a6a", + n: [ + // Synthetic test + { input: "ZdZIqFPQK-Ty8wId", expected: "Q3JvBQziA7PvI" }, + ], + sig: [ + // Synthetic test + { + input: + "gN7a-hudCuAuPH6fByOk1_GNXN0yNMHShjZXS2VOgsEItAJz0tipeavEOmNdYN-wUtcEqD3bCXjc0iyKfAyZxCBGgIARwsSdQfJ2CJtt", + expected: + "g7aNhudCuAuPH6fByOk1_GNXN0yNMHShjZXS2VOgsEItAJz0tipeavEOmNdYN-wUtcEqD3bCXjc0iyKfAyJxCBGgIARwsSdQfJ2CZ", + }, + ], + }, + { + // sig: tce: call with 3 parameters + player: "54bd1de4", + n: [ + // Synthetic test + { input: "ZdZIqFPQK-Ty8wId", expected: "ka-slAQ31sijFN" }, + ], + sig: [ + // Synthetic test + { + input: + "gN7a-hudCuAuPH6fByOk1_GNXN0yNMHShjZXS2VOgsEItAJz0tipeavEOmNdYN-wUtcEqD3bCXjc0iyKfAyZxCBGgIARwsSdQfJ2CJtt", + expected: + "gN7a-hudCuAuPH6fByOk1_GNXN0yNMHShjZXS2VOgsEItAJz0titeavEOmNdYN-wUtcEqD3bCXjc0iyKfAyZxCBGgIARwsSdQfJ2CJtp", + }, + ], + }, + { + // sig: tce: call with 3 parameters + player: "f104ea90", + n: [ + // Synthetic test + { input: "ZdZIqFPQK-Ty8wId", expected: "n5DnuOYzgrSUbWp" }, + ], + sig: [ + // Synthetic test + { + input: + "gN7a-hudCuAuPH6fByOk1_GNXN0yNMHShjZXS2VOgsEItAJz0tipeavEOmNdYN-wUtcEqD3bCXjc0iyKfAyZxCBGgIARwsSdQfJ2CJtt", + expected: + "fJC2JtQdSswRAIgGBCxZyAfKyi0cjXCb3DqEctUw-NYdNmOEZaepit0z7AtIEsgOV2SX-jhSHMNy0NXNG_1kOyBf6HPuAuCduhv", + }, + ], + }, + { + // sig: tce: call with 3 parameters + player: "3510b6ff", + n: [ + // Synthetic test + { input: "ZdZIqFPQK-Ty8wId", expected: "n5DnuOYzgrSUbWp" }, + ], + sig: [ + // Synthetic test + { + input: + "gN7a-hudCuAuPH6fByOk1_GNXN0yNMHShjZXS2VOgsEItAJz0tipeavEOmNdYN-wUtcEqD3bCXjc0iyKfAyZxCBGgIARwsSdQfJ2CJtt", + expected: + "fJC2JtQdSswRAIgGBCxZyAfKyi0cjXCb3DqEctUw-NYdNmOEZaepit0z7AtIEsgOV2SX-jhSHMNy0NXNG_1kOyBf6HPuAuCduhv", + }, + ], + }, + { + // sig: tce: call with 3 parameters + player: "0675bd00", + n: [ + // Synthetic test + { input: "ZdZIqFPQK-Ty8wId", expected: "n5DnuOYzgrSUbWp" }, + ], + sig: [ + // Synthetic test + { + input: + "gN7a-hudCuAuPH6fByOk1_GNXN0yNMHShjZXS2VOgsEItAJz0tipeavEOmNdYN-wUtcEqD3bCXjc0iyKfAyZxCBGgIARwsSdQfJ2CJtt", + expected: + "fJC2JtQdSswRAIgGBCxZyAfKyi0cjXCb3DqEctUw-NYdNmOEZaepit0z7AtIEsgOV2SX-jhSHMNy0NXNG_1kOyBf6HPuAuCduhv", + }, + ], + }, + { + // sig: tce: call with 3 parameters + player: "e0528946", + n: [ + // Synthetic test + { input: "ZdZIqFPQK-Ty8wId", expected: "cGKEGBME8PGi7z" }, + ], + sig: [ + // Synthetic test + { + input: + "gN7a-hudCuAuPH6fByOk1_GNXN0yNMHShjZXS2VOgsEItAJz0tipeavEOmNdYN-wUtcEqD3bCXjc0iyKfAyZxCBGgIARwsSdQfJ2CJtt", + expected: + "7a-hudCuAuPH6fByOk1_GNXN0yNMgShjZXS2VOgsEItAJz0tipeavEOmNdYN-wUtcEqD3bCXjc0iyKfAyZxCBGgIARwsSdQfJ2C", + }, + ], + }, + { + // sig: es6: call with 3 parameters + player: "94667337", + n: [{ input: "BQoJvGBkC2nj1ZZLK-", expected: "ib1ShEOGoFXIIw" }], + sig: [ + { + input: + "NJAJEij0EwRgIhAI0KExTgjfPk-MPM9MAdzyyPRt=BM8-XO5tm5hlMCSVpAiEAv7eP3CURqZNSPow8BXXAoazVoXgeMP7gH9BdylHCwgw=gwzz", + expected: + "AJEij0EwRgIhAI0KExTgjfPk-MPM9MNdzyyPRtzBM8-XO5tm5hlMCSVpAiEAv7eP3CURqZNSPow8BXXAoazVoXgeMP7gH9BdylHCwgw=", + }, + ], + }, ]; export const players = new Map([ @@ -330,6 +494,8 @@ export const players = new Map([ ["tv", "tv-player-ias.vflset/tv-player-ias.js"], ["tv_es6", "tv-player-es6.vflset/tv-player-es6.js"], ["phone", "player-plasma-ias-phone-en_US.vflset/base.js"], + ["es6_tcc", "player_es6_tcc.vflset/en_US/base.js"], + ["es6_tce", "player_es6_tce.vflset/en_US/base.js"], ] as const); export type Variant = typeof players extends Map ? T : never;