@pan-sec/notebooklm-mcp 1.6.0 ā 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +10 -0
- package/dist/config.js.map +1 -1
- package/dist/events/event-emitter.d.ts +45 -0
- package/dist/events/event-emitter.d.ts.map +1 -0
- package/dist/events/event-emitter.js +100 -0
- package/dist/events/event-emitter.js.map +1 -0
- package/dist/events/event-types.d.ts +124 -0
- package/dist/events/event-types.d.ts.map +1 -0
- package/dist/events/event-types.js +18 -0
- package/dist/events/event-types.js.map +1 -0
- package/dist/gemini/gemini-client.d.ts +45 -0
- package/dist/gemini/gemini-client.d.ts.map +1 -0
- package/dist/gemini/gemini-client.js +211 -0
- package/dist/gemini/gemini-client.js.map +1 -0
- package/dist/gemini/index.d.ts +8 -0
- package/dist/gemini/index.d.ts.map +1 -0
- package/dist/gemini/index.js +8 -0
- package/dist/gemini/index.js.map +1 -0
- package/dist/gemini/types.d.ts +136 -0
- package/dist/gemini/types.d.ts.map +1 -0
- package/dist/gemini/types.js +10 -0
- package/dist/gemini/types.js.map +1 -0
- package/dist/index.js +76 -3
- package/dist/index.js.map +1 -1
- package/dist/library/notebook-library.d.ts +25 -2
- package/dist/library/notebook-library.d.ts.map +1 -1
- package/dist/library/notebook-library.js +142 -2
- package/dist/library/notebook-library.js.map +1 -1
- package/dist/library/types.d.ts +15 -0
- package/dist/library/types.d.ts.map +1 -1
- package/dist/notebook-creation/audio-manager.d.ts +56 -0
- package/dist/notebook-creation/audio-manager.d.ts.map +1 -0
- package/dist/notebook-creation/audio-manager.js +335 -0
- package/dist/notebook-creation/audio-manager.js.map +1 -0
- package/dist/notebook-creation/discover-creation-flow.d.ts +8 -0
- package/dist/notebook-creation/discover-creation-flow.d.ts.map +1 -0
- package/dist/notebook-creation/discover-creation-flow.js +177 -0
- package/dist/notebook-creation/discover-creation-flow.js.map +1 -0
- package/dist/notebook-creation/discover-quota.d.ts +8 -0
- package/dist/notebook-creation/discover-quota.d.ts.map +1 -0
- package/dist/notebook-creation/discover-quota.js +195 -0
- package/dist/notebook-creation/discover-quota.js.map +1 -0
- package/dist/notebook-creation/discover-source-dialog.d.ts +8 -0
- package/dist/notebook-creation/discover-source-dialog.d.ts.map +1 -0
- package/dist/notebook-creation/discover-source-dialog.js +134 -0
- package/dist/notebook-creation/discover-source-dialog.js.map +1 -0
- package/dist/notebook-creation/discover-sources.d.ts +8 -0
- package/dist/notebook-creation/discover-sources.d.ts.map +1 -0
- package/dist/notebook-creation/discover-sources.js +273 -0
- package/dist/notebook-creation/discover-sources.js.map +1 -0
- package/dist/notebook-creation/discover-text-input.d.ts +7 -0
- package/dist/notebook-creation/discover-text-input.d.ts.map +1 -0
- package/dist/notebook-creation/discover-text-input.js +135 -0
- package/dist/notebook-creation/discover-text-input.js.map +1 -0
- package/dist/notebook-creation/index.d.ts +12 -0
- package/dist/notebook-creation/index.d.ts.map +1 -0
- package/dist/notebook-creation/index.js +12 -0
- package/dist/notebook-creation/index.js.map +1 -0
- package/dist/notebook-creation/notebook-creator.d.ts +95 -0
- package/dist/notebook-creation/notebook-creator.d.ts.map +1 -0
- package/dist/notebook-creation/notebook-creator.js +689 -0
- package/dist/notebook-creation/notebook-creator.js.map +1 -0
- package/dist/notebook-creation/notebook-sync.d.ts +93 -0
- package/dist/notebook-creation/notebook-sync.d.ts.map +1 -0
- package/dist/notebook-creation/notebook-sync.js +370 -0
- package/dist/notebook-creation/notebook-sync.js.map +1 -0
- package/dist/notebook-creation/run-discovery.d.ts +11 -0
- package/dist/notebook-creation/run-discovery.d.ts.map +1 -0
- package/dist/notebook-creation/run-discovery.js +151 -0
- package/dist/notebook-creation/run-discovery.js.map +1 -0
- package/dist/notebook-creation/selector-discovery.d.ts +65 -0
- package/dist/notebook-creation/selector-discovery.d.ts.map +1 -0
- package/dist/notebook-creation/selector-discovery.js +421 -0
- package/dist/notebook-creation/selector-discovery.js.map +1 -0
- package/dist/notebook-creation/selectors.d.ts +150 -0
- package/dist/notebook-creation/selectors.d.ts.map +1 -0
- package/dist/notebook-creation/selectors.js +225 -0
- package/dist/notebook-creation/selectors.js.map +1 -0
- package/dist/notebook-creation/source-manager.d.ts +73 -0
- package/dist/notebook-creation/source-manager.d.ts.map +1 -0
- package/dist/notebook-creation/source-manager.js +486 -0
- package/dist/notebook-creation/source-manager.js.map +1 -0
- package/dist/notebook-creation/test-create.d.ts +8 -0
- package/dist/notebook-creation/test-create.d.ts.map +1 -0
- package/dist/notebook-creation/test-create.js +72 -0
- package/dist/notebook-creation/test-create.js.map +1 -0
- package/dist/notebook-creation/types.d.ts +173 -0
- package/dist/notebook-creation/types.d.ts.map +1 -0
- package/dist/notebook-creation/types.js +5 -0
- package/dist/notebook-creation/types.js.map +1 -0
- package/dist/quota/index.d.ts +8 -0
- package/dist/quota/index.d.ts.map +1 -0
- package/dist/quota/index.js +8 -0
- package/dist/quota/index.js.map +1 -0
- package/dist/quota/quota-manager.d.ts +125 -0
- package/dist/quota/quota-manager.d.ts.map +1 -0
- package/dist/quota/quota-manager.js +330 -0
- package/dist/quota/quota-manager.js.map +1 -0
- package/dist/session/session-manager.d.ts +5 -0
- package/dist/session/session-manager.d.ts.map +1 -1
- package/dist/session/session-manager.js +6 -0
- package/dist/session/session-manager.js.map +1 -1
- package/dist/tools/definitions/gemini.d.ts +12 -0
- package/dist/tools/definitions/gemini.d.ts.map +1 -0
- package/dist/tools/definitions/gemini.js +135 -0
- package/dist/tools/definitions/gemini.js.map +1 -0
- package/dist/tools/definitions/notebook-management.d.ts.map +1 -1
- package/dist/tools/definitions/notebook-management.js +525 -0
- package/dist/tools/definitions/notebook-management.js.map +1 -1
- package/dist/tools/definitions/system.d.ts.map +1 -1
- package/dist/tools/definitions/system.js +158 -0
- package/dist/tools/definitions/system.js.map +1 -1
- package/dist/tools/definitions.d.ts.map +1 -1
- package/dist/tools/definitions.js +2 -0
- package/dist/tools/definitions.js.map +1 -1
- package/dist/tools/handlers.d.ts +257 -0
- package/dist/tools/handlers.d.ts.map +1 -1
- package/dist/tools/handlers.js +1097 -0
- package/dist/tools/handlers.js.map +1 -1
- package/dist/webhooks/index.d.ts +8 -0
- package/dist/webhooks/index.d.ts.map +1 -0
- package/dist/webhooks/index.js +8 -0
- package/dist/webhooks/index.js.map +1 -0
- package/dist/webhooks/types.d.ts +57 -0
- package/dist/webhooks/types.d.ts.map +1 -0
- package/dist/webhooks/types.js +5 -0
- package/dist/webhooks/types.js.map +1 -0
- package/dist/webhooks/webhook-dispatcher.d.ts +120 -0
- package/dist/webhooks/webhook-dispatcher.d.ts.map +1 -0
- package/dist/webhooks/webhook-dispatcher.js +519 -0
- package/dist/webhooks/webhook-dispatcher.js.map +1 -0
- package/package.json +2 -1
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discover Quota/License UI Elements
|
|
3
|
+
*
|
|
4
|
+
* Finds where license tier and usage limits are displayed in NotebookLM.
|
|
5
|
+
* Run: node dist/notebook-creation/discover-quota.js
|
|
6
|
+
*/
|
|
7
|
+
import { AuthManager } from "../auth/auth-manager.js";
|
|
8
|
+
import { SharedContextManager } from "../session/shared-context-manager.js";
|
|
9
|
+
import { log } from "../utils/logger.js";
|
|
10
|
+
const NOTEBOOKLM_URL = "https://notebooklm.google.com/";
|
|
11
|
+
async function findQuotaElements(page, description) {
|
|
12
|
+
log.info(`\nš ${description}:`);
|
|
13
|
+
// Look for quota-related text patterns
|
|
14
|
+
const quotaInfo = await page.evaluate(() => {
|
|
15
|
+
const results = [];
|
|
16
|
+
// Get all text content and look for quota patterns
|
|
17
|
+
// @ts-expect-error - DOM types
|
|
18
|
+
const allElements = document.querySelectorAll('*');
|
|
19
|
+
for (const el of allElements) {
|
|
20
|
+
const text = el.textContent?.trim() || "";
|
|
21
|
+
// Skip very long text (likely containers)
|
|
22
|
+
if (text.length > 200)
|
|
23
|
+
continue;
|
|
24
|
+
// Look for quota-related patterns
|
|
25
|
+
const patterns = [
|
|
26
|
+
/pro/i,
|
|
27
|
+
/free/i,
|
|
28
|
+
/limit/i,
|
|
29
|
+
/\d+\s*\/\s*\d+/, // X/Y format
|
|
30
|
+
/source/i,
|
|
31
|
+
/notebook/i,
|
|
32
|
+
/quota/i,
|
|
33
|
+
/usage/i,
|
|
34
|
+
/upgrade/i,
|
|
35
|
+
/plan/i,
|
|
36
|
+
/subscription/i,
|
|
37
|
+
];
|
|
38
|
+
for (const pattern of patterns) {
|
|
39
|
+
if (pattern.test(text) && text.length < 100) {
|
|
40
|
+
// Get more context
|
|
41
|
+
const tag = el.tagName;
|
|
42
|
+
const className = el.className?.substring?.(0, 50) || "";
|
|
43
|
+
const ariaLabel = el.getAttribute("aria-label") || "";
|
|
44
|
+
results.push(`[${tag}] "${text}" class="${className}" aria="${ariaLabel}"`);
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Deduplicate
|
|
50
|
+
return [...new Set(results)];
|
|
51
|
+
});
|
|
52
|
+
for (const item of quotaInfo) {
|
|
53
|
+
log.dim(` ${item}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async function extractQuotaFromHomepage(page) {
|
|
57
|
+
log.info("\nš Extracting quota info from homepage...");
|
|
58
|
+
const info = await page.evaluate(() => {
|
|
59
|
+
const result = { rawTexts: [] };
|
|
60
|
+
// Look for PRO/FREE badge
|
|
61
|
+
// @ts-expect-error - DOM types
|
|
62
|
+
const allText = document.body.innerText;
|
|
63
|
+
if (allText.includes("PRO")) {
|
|
64
|
+
result.tier = "pro";
|
|
65
|
+
}
|
|
66
|
+
else if (allText.match(/free\s*(tier|plan|account)/i)) {
|
|
67
|
+
result.tier = "free";
|
|
68
|
+
}
|
|
69
|
+
// Count notebooks in the table
|
|
70
|
+
// @ts-expect-error - DOM types
|
|
71
|
+
const rows = document.querySelectorAll('tr');
|
|
72
|
+
let notebookCount = 0;
|
|
73
|
+
for (const row of rows) {
|
|
74
|
+
if (row.textContent?.includes("Source")) {
|
|
75
|
+
notebookCount++;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (notebookCount > 0) {
|
|
79
|
+
result.notebookCount = notebookCount;
|
|
80
|
+
}
|
|
81
|
+
// Look for X/Y patterns (like "0/300")
|
|
82
|
+
const limitMatches = allText.match(/(\d+)\s*\/\s*(\d+)/g) || [];
|
|
83
|
+
result.rawTexts = limitMatches;
|
|
84
|
+
return result;
|
|
85
|
+
});
|
|
86
|
+
log.info(` Tier: ${info.tier || "unknown"}`);
|
|
87
|
+
log.info(` Notebook count: ${info.notebookCount || "unknown"}`);
|
|
88
|
+
log.info(` Limit patterns found: ${info.rawTexts?.join(", ") || "none"}`);
|
|
89
|
+
return info;
|
|
90
|
+
}
|
|
91
|
+
async function checkSettingsPage(page) {
|
|
92
|
+
log.info("\nš Checking Settings for quota info...");
|
|
93
|
+
// Try to click Settings button
|
|
94
|
+
const settingsClicked = await page.evaluate(() => {
|
|
95
|
+
// @ts-expect-error - DOM types
|
|
96
|
+
const buttons = document.querySelectorAll('button');
|
|
97
|
+
for (const btn of buttons) {
|
|
98
|
+
const aria = btn.getAttribute("aria-label")?.toLowerCase() || "";
|
|
99
|
+
const text = btn.textContent?.toLowerCase() || "";
|
|
100
|
+
if (aria.includes("settings") || text.includes("settings")) {
|
|
101
|
+
btn.click();
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return false;
|
|
106
|
+
});
|
|
107
|
+
if (settingsClicked) {
|
|
108
|
+
log.success(" ā
Clicked Settings button");
|
|
109
|
+
await page.waitForTimeout(2000);
|
|
110
|
+
await findQuotaElements(page, "Settings dialog elements");
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
log.warning(" ā ļø Could not find Settings button");
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async function checkSourceDialog(page) {
|
|
117
|
+
log.info("\nš Checking Source Dialog for limits...");
|
|
118
|
+
// Create a new notebook to see the source dialog
|
|
119
|
+
const createClicked = await page.evaluate(() => {
|
|
120
|
+
// @ts-expect-error - DOM types
|
|
121
|
+
const buttons = document.querySelectorAll('button');
|
|
122
|
+
for (const btn of buttons) {
|
|
123
|
+
const aria = btn.getAttribute("aria-label") || "";
|
|
124
|
+
if (aria.includes("Create new notebook")) {
|
|
125
|
+
btn.click();
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return false;
|
|
130
|
+
});
|
|
131
|
+
if (createClicked) {
|
|
132
|
+
log.success(" ā
Created new notebook");
|
|
133
|
+
await page.waitForTimeout(3000);
|
|
134
|
+
// Look for source limit indicator
|
|
135
|
+
const sourceLimitInfo = await page.evaluate(() => {
|
|
136
|
+
// @ts-expect-error - DOM types
|
|
137
|
+
const spans = document.querySelectorAll('span');
|
|
138
|
+
for (const span of spans) {
|
|
139
|
+
const text = span.textContent?.trim() || "";
|
|
140
|
+
// Look for "X/Y" pattern near "Source"
|
|
141
|
+
if (text.match(/\d+\s*\/\s*\d+/)) {
|
|
142
|
+
return text;
|
|
143
|
+
}
|
|
144
|
+
if (text.toLowerCase().includes("source limit")) {
|
|
145
|
+
return text;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return null;
|
|
149
|
+
});
|
|
150
|
+
if (sourceLimitInfo) {
|
|
151
|
+
log.success(` ā
Source limit indicator: "${sourceLimitInfo}"`);
|
|
152
|
+
}
|
|
153
|
+
await findQuotaElements(page, "Source dialog quota elements");
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
async function main() {
|
|
157
|
+
log.info("š Discovering Quota/License UI Elements...\n");
|
|
158
|
+
const authManager = new AuthManager();
|
|
159
|
+
const contextManager = new SharedContextManager(authManager);
|
|
160
|
+
try {
|
|
161
|
+
const context = await contextManager.getOrCreateContext(true);
|
|
162
|
+
const isAuth = await authManager.validateCookiesExpiry(context);
|
|
163
|
+
if (!isAuth) {
|
|
164
|
+
log.error("ā Not authenticated. Run setup_auth first.");
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
const page = await context.newPage();
|
|
168
|
+
// Navigate to NotebookLM homepage
|
|
169
|
+
log.info("š Navigating to NotebookLM homepage...");
|
|
170
|
+
await page.goto(NOTEBOOKLM_URL, { waitUntil: "domcontentloaded" });
|
|
171
|
+
await page.waitForLoadState("networkidle").catch(() => { });
|
|
172
|
+
await page.waitForTimeout(3000);
|
|
173
|
+
// 1. Check homepage for quota info
|
|
174
|
+
await findQuotaElements(page, "Homepage quota-related elements");
|
|
175
|
+
await extractQuotaFromHomepage(page);
|
|
176
|
+
// 2. Check Settings dialog
|
|
177
|
+
await checkSettingsPage(page);
|
|
178
|
+
// Close any dialog
|
|
179
|
+
await page.keyboard.press("Escape");
|
|
180
|
+
await page.waitForTimeout(1000);
|
|
181
|
+
// 3. Check source dialog in new notebook
|
|
182
|
+
await checkSourceDialog(page);
|
|
183
|
+
// Keep browser open for inspection
|
|
184
|
+
log.info("\nā
Discovery complete. Browser open for 60 seconds...");
|
|
185
|
+
await page.waitForTimeout(60000);
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
log.error(`ā Error: ${error}`);
|
|
189
|
+
}
|
|
190
|
+
finally {
|
|
191
|
+
await contextManager.closeContext();
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
main().catch(console.error);
|
|
195
|
+
//# sourceMappingURL=discover-quota.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discover-quota.js","sourceRoot":"","sources":["../../src/notebook-creation/discover-quota.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discover-source-dialog.d.ts","sourceRoot":"","sources":["../../src/notebook-creation/discover-source-dialog.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discover Source Dialog Options
|
|
3
|
+
*
|
|
4
|
+
* Dumps elements available after clicking "Add source" button.
|
|
5
|
+
* Run: node dist/notebook-creation/discover-source-dialog.js
|
|
6
|
+
*/
|
|
7
|
+
import { AuthManager } from "../auth/auth-manager.js";
|
|
8
|
+
import { SharedContextManager } from "../session/shared-context-manager.js";
|
|
9
|
+
import { log } from "../utils/logger.js";
|
|
10
|
+
const NOTEBOOKLM_URL = "https://notebooklm.google.com/";
|
|
11
|
+
async function dumpElements(page, description) {
|
|
12
|
+
log.info(`\nš ${description}:`);
|
|
13
|
+
const elements = await page.evaluate(() => {
|
|
14
|
+
const results = [];
|
|
15
|
+
// @ts-expect-error - DOM types
|
|
16
|
+
const els = document.querySelectorAll('button, input, textarea, [role="button"], [role="menuitem"], [role="option"], [role="tab"], a, [contenteditable="true"], span');
|
|
17
|
+
for (const el of els) {
|
|
18
|
+
const text = el.textContent?.trim().substring(0, 60) || "";
|
|
19
|
+
const ariaLabel = el.getAttribute("aria-label") || "";
|
|
20
|
+
const role = el.getAttribute("role") || "";
|
|
21
|
+
const visible = el.offsetParent !== null;
|
|
22
|
+
// Skip empty or hidden elements
|
|
23
|
+
if (!visible)
|
|
24
|
+
continue;
|
|
25
|
+
if (!text && !ariaLabel)
|
|
26
|
+
continue;
|
|
27
|
+
if (text.length > 200)
|
|
28
|
+
continue; // Skip large text blocks
|
|
29
|
+
results.push({
|
|
30
|
+
tag: el.tagName,
|
|
31
|
+
text: text.substring(0, 60),
|
|
32
|
+
ariaLabel: ariaLabel,
|
|
33
|
+
role: role,
|
|
34
|
+
type: el.getAttribute("type") || "",
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return results;
|
|
38
|
+
});
|
|
39
|
+
// Log interesting elements
|
|
40
|
+
for (const el of elements) {
|
|
41
|
+
const info = [];
|
|
42
|
+
if (el.text)
|
|
43
|
+
info.push(`"${el.text}"`);
|
|
44
|
+
if (el.ariaLabel)
|
|
45
|
+
info.push(`aria="${el.ariaLabel}"`);
|
|
46
|
+
if (el.role)
|
|
47
|
+
info.push(`role=${el.role}`);
|
|
48
|
+
if (el.type)
|
|
49
|
+
info.push(`type=${el.type}`);
|
|
50
|
+
if (info.length > 0) {
|
|
51
|
+
log.dim(` ${el.tag}: ${info.join(", ")}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async function main() {
|
|
56
|
+
log.info("š Discovering Source Dialog Options...\n");
|
|
57
|
+
const authManager = new AuthManager();
|
|
58
|
+
const contextManager = new SharedContextManager(authManager);
|
|
59
|
+
try {
|
|
60
|
+
const context = await contextManager.getOrCreateContext(true);
|
|
61
|
+
const isAuth = await authManager.validateCookiesExpiry(context);
|
|
62
|
+
if (!isAuth) {
|
|
63
|
+
log.error("ā Not authenticated. Run setup_auth first.");
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const page = await context.newPage();
|
|
67
|
+
// Navigate to NotebookLM
|
|
68
|
+
log.info("š Navigating to NotebookLM...");
|
|
69
|
+
await page.goto(NOTEBOOKLM_URL, { waitUntil: "domcontentloaded" });
|
|
70
|
+
await page.waitForLoadState("networkidle").catch(() => { });
|
|
71
|
+
await page.waitForTimeout(3000);
|
|
72
|
+
// Click create new notebook first
|
|
73
|
+
log.info("š Creating new notebook...");
|
|
74
|
+
const createButton = await page.$('button[aria-label="Create new notebook"]');
|
|
75
|
+
if (createButton) {
|
|
76
|
+
await createButton.click();
|
|
77
|
+
await page.waitForTimeout(3000);
|
|
78
|
+
log.success("ā
Clicked Create new notebook");
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
log.error("ā Could not find Create new notebook button");
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
// Check current URL
|
|
85
|
+
log.info(`š Current URL: ${page.url()}`);
|
|
86
|
+
// Now click Add source
|
|
87
|
+
log.info("\nš Looking for Add source button...");
|
|
88
|
+
await dumpElements(page, "Before Add source click - looking for add buttons");
|
|
89
|
+
const addSourceButton = await page.$('button[aria-label="Opens the upload source dialogue"]');
|
|
90
|
+
if (addSourceButton) {
|
|
91
|
+
await addSourceButton.click();
|
|
92
|
+
await page.waitForTimeout(2000);
|
|
93
|
+
log.success("ā
Clicked Add source button");
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
log.warning("ā ļø Primary selector failed, trying fallback...");
|
|
97
|
+
// Try text-based click
|
|
98
|
+
const clicked = await page.evaluate(() => {
|
|
99
|
+
// @ts-expect-error - DOM types
|
|
100
|
+
const buttons = document.querySelectorAll('button, [role="button"]');
|
|
101
|
+
for (const btn of buttons) {
|
|
102
|
+
const text = btn.textContent?.toLowerCase() || "";
|
|
103
|
+
const aria = btn.getAttribute("aria-label")?.toLowerCase() || "";
|
|
104
|
+
if (text.includes("add source") || aria.includes("upload") || aria.includes("source")) {
|
|
105
|
+
btn.click();
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return false;
|
|
110
|
+
});
|
|
111
|
+
if (clicked) {
|
|
112
|
+
await page.waitForTimeout(2000);
|
|
113
|
+
log.success("ā
Clicked Add source (fallback)");
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
log.error("ā Could not find Add source button");
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Dump source dialog options
|
|
121
|
+
await dumpElements(page, "SOURCE DIALOG OPTIONS (after clicking Add source)");
|
|
122
|
+
// Keep browser open for inspection
|
|
123
|
+
log.info("\nā
Discovery complete. Browser open for 60 seconds...");
|
|
124
|
+
await page.waitForTimeout(60000);
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
log.error(`ā Error: ${error}`);
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
await contextManager.closeContext();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
main().catch(console.error);
|
|
134
|
+
//# sourceMappingURL=discover-source-dialog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discover-source-dialog.js","sourceRoot":"","sources":["../../src/notebook-creation/discover-source-dialog.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discover-sources.d.ts","sourceRoot":"","sources":["../../src/notebook-creation/discover-sources.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discover Source Management UI Elements
|
|
3
|
+
*
|
|
4
|
+
* Finds selectors for listing, adding, and removing sources in NotebookLM.
|
|
5
|
+
* Run: node dist/notebook-creation/discover-sources.js
|
|
6
|
+
*/
|
|
7
|
+
import { AuthManager } from "../auth/auth-manager.js";
|
|
8
|
+
import { SharedContextManager } from "../session/shared-context-manager.js";
|
|
9
|
+
import { log } from "../utils/logger.js";
|
|
10
|
+
// Use a notebook URL with existing sources for discovery
|
|
11
|
+
const TEST_NOTEBOOK_URL = process.env.TEST_NOTEBOOK_URL || "";
|
|
12
|
+
// Future: Interface for discovered selectors (when UI discovery is complete)
|
|
13
|
+
// interface DiscoveredSourceSelectors {
|
|
14
|
+
// sourceListContainer: string | null;
|
|
15
|
+
// sourceItems: string[];
|
|
16
|
+
// sourceTitle: string | null;
|
|
17
|
+
// sourceDeleteButton: string | null;
|
|
18
|
+
// sourceOptionsMenu: string | null;
|
|
19
|
+
// sourceCount: string | null;
|
|
20
|
+
// }
|
|
21
|
+
async function dumpSourceElements(page) {
|
|
22
|
+
return await page.evaluate(() => {
|
|
23
|
+
const results = [];
|
|
24
|
+
// Look for source-related elements
|
|
25
|
+
// @ts-expect-error - DOM types
|
|
26
|
+
const allElements = document.querySelectorAll("*");
|
|
27
|
+
for (const el of allElements) {
|
|
28
|
+
const text = el.textContent?.trim().substring(0, 100) || "";
|
|
29
|
+
const ariaLabel = el.getAttribute("aria-label") || "";
|
|
30
|
+
const classes = el.className || "";
|
|
31
|
+
const tag = el.tagName;
|
|
32
|
+
// Skip if no useful info
|
|
33
|
+
if (!text && !ariaLabel && !classes)
|
|
34
|
+
continue;
|
|
35
|
+
// Look for source-related patterns
|
|
36
|
+
const patterns = [
|
|
37
|
+
/source/i,
|
|
38
|
+
/document/i,
|
|
39
|
+
/upload/i,
|
|
40
|
+
/file/i,
|
|
41
|
+
/delete/i,
|
|
42
|
+
/remove/i,
|
|
43
|
+
/trash/i,
|
|
44
|
+
/more.*options/i,
|
|
45
|
+
/\d+\s*(source|file|document)/i,
|
|
46
|
+
];
|
|
47
|
+
const isRelevant = patterns.some((p) => p.test(text) || p.test(ariaLabel) || p.test(classes));
|
|
48
|
+
if (isRelevant && text.length < 200) {
|
|
49
|
+
// Get data attributes
|
|
50
|
+
const dataAttrs = {};
|
|
51
|
+
for (const attr of Array.from(el.attributes)) {
|
|
52
|
+
if (attr.name.startsWith("data-")) {
|
|
53
|
+
dataAttrs[attr.name] = attr.value;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
results.push({
|
|
57
|
+
selector: el.id ? `#${el.id}` : `.${classes.split(" ")[0]}`,
|
|
58
|
+
text: text.substring(0, 100),
|
|
59
|
+
ariaLabel,
|
|
60
|
+
classes: classes.substring(0, 100),
|
|
61
|
+
tag,
|
|
62
|
+
dataAttrs,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return results;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
async function findSourceListElements(page) {
|
|
70
|
+
log.info("\nš Looking for source list elements...");
|
|
71
|
+
// Look for the sources panel/sidebar
|
|
72
|
+
const sourceElements = await page.evaluate(() => {
|
|
73
|
+
const results = [];
|
|
74
|
+
// Common patterns for source lists
|
|
75
|
+
const listSelectors = [
|
|
76
|
+
'[class*="source-list"]',
|
|
77
|
+
'[class*="sources-panel"]',
|
|
78
|
+
'[class*="sidebar"]',
|
|
79
|
+
'[role="list"]',
|
|
80
|
+
'[role="listbox"]',
|
|
81
|
+
"mat-list",
|
|
82
|
+
"mat-nav-list",
|
|
83
|
+
];
|
|
84
|
+
for (const selector of listSelectors) {
|
|
85
|
+
// @ts-expect-error - DOM types
|
|
86
|
+
const elements = document.querySelectorAll(selector);
|
|
87
|
+
for (const el of elements) {
|
|
88
|
+
const text = el.textContent?.substring(0, 200) || "";
|
|
89
|
+
if (text.toLowerCase().includes("source")) {
|
|
90
|
+
results.push({
|
|
91
|
+
selector,
|
|
92
|
+
childCount: el.children.length,
|
|
93
|
+
text: text.substring(0, 100),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return results;
|
|
99
|
+
});
|
|
100
|
+
for (const item of sourceElements) {
|
|
101
|
+
log.dim(` Found: ${item.selector} (${item.childCount} children)`);
|
|
102
|
+
log.dim(` Text: "${item.text}"`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async function findSourceItems(page) {
|
|
106
|
+
log.info("\nš Looking for individual source items...");
|
|
107
|
+
const items = await page.evaluate(() => {
|
|
108
|
+
const results = [];
|
|
109
|
+
// Look for list items that might be sources
|
|
110
|
+
// @ts-expect-error - DOM types
|
|
111
|
+
const listItems = document.querySelectorAll('mat-list-item, [role="listitem"], .source-item, [class*="source"]');
|
|
112
|
+
for (const item of listItems) {
|
|
113
|
+
const text = item.textContent?.trim().substring(0, 100) || "";
|
|
114
|
+
const classes = item.className || "";
|
|
115
|
+
// Skip if it's clearly not a source item
|
|
116
|
+
if (text.toLowerCase().includes("add") && text.length < 20)
|
|
117
|
+
continue;
|
|
118
|
+
results.push({
|
|
119
|
+
tag: item.tagName,
|
|
120
|
+
classes: classes.substring(0, 80),
|
|
121
|
+
text,
|
|
122
|
+
hasCheckbox: !!item.querySelector('input[type="checkbox"], mat-checkbox'),
|
|
123
|
+
hasDeleteBtn: !!item.querySelector('[aria-label*="delete" i], [aria-label*="remove" i], button[class*="delete"]'),
|
|
124
|
+
hasOptionsBtn: !!item.querySelector('[aria-label*="more" i], [aria-label*="option" i], button[class*="menu"]'),
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
return results;
|
|
128
|
+
});
|
|
129
|
+
for (const item of items) {
|
|
130
|
+
log.dim(` [${item.tag}] "${item.text}"`);
|
|
131
|
+
log.dim(` Classes: ${item.classes}`);
|
|
132
|
+
log.dim(` Has: checkbox=${item.hasCheckbox}, delete=${item.hasDeleteBtn}, options=${item.hasOptionsBtn}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async function findDeleteButtons(page) {
|
|
136
|
+
log.info("\nš Looking for delete/remove buttons...");
|
|
137
|
+
const buttons = await page.evaluate(() => {
|
|
138
|
+
const results = [];
|
|
139
|
+
// @ts-expect-error - DOM types
|
|
140
|
+
const allButtons = document.querySelectorAll("button, [role='button']");
|
|
141
|
+
for (const btn of allButtons) {
|
|
142
|
+
const ariaLabel = btn.getAttribute("aria-label") || "";
|
|
143
|
+
const text = btn.textContent?.trim() || "";
|
|
144
|
+
const classes = btn.className || "";
|
|
145
|
+
const isDelete = /delete|remove|trash|discard/i.test(ariaLabel) ||
|
|
146
|
+
/delete|remove|trash|discard/i.test(text) ||
|
|
147
|
+
/delete|remove|trash/i.test(classes);
|
|
148
|
+
if (isDelete) {
|
|
149
|
+
results.push({
|
|
150
|
+
tag: btn.tagName,
|
|
151
|
+
ariaLabel,
|
|
152
|
+
text: text.substring(0, 50),
|
|
153
|
+
classes: classes.substring(0, 80),
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return results;
|
|
158
|
+
});
|
|
159
|
+
for (const btn of buttons) {
|
|
160
|
+
log.dim(` [${btn.tag}] aria="${btn.ariaLabel}" text="${btn.text}"`);
|
|
161
|
+
log.dim(` Classes: ${btn.classes}`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
async function findSourceCount(page) {
|
|
165
|
+
log.info("\nš Looking for source count indicator...");
|
|
166
|
+
const counts = await page.evaluate(() => {
|
|
167
|
+
const results = [];
|
|
168
|
+
// Look for "X sources" or "X/Y" patterns
|
|
169
|
+
// @ts-expect-error - DOM types
|
|
170
|
+
const allText = document.body.innerText;
|
|
171
|
+
const matches = allText.match(/(\d+)\s*(source|file|document)s?/gi) || [];
|
|
172
|
+
// Also look for specific elements
|
|
173
|
+
// @ts-expect-error - DOM types
|
|
174
|
+
const spans = document.querySelectorAll("span, div, p");
|
|
175
|
+
for (const el of spans) {
|
|
176
|
+
const text = el.textContent?.trim() || "";
|
|
177
|
+
if (/^\d+\s*(source|file|document)s?$/i.test(text) || /^\d+\s*\/\s*\d+$/.test(text)) {
|
|
178
|
+
results.push({
|
|
179
|
+
tag: el.tagName,
|
|
180
|
+
text,
|
|
181
|
+
classes: (el.className || "").substring(0, 80),
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return { textMatches: matches, elements: results };
|
|
186
|
+
});
|
|
187
|
+
log.dim(` Text matches: ${counts.textMatches.join(", ") || "none"}`);
|
|
188
|
+
for (const el of counts.elements) {
|
|
189
|
+
log.dim(` [${el.tag}] "${el.text}" class="${el.classes}"`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
async function main() {
|
|
193
|
+
log.info("š Discovering Source Management UI Elements...\n");
|
|
194
|
+
if (!TEST_NOTEBOOK_URL) {
|
|
195
|
+
log.warning("ā ļø No TEST_NOTEBOOK_URL environment variable set.");
|
|
196
|
+
log.warning(" Set it to a notebook URL with existing sources:");
|
|
197
|
+
log.warning(" TEST_NOTEBOOK_URL=https://notebooklm.google.com/notebook/xxx node dist/notebook-creation/discover-sources.js");
|
|
198
|
+
log.warning("\n Continuing without URL - will navigate to homepage first...\n");
|
|
199
|
+
}
|
|
200
|
+
const authManager = new AuthManager();
|
|
201
|
+
const contextManager = new SharedContextManager(authManager);
|
|
202
|
+
try {
|
|
203
|
+
const context = await contextManager.getOrCreateContext(true);
|
|
204
|
+
const isAuth = await authManager.validateCookiesExpiry(context);
|
|
205
|
+
if (!isAuth) {
|
|
206
|
+
log.error("ā Not authenticated. Run setup_auth first.");
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
const page = await context.newPage();
|
|
210
|
+
// Navigate to notebook or homepage
|
|
211
|
+
const url = TEST_NOTEBOOK_URL || "https://notebooklm.google.com/";
|
|
212
|
+
log.info(`š Navigating to: ${url}`);
|
|
213
|
+
await page.goto(url, { waitUntil: "domcontentloaded" });
|
|
214
|
+
await page.waitForLoadState("networkidle").catch(() => { });
|
|
215
|
+
await page.waitForTimeout(3000);
|
|
216
|
+
// If on homepage, try to click on first notebook
|
|
217
|
+
if (!TEST_NOTEBOOK_URL) {
|
|
218
|
+
log.info("š Looking for a notebook to open...");
|
|
219
|
+
const clicked = await page.evaluate(() => {
|
|
220
|
+
// @ts-expect-error - DOM types
|
|
221
|
+
const rows = document.querySelectorAll("tr");
|
|
222
|
+
for (const row of rows) {
|
|
223
|
+
if (row.textContent?.includes("Source")) {
|
|
224
|
+
row.click();
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return false;
|
|
229
|
+
});
|
|
230
|
+
if (clicked) {
|
|
231
|
+
log.success(" ā
Clicked on a notebook");
|
|
232
|
+
await page.waitForTimeout(3000);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
log.warning(" ā ļø No notebooks found to click");
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
// Run discovery
|
|
239
|
+
log.info("\n=== Source UI Discovery ===\n");
|
|
240
|
+
// 1. Dump all source-related elements
|
|
241
|
+
log.info("š All source-related elements:");
|
|
242
|
+
const allElements = await dumpSourceElements(page);
|
|
243
|
+
for (const el of allElements.slice(0, 20)) {
|
|
244
|
+
log.dim(` [${el.tag}] "${el.text}" aria="${el.ariaLabel}"`);
|
|
245
|
+
}
|
|
246
|
+
if (allElements.length > 20) {
|
|
247
|
+
log.dim(` ... and ${allElements.length - 20} more`);
|
|
248
|
+
}
|
|
249
|
+
// 2. Find source list container
|
|
250
|
+
await findSourceListElements(page);
|
|
251
|
+
// 3. Find individual source items
|
|
252
|
+
await findSourceItems(page);
|
|
253
|
+
// 4. Find delete buttons
|
|
254
|
+
await findDeleteButtons(page);
|
|
255
|
+
// 5. Find source count
|
|
256
|
+
await findSourceCount(page);
|
|
257
|
+
// Take a screenshot for reference
|
|
258
|
+
const screenshotPath = "/tmp/notebooklm-sources-discovery.png";
|
|
259
|
+
await page.screenshot({ path: screenshotPath, fullPage: true });
|
|
260
|
+
log.info(`\nšø Screenshot saved: ${screenshotPath}`);
|
|
261
|
+
// Keep browser open for inspection
|
|
262
|
+
log.info("\nā
Discovery complete. Browser open for 60 seconds...");
|
|
263
|
+
await page.waitForTimeout(60000);
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
log.error(`ā Error: ${error}`);
|
|
267
|
+
}
|
|
268
|
+
finally {
|
|
269
|
+
await contextManager.closeContext();
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
main().catch(console.error);
|
|
273
|
+
//# sourceMappingURL=discover-sources.js.map
|