Markdown Converter
Agent skill for markdown-converter
Automate NotebookLM notebook creation from YouTube videos. Given a YouTube video URL, extract information about people featured in the video, research them online, create a new NotebookLM notebook with the video and research as sources, and generate an audio overview. Uses screenshot-first automation to reliably target UI elements.
Sign in to like and favorite skills
Automate NotebookLM notebook creation from YouTube videos with automatic research and Audio Overview generation.
Screenshot before every action ā verify UI state, identify correct elements, confirm success.
šø Screenshot ā š Analyze ā šÆ Target ā ā Verify ā š±ļø Execute ā šø Screenshot ā ā Confirm
# 1. Get video info Control Chrome:open_url("https://www.youtube.com/watch?v=VIDEO_ID") Control Chrome:get_page_content() # 2. Research people mentioned web_search("[Person Name] background career") # 3. Create research document (keep under 500k chars)
# 1. Navigate Control Chrome:open_url("https://notebooklm.google.com/") # 2. Create notebook # Click "Create new" button # 3. Add YouTube source # Click "Websites" ā Enter URL ā Click "Insert" # 4. Add research document # Click "Add sources" ā "Copied text" ā Paste content ā Click "Insert" # 5. Generate audio # Click "Audio Overview" in Studio panel
NotebookLM has multiple textareas. Generic selectors grab the wrong one!
SIDEBAR (wrong) CENTER MODAL (correct) āāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāā ā Search box ā ā URL/Text input ā ā query-input ā ā "Paste any links"| āāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāā
| Element | Selector |
|---|---|
| URL input | |
| Text input | |
| Sidebar (AVOID) | |
// Simple .value = doesn't work! Use this: var setter = Object.getOwnPropertyDescriptor( HTMLTextAreaElement.prototype, 'value' ).set; setter.call(textarea, 'content'); textarea.dispatchEvent(new Event('input', {bubbles: true})); textarea.dispatchEvent(new Event('change', {bubbles: true}));
var btn = document.querySelector('button'); if (btn && !btn.disabled && !btn.className.includes('disabled')) { btn.click(); }
var urlTextarea = document.querySelector('textarea[placeholder="Paste any links"]'); if (urlTextarea) { var setter = Object.getOwnPropertyDescriptor( HTMLTextAreaElement.prototype, 'value' ).set; setter.call(urlTextarea, 'https://www.youtube.com/watch?v=VIDEO_ID'); urlTextarea.dispatchEvent(new Event('input', {bubbles: true})); urlTextarea.dispatchEvent(new Event('change', {bubbles: true})); }
var pasteTextarea = document.querySelector('textarea[placeholder="Paste text here"]'); if (pasteTextarea) { var setter = Object.getOwnPropertyDescriptor( HTMLTextAreaElement.prototype, 'value' ).set; setter.call(pasteTextarea, RESEARCH_CONTENT); pasteTextarea.dispatchEvent(new Event('input', {bubbles: true})); pasteTextarea.dispatchEvent(new Event('change', {bubbles: true})); }
var buttons = Array.from(document.querySelectorAll('button')); var btn = buttons.find(b => b.textContent.includes('Insert')); if (btn && !btn.disabled) { btn.click(); }
// Check what textareas exist var textareas = Array.from(document.querySelectorAll('textarea')); textareas.map(t => ({ placeholder: t.placeholder, value: t.value.substring(0, 50) }));
| Step | Verify Before | Verify After |
|---|---|---|
| Navigate | - | Home page loaded |
| Create notebook | Create button visible | Notebook opened |
| Add URL | Correct textarea identified | URL in center, not sidebar |
| Click Insert | Button ENABLED | Source added |
| Add text | Correct textarea identified | Text in center, not sidebar |
| Click Insert | Button ENABLED | 2 sources shown |
| Audio Overview | Studio panel visible | Generation started |
| ā Don't | ā Do |
|---|---|
| |
| Click without checking state | Verify button enabled first |
| Assume action succeeded | Screenshot to confirm |
| Rush through steps | Wait for async operations |
| Action | Wait |
|---|---|
| Page navigation | 3s |
| Dialog open | 2s |
| YouTube source processing | 8-10s |
| Text source processing | 5s |
| Audio generation | 5-10 minutes |
Wrong input targeted:
document.querySelectorAll('.query-input').forEach(el => el.value = '')Button disabled:
Modal didn't open: