Skip to content

Instantly share code, notes, and snippets.

@laiso
Last active February 27, 2025 04:14
Show Gist options
  • Save laiso/66d4547d6947eaa7e7da545dbfbdb720 to your computer and use it in GitHub Desktop.
Save laiso/66d4547d6947eaa7e7da545dbfbdb720 to your computer and use it in GitHub Desktop.
async function listNotebooks() {
const authParams = await getAuthParams();
const { url: n, headers: r, body: o } = await createBatchExecuteRequest(authParams);
const response = await fetch(n.toString(), {
method: "POST",
headers: r,
body: o
});
const text = await response.text();
const parsedResponse = parseBatchExecuteResponse(text);
return parsedResponse.map(item => ({
id: item.data[2],
title: item.data[0],
emoji: item.data[3]
}));
}
async function getAuthParams() {
const response = await fetch("https://notebooklm.google.com/", {
method: "GET",
redirect: "error"
});
const text = await response.text();
const at = extractValue("SNlM0e", text);
const bl = extractValue("cfb2h", text);
if (!at || !bl) {
throw new Error("Please sign-in to your Google account to use NotebookLM");
}
return {
at,
bl
};
}
function extractValue(key, text) {
const match = text.match(new RegExp(`"${key}":"([^"]+)"`));
return match ? match[1] : null;
}
async function createBatchExecuteRequest(authParams) {
const url = new URL(`https://notebooklm.google.com/_/LabsTailwindUi/data/batchexecute`);
url.searchParams.append("rpcids", "wXbhsf"); // Only 'wXbhsf' RPC ID is used here.
url.searchParams.append("_reqid", gC().toString()); // gC() is a helper function to generate a random number.
url.searchParams.append("source-path", "/");
url.searchParams.append("rt", "c");
const headers = new Headers({ "Content-Type": "application/x-www-form-urlencoded;charset=utf-8" });
const body = new URLSearchParams({ "f.req": JSON.stringify([["wXbhsf", [null, 1], null, "generic"]]) }); // Hardcoded for listNotebooks RPC.
url.searchParams.append("bl", authParams.bl); //Append auth parameters
body.append("at", authParams.at); //Append auth parameters
return { url, headers, body };
}
function parseBatchExecuteResponse(response) {
const extractedData = extractDataFromResponse(response); //Helper function. Not included in this flat function.
return extractedData;
}
function extractDataFromResponse(response) {
const t = response.split('\n').slice(2).join('');
const n = JSON.parse(t);
const r = [];
for (const o of n) {
if (o[0] !== 'wrb.fr') continue;
let i;
o[6] === 'generic' ? i = 1 : i = parseInt(o[6], 10);
const s = o[1], l = JSON.parse(o[2]);
r.push({ index: i, rpcId: s, data: l });
}
return r.map(item => item.data);
}
function gC() {
return Math.floor(Math.random() * 9e5) + 1e5;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment