/*!
 * SPDX-License-Identifier: Unlicense
 * This file was automatically generated by https://github.com/yt-dlp/ejs
 */
var jsc = (function (meriyah, astring) {
  'use strict';
  function matchesStructure(obj, structure) {
    if (Array.isArray(structure)) {
      if (!Array.isArray(obj)) {
        return false;
      }
      return (
        structure.length === obj.length &&
        structure.every((value, index) => matchesStructure(obj[index], value))
      );
    }
    if (typeof structure === 'object') {
      if (!obj) {
        return !structure;
      }
      if ('or' in structure) {
        return structure.or.some((node) => matchesStructure(obj, node));
      }
      if ('anykey' in structure && Array.isArray(structure.anykey)) {
        const haystack = Array.isArray(obj) ? obj : Object.values(obj);
        return structure.anykey.every((value) =>
          haystack.some((el) => matchesStructure(el, value)),
        );
      }
      for (const [key, value] of Object.entries(structure)) {
        if (!matchesStructure(obj[key], value)) {
          return false;
        }
      }
      return true;
    }
    return structure === obj;
  }
  function isOneOf(value, ...of) {
    return of.includes(value);
  }
  function _optionalChain$2(ops) {
    let lastAccessLHS = undefined;
    let value = ops[0];
    let i = 1;
    while (i < ops.length) {
      const op = ops[i];
      const fn = ops[i + 1];
      i += 2;
      if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) {
        return undefined;
      }
      if (op === 'access' || op === 'optionalAccess') {
        lastAccessLHS = value;
        value = fn(value);
      } else if (op === 'call' || op === 'optionalCall') {
        value = fn((...args) => value.call(lastAccessLHS, ...args));
        lastAccessLHS = undefined;
      }
    }
    return value;
  }
  const logicalExpression = {
    type: 'ExpressionStatement',
    expression: {
      type: 'LogicalExpression',
      left: { type: 'Identifier' },
      right: {
        type: 'SequenceExpression',
        expressions: [
          {
            type: 'AssignmentExpression',
            left: { type: 'Identifier' },
            operator: '=',
            right: {
              type: 'CallExpression',
              callee: { type: 'Identifier' },
              arguments: {
                or: [
                  [
                    { type: 'Literal' },
                    {
                      type: 'CallExpression',
                      callee: {
                        type: 'Identifier',
                        name: 'decodeURIComponent',
                      },
                      arguments: [{ type: 'Identifier' }],
                      optional: false,
                    },
                  ],
                  [
                    {
                      type: 'CallExpression',
                      callee: {
                        type: 'Identifier',
                        name: 'decodeURIComponent',
                      },
                      arguments: [{ type: 'Identifier' }],
                      optional: false,
                    },
                  ],
                ],
              },
              optional: false,
            },
          },
          { type: 'CallExpression' },
        ],
      },
      operator: '&&',
    },
  };
  const identifier$1 = {
    or: [
      {
        type: 'ExpressionStatement',
        expression: {
          type: 'AssignmentExpression',
          operator: '=',
          left: { type: 'Identifier' },
          right: { type: 'FunctionExpression', params: [{}, {}, {}] },
        },
      },
      { type: 'FunctionDeclaration', params: [{}, {}, {}] },
      {
        type: 'VariableDeclaration',
        declarations: {
          anykey: [
            {
              type: 'VariableDeclarator',
              init: { type: 'FunctionExpression', params: [{}, {}, {}] },
            },
          ],
        },
      },
    ],
  };
  function extract$1(node) {
    if (!matchesStructure(node, identifier$1)) {
      return null;
    }
    let block;
    if (
      node.type === 'ExpressionStatement' &&
      node.expression.type === 'AssignmentExpression' &&
      node.expression.right.type === 'FunctionExpression'
    ) {
      block = node.expression.right.body;
    } else if (node.type === 'VariableDeclaration') {
      for (const decl of node.declarations) {
        if (
          decl.type === 'VariableDeclarator' &&
          _optionalChain$2([
            decl,
            'access',
            (_) => _.init,
            'optionalAccess',
            (_2) => _2.type,
          ]) === 'FunctionExpression' &&
          _optionalChain$2([
            decl,
            'access',
            (_3) => _3.init,
            'optionalAccess',
            (_4) => _4.params,
            'access',
            (_5) => _5.length,
          ]) === 3
        ) {
          block = decl.init.body;
          break;
        }
      }
    } else if (node.type === 'FunctionDeclaration') {
      block = node.body;
    } else {
      return null;
    }
    const relevantExpression = _optionalChain$2([
      block,
      'optionalAccess',
      (_6) => _6.body,
      'access',
      (_7) => _7.at,
      'call',
      (_8) => _8(-2),
    ]);
    if (!matchesStructure(relevantExpression, logicalExpression)) {
      return null;
    }
    if (
      _optionalChain$2([
        relevantExpression,
        'optionalAccess',
        (_9) => _9.type,
      ]) !== 'ExpressionStatement' ||
      relevantExpression.expression.type !== 'LogicalExpression' ||
      relevantExpression.expression.right.type !== 'SequenceExpression' ||
      relevantExpression.expression.right.expressions[0].type !==
        'AssignmentExpression'
    ) {
      return null;
    }
    const call = relevantExpression.expression.right.expressions[0].right;
    if (call.type !== 'CallExpression' || call.callee.type !== 'Identifier') {
      return null;
    }
    return {
      type: 'ArrowFunctionExpression',
      params: [{ type: 'Identifier', name: 'sig' }],
      body: {
        type: 'CallExpression',
        callee: { type: 'Identifier', name: call.callee.name },
        arguments:
          call.arguments.length === 1
            ? [{ type: 'Identifier', name: 'sig' }]
            : [call.arguments[0], { type: 'Identifier', name: 'sig' }],
        optional: false,
      },
      async: false,
      expression: false,
      generator: false,
    };
  }
  function _optionalChain$1(ops) {
    let lastAccessLHS = undefined;
    let value = ops[0];
    let i = 1;
    while (i < ops.length) {
      const op = ops[i];
      const fn = ops[i + 1];
      i += 2;
      if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) {
        return undefined;
      }
      if (op === 'access' || op === 'optionalAccess') {
        lastAccessLHS = value;
        value = fn(value);
      } else if (op === 'call' || op === 'optionalCall') {
        value = fn((...args) => value.call(lastAccessLHS, ...args));
        lastAccessLHS = undefined;
      }
    }
    return value;
  }
  const identifier = {
    or: [
      {
        type: 'VariableDeclaration',
        kind: 'var',
        declarations: {
          anykey: [
            {
              type: 'VariableDeclarator',
              id: { type: 'Identifier' },
              init: {
                type: 'ArrayExpression',
                elements: [{ type: 'Identifier' }],
              },
            },
          ],
        },
      },
      {
        type: 'ExpressionStatement',
        expression: {
          type: 'AssignmentExpression',
          left: { type: 'Identifier' },
          operator: '=',
          right: {
            type: 'ArrayExpression',
            elements: [{ type: 'Identifier' }],
          },
        },
      },
    ],
  };
  const catchBlockBody = [
    {
      type: 'ReturnStatement',
      argument: {
        type: 'BinaryExpression',
        left: {
          type: 'MemberExpression',
          object: { type: 'Identifier' },
          computed: true,
          property: { type: 'Literal' },
          optional: false,
        },
        right: { type: 'Identifier' },
        operator: '+',
      },
    },
  ];
  function extract(node) {
    if (!matchesStructure(node, identifier)) {
      let name = null;
      let block = null;
      switch (node.type) {
        case 'ExpressionStatement': {
          if (
            node.expression.type === 'AssignmentExpression' &&
            node.expression.left.type === 'Identifier' &&
            node.expression.right.type === 'FunctionExpression' &&
            node.expression.right.params.length === 1
          ) {
            name = node.expression.left.name;
            block = node.expression.right.body;
          }
          break;
        }
        case 'FunctionDeclaration': {
          if (node.params.length === 1) {
            name = _optionalChain$1([
              node,
              'access',
              (_) => _.id,
              'optionalAccess',
              (_2) => _2.name,
            ]);
            block = node.body;
          }
          break;
        }
      }
      if (!block || !name) {
        return null;
      }
      const tryNode = block.body.at(-2);
      if (
        _optionalChain$1([tryNode, 'optionalAccess', (_3) => _3.type]) !==
          'TryStatement' ||
        _optionalChain$1([
          tryNode,
          'access',
          (_4) => _4.handler,
          'optionalAccess',
          (_5) => _5.type,
        ]) !== 'CatchClause'
      ) {
        return null;
      }
      const catchBody = tryNode.handler.body.body;
      if (matchesStructure(catchBody, catchBlockBody)) {
        return makeSolverFuncFromName(name);
      }
      return null;
    }
    if (node.type === 'VariableDeclaration') {
      for (const declaration of node.declarations) {
        if (
          declaration.type !== 'VariableDeclarator' ||
          !declaration.init ||
          declaration.init.type !== 'ArrayExpression' ||
          declaration.init.elements.length !== 1
        ) {
          continue;
        }
        const [firstElement] = declaration.init.elements;
        if (firstElement && firstElement.type === 'Identifier') {
          return makeSolverFuncFromName(firstElement.name);
        }
      }
    } else if (node.type === 'ExpressionStatement') {
      const expr = node.expression;
      if (
        expr.type === 'AssignmentExpression' &&
        expr.left.type === 'Identifier' &&
        expr.operator === '=' &&
        expr.right.type === 'ArrayExpression' &&
        expr.right.elements.length === 1
      ) {
        const [firstElement] = expr.right.elements;
        if (firstElement && firstElement.type === 'Identifier') {
          return makeSolverFuncFromName(firstElement.name);
        }
      }
    }
    return null;
  }
  function makeSolverFuncFromName(name) {
    return {
      type: 'ArrowFunctionExpression',
      params: [{ type: 'Identifier', name: 'n' }],
      body: {
        type: 'CallExpression',
        callee: { type: 'Identifier', name: name },
        arguments: [{ type: 'Identifier', name: 'n' }],
        optional: false,
      },
      async: false,
      expression: false,
      generator: false,
    };
  }
  const setupNodes = meriyah.parse(
    `\nif (typeof globalThis.XMLHttpRequest === "undefined") {\n    globalThis.XMLHttpRequest = { prototype: {} };\n}\nconst window = Object.create(null);\nif (typeof URL === "undefined") {\n    window.location = {\n        hash: "",\n        host: "www.youtube.com",\n        hostname: "www.youtube.com",\n        href: "https://www.youtube.com/watch?v=yt-dlp-wins",\n        origin: "https://www.youtube.com",\n        password: "",\n        pathname: "/watch",\n        port: "",\n        protocol: "https:",\n        search: "?v=yt-dlp-wins",\n        username: "",\n    };\n} else {\n    window.location = new URL("https://www.youtube.com/watch?v=yt-dlp-wins");\n}\nif (typeof globalThis.document === "undefined") {\n    globalThis.document = Object.create(null);\n}\nif (typeof globalThis.navigator === "undefined") {\n    globalThis.navigator = Object.create(null);\n}\nif (typeof globalThis.self === "undefined") {\n    globalThis.self = globalThis;\n}\n`,
  ).body;
  function _optionalChain(ops) {
    let lastAccessLHS = undefined;
    let value = ops[0];
    let i = 1;
    while (i < ops.length) {
      const op = ops[i];
      const fn = ops[i + 1];
      i += 2;
      if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) {
        return undefined;
      }
      if (op === 'access' || op === 'optionalAccess') {
        lastAccessLHS = value;
        value = fn(value);
      } else if (op === 'call' || op === 'optionalCall') {
        value = fn((...args) => value.call(lastAccessLHS, ...args));
        lastAccessLHS = undefined;
      }
    }
    return value;
  }
  function preprocessPlayer(data) {
    const ast = meriyah.parse(data);
    const body = ast.body;
    const block = (() => {
      switch (body.length) {
        case 1: {
          const func = body[0];
          if (
            _optionalChain([func, 'optionalAccess', (_) => _.type]) ===
              'ExpressionStatement' &&
            func.expression.type === 'CallExpression' &&
            func.expression.callee.type === 'MemberExpression' &&
            func.expression.callee.object.type === 'FunctionExpression'
          ) {
            return func.expression.callee.object.body;
          }
          break;
        }
        case 2: {
          const func = body[1];
          if (
            _optionalChain([func, 'optionalAccess', (_2) => _2.type]) ===
              'ExpressionStatement' &&
            func.expression.type === 'CallExpression' &&
            func.expression.callee.type === 'FunctionExpression'
          ) {
            const block = func.expression.callee.body;
            block.body.splice(0, 1);
            return block;
          }
          break;
        }
      }
      throw 'unexpected structure';
    })();
    const found = { n: [], sig: [] };
    const plainExpressions = block.body.filter((node) => {
      const n = extract(node);
      if (n) {
        found.n.push(n);
      }
      const sig = extract$1(node);
      if (sig) {
        found.sig.push(sig);
      }
      if (node.type === 'ExpressionStatement') {
        if (node.expression.type === 'AssignmentExpression') {
          return true;
        }
        return node.expression.type === 'Literal';
      }
      return true;
    });
    block.body = plainExpressions;
    for (const [name, options] of Object.entries(found)) {
      const unique = new Set(options.map((x) => JSON.stringify(x)));
      if (unique.size !== 1) {
        const message = `found ${unique.size} ${name} function possibilities`;
        throw (
          message +
          (unique.size
            ? `: ${options.map((x) => astring.generate(x)).join(', ')}`
            : '')
        );
      }
      plainExpressions.push({
        type: 'ExpressionStatement',
        expression: {
          type: 'AssignmentExpression',
          operator: '=',
          left: {
            type: 'MemberExpression',
            computed: false,
            object: { type: 'Identifier', name: '_result' },
            property: { type: 'Identifier', name: name },
          },
          right: options[0],
        },
      });
    }
    ast.body.splice(0, 0, ...setupNodes);
    return astring.generate(ast);
  }
  function getFromPrepared(code) {
    const resultObj = { n: null, sig: null };
    Function('_result', code)(resultObj);
    return resultObj;
  }
  function main(input) {
    const preprocessedPlayer =
      input.type === 'player'
        ? preprocessPlayer(input.player)
        : input.preprocessed_player;
    const solvers = getFromPrepared(preprocessedPlayer);
    const responses = input.requests.map((input) => {
      if (!isOneOf(input.type, 'n', 'sig')) {
        return { type: 'error', error: `Unknown request type: ${input.type}` };
      }
      const solver = solvers[input.type];
      if (!solver) {
        return {
          type: 'error',
          error: `Failed to extract ${input.type} function`,
        };
      }
      try {
        return {
          type: 'result',
          data: Object.fromEntries(
            input.challenges.map((challenge) => [challenge, solver(challenge)]),
          ),
        };
      } catch (error) {
        return {
          type: 'error',
          error:
            error instanceof Error
              ? `${error.message}\n${error.stack}`
              : `${error}`,
        };
      }
    });
    const output = { type: 'result', responses: responses };
    if (input.type === 'player' && input.output_preprocessed) {
      output.preprocessed_player = preprocessedPlayer;
    }
    return output;
  }
  return main;
})(meriyah, astring);
