/*
 * harvest-pot-console.js — PASTE INTO THE BROWSER DEVTOOLS CONSOLE on an
 * open https://www.youtube.com/watch?v=... tab. Companion to sabr-probe.mjs.
 *
 * On the modern web player the GVS PO token is NOT a URL ?pot= param — it is
 * carried inside the SABR POST body (VideoPlaybackAbrRequest protobuf:
 * field 19 streamerContext -> field 2 poToken). This snippet hooks fetch+XHR,
 * intercepts the page player's own videoplayback requests, and extracts that
 * token + the bound visitorData so you can replay them in the node PoC:
 *
 *     node tools/sabr-probe.mjs BRfjeH366EY --pot='<POT>' --visitor='<VD>'
 *
 * Pure observation: no eval, no remote code. After pasting, PLAY or SEEK the
 * video so the player fires a fresh SABR request for the hook to catch.
 */
(() => {
  const seen = new Set();

  const readVarint = (buf, pos) => {
    let result = 0, shift = 0, b;
    do { b = buf[pos++]; result += (b & 0x7f) * Math.pow(2, shift); shift += 7; } while (b & 0x80);
    return [result, pos];
  };
  // return the bytes of the first length-delimited (wiretype 2) field == target
  const field = (buf, target) => {
    let pos = 0;
    while (pos < buf.length) {
      let tag; [tag, pos] = readVarint(buf, pos);
      const f = Math.floor(tag / 8), wt = tag & 7;
      if (wt === 2) { let len; [len, pos] = readVarint(buf, pos); if (f === target) return buf.subarray(pos, pos + len); pos += len; }
      else if (wt === 0) { [, pos] = readVarint(buf, pos); }
      else if (wt === 1) pos += 8;
      else if (wt === 5) pos += 4;
      else return null;
    }
    return null;
  };
  const b64url = (u8) => { let s = ''; for (const c of u8) s += String.fromCharCode(c); return btoa(s).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); };

  const toU8 = async (body, input) => {
    if (body == null && input instanceof Request) { try { return new Uint8Array(await input.clone().arrayBuffer()); } catch { return null; } }
    if (body instanceof Blob) return new Uint8Array(await body.arrayBuffer());
    if (body instanceof ArrayBuffer) return new Uint8Array(body);
    if (ArrayBuffer.isView(body)) return new Uint8Array(body.buffer, body.byteOffset, body.byteLength);
    return null;
  };

  const visitor = (() => { try { return window.ytcfg && ytcfg.get('VISITOR_DATA'); } catch { return ''; } })();
  const videoId = (() => {
    try { return new URLSearchParams(location.search).get('v') || (location.pathname.match(/\/(?:shorts|embed)\/([\w-]{11})/) || [])[1] || ''; } catch { return ''; }
  })();
  console.log('%c[pot-harvest] visitorData =', 'color:#0a0', visitor || '(none — run on a watch page)');

  const report = (pot, src) => {
    if (!pot || seen.has(pot)) return;
    seen.add(pot);
    console.log('%c[pot-harvest] POT FOUND (%s, %d chars)', 'color:#08f;font-weight:bold', src, pot.length);
    console.log(pot);
    console.log('%c[pot-harvest] run:', 'color:#0a0', `node tools/sabr-probe.mjs <videoId> --pot='${pot}' --visitor='${visitor}'`);
  };

  // Emit the page's EXACT SABR request (url + full body) so it can be replayed
  // verbatim from node — removes every pot/ustreamer/visitor binding variable.
  let capturedOnce = false;
  const emitCapture = (url, u8, pot) => {
    if (capturedOnce) return;
    capturedOnce = true;
    let s = ''; for (const c of u8) s += String.fromCharCode(c);
    const cap = { url, bodyB64: btoa(s), pot, visitor, videoId };
    const json = JSON.stringify(cap);
    console.log('%c[pot-harvest] FULL SABR CAPTURE (%d body bytes) — save to tools/captured.json:', 'color:#08f;font-weight:bold', u8.length);
    console.log(json);
    try { copy(json); console.log('%c[pot-harvest] capture JSON copied to clipboard → paste into tools/captured.json, then: node tools/sabr-replay.mjs', 'color:#0a0'); } catch {}
  };

  const scan = async (url, body, input) => {
    if (!/googlevideo\.com\/.*videoplayback|\/videoplayback\?/.test(url || '')) return;
    const u = (url.match(/[?&]pot=([^&]+)/) || [])[1];
    if (u) report(decodeURIComponent(u), 'url ?pot=');
    try {
      const u8 = await toU8(body, input);
      if (!u8) return;
      const sc = field(u8, 19); // streamerContext
      const pt = sc && field(sc, 2); // poToken
      const pot = pt && pt.length ? b64url(pt) : '';
      if (pot) report(pot, 'SABR body');
      if (u8.length > 0) emitCapture(url, u8, pot); // POST body present = real SABR request
    } catch {}
  };

  const of = window.fetch;
  window.fetch = function (input, init) {
    try { const url = typeof input === 'string' ? input : (input && input.url) || ''; scan(url, init && init.body, input); } catch {}
    return of.apply(this, arguments);
  };
  const oo = XMLHttpRequest.prototype.open, os = XMLHttpRequest.prototype.send;
  XMLHttpRequest.prototype.open = function (m, url) { this.__u = url; return oo.apply(this, arguments); };
  XMLHttpRequest.prototype.send = function (body) { try { scan(this.__u, body); } catch {} return os.apply(this, arguments); };

  console.log('%c[pot-harvest] hook installed — now PLAY or SEEK the video to trigger a SABR request.', 'color:#a60');
})();
