mcp-scraper 0.1.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.
Files changed (38) hide show
  1. package/README.md +56 -0
  2. package/dist/bin/api-server.cjs +9256 -0
  3. package/dist/bin/api-server.cjs.map +1 -0
  4. package/dist/bin/api-server.d.cts +1 -0
  5. package/dist/bin/api-server.d.ts +1 -0
  6. package/dist/bin/api-server.js +38 -0
  7. package/dist/bin/api-server.js.map +1 -0
  8. package/dist/bin/mcp-stdio-server.cjs +840 -0
  9. package/dist/bin/mcp-stdio-server.cjs.map +1 -0
  10. package/dist/bin/mcp-stdio-server.d.cts +1 -0
  11. package/dist/bin/mcp-stdio-server.d.ts +1 -0
  12. package/dist/bin/mcp-stdio-server.js +41 -0
  13. package/dist/bin/mcp-stdio-server.js.map +1 -0
  14. package/dist/bin/paa-harvest.cjs +1438 -0
  15. package/dist/bin/paa-harvest.cjs.map +1 -0
  16. package/dist/bin/paa-harvest.d.cts +1 -0
  17. package/dist/bin/paa-harvest.d.ts +1 -0
  18. package/dist/bin/paa-harvest.js +37 -0
  19. package/dist/bin/paa-harvest.js.map +1 -0
  20. package/dist/chunk-4API3ZCT.js +1387 -0
  21. package/dist/chunk-4API3ZCT.js.map +1 -0
  22. package/dist/chunk-LXZDJJXR.js +476 -0
  23. package/dist/chunk-LXZDJJXR.js.map +1 -0
  24. package/dist/chunk-ZBP4RHNW.js +805 -0
  25. package/dist/chunk-ZBP4RHNW.js.map +1 -0
  26. package/dist/db-IOYMX64U.js +87 -0
  27. package/dist/db-IOYMX64U.js.map +1 -0
  28. package/dist/index.cjs +1689 -0
  29. package/dist/index.cjs.map +1 -0
  30. package/dist/index.d.cts +210 -0
  31. package/dist/index.d.ts +210 -0
  32. package/dist/index.js +275 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/server-63DR2HE5.js +6062 -0
  35. package/dist/server-63DR2HE5.js.map +1 -0
  36. package/dist/worker-3ECJHPRE.js +88 -0
  37. package/dist/worker-3ECJHPRE.js.map +1 -0
  38. package/package.json +76 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/schemas.ts","../src/driver/BrowserDriver.ts","../src/selectors.ts","../src/errors.ts","../src/locations.ts","../src/uule.ts","../src/lib/paa-answer-cleanup.ts","../src/extractor/PAAExtractor.ts","../src/output/OutputSerializer.ts","../src/output/ProgressReporter.ts","../src/harvest.ts","../src/video/VideoGenerator.ts","../src/video/promptBuilder.ts","../src/video/AudioGenerator.ts","../src/video/VideoMixer.ts"],"sourcesContent":["export { harvest } from './harvest.js'\nexport type { HarvestOptions, HarvestResult, PAANode, FlatRow, HarvestStats, AIOverviewResult, AIModeResult, AICitation, GoogleSurface, WhatPeopleSayingCard } from './types.js'\nexport { VideoGenerator } from './video/VideoGenerator.js'\nexport type { ClipPairOptions, ClipPairResult } from './video/VideoGenerator.js'\nexport { buildClipPrompts } from './video/promptBuilder.js'\n","import { z } from 'zod'\n\nexport const HarvestOptionsSchema = z.object({\n query: z.string().min(1),\n location: z.string().optional(),\n gl: z.string().length(2).default('us'),\n hl: z.string().length(2).default('en'),\n depth: z.number().int().min(1).max(30).default(3),\n maxQuestions: z.number().int().min(1).max(1000).default(100),\n headless: z.boolean().default(false),\n profileDir: z.string().optional(),\n proxy: z.string().url().optional(),\n kernelApiKey: z.string().optional(),\n kernelProxyId: z.string().optional(),\n outputDir: z.string().default('./paa-output'),\n format: z.enum(['json', 'csv', 'both']).default('both'),\n serpOnly: z.boolean().default(false),\n pages: z.number().int().min(1).max(2).default(1),\n})\n\nexport const MapsPlaceOptionsSchema = z.object({\n businessName: z.string().min(1),\n location: z.string().min(1),\n gl: z.string().length(2).default('us'),\n hl: z.string().length(2).default('en'),\n includeReviews: z.boolean().default(false),\n maxReviews: z.number().int().min(1).max(500).default(50),\n kernelApiKey: z.string().optional(),\n kernelProxyId: z.string().optional(),\n headless: z.boolean().default(true),\n})\n\nexport const RawPAAItemSchema = z.object({\n question: z.string().min(1),\n answer: z.string().optional(),\n sourceTitle: z.string().optional(),\n sourceSite: z.string().optional(),\n sourceCite: z.string().optional(),\n})\n","import { chromium } from 'playwright-extra'\nimport StealthPlugin from 'puppeteer-extra-plugin-stealth'\nimport { chromium as playwrightChromium } from 'playwright'\nimport type { Browser, BrowserContext, Page } from 'playwright'\nimport Kernel from '@onkernel/sdk'\nimport { PAASelectors } from '../selectors.js'\nimport { CaptchaError, ExtractionError, RECAPTCHA_INSTRUCTIONS } from '../errors.js'\nimport type { DriverConfig, UuleString } from '../types.js'\nimport type { IBrowserDriver } from './IBrowserDriver.js'\n\nchromium.use(StealthPlugin())\n\nconst DESKTOP_USER_AGENT =\n 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36'\n\nexport function buildYouTubeChannelVideosUrl(channelInput: string): string {\n const raw = channelInput.trim()\n if (!raw) throw new Error('channelHandle is required')\n\n const urlLike = /^https?:\\/\\//i.test(raw) || /^(www\\.|m\\.)?youtube\\.com\\//i.test(raw)\n if (urlLike) {\n const parsed = new URL(/^https?:\\/\\//i.test(raw) ? raw : `https://${raw}`)\n const host = parsed.hostname.replace(/^www\\./, '').replace(/^m\\./, '').toLowerCase()\n if (host !== 'youtube.com') throw new Error('channel URL must be on youtube.com')\n\n const segments = parsed.pathname.split('/').filter(Boolean)\n const first = segments[0] ?? ''\n const second = segments[1] ?? ''\n\n if (first.startsWith('@')) return `https://www.youtube.com/${first}/videos`\n if (first === 'channel' && second) return `https://www.youtube.com/channel/${second}/videos`\n if ((first === 'c' || first === 'user') && second) return `https://www.youtube.com/${first}/${second}/videos`\n\n throw new Error('channel URL must be a YouTube handle, /channel/UC..., /c/..., or /user/... URL')\n }\n\n const stripped = raw.replace(/^\\/+/, '').replace(/\\/+$/, '')\n const withoutVideos = stripped.replace(/\\/videos$/i, '')\n if (/^UC[\\w-]{20,}$/.test(withoutVideos)) {\n return `https://www.youtube.com/channel/${withoutVideos}/videos`\n }\n\n const handle = withoutVideos.startsWith('@') ? withoutVideos : `@${withoutVideos}`\n if (!/^@[\\w.-]+$/.test(handle)) {\n throw new Error('channelHandle must be an @handle, UC channel ID, or YouTube channel URL')\n }\n return `https://www.youtube.com/${handle}/videos`\n}\n\nexport class BrowserDriver implements IBrowserDriver {\n private browser: Browser | null = null\n private context: BrowserContext | null = null\n private page: Page | null = null\n private kernelClient: Kernel | null = null\n private kernelSessionId: string | null = null\n\n async launch(config: DriverConfig): Promise<void> {\n if (config.kernelApiKey) {\n this.kernelClient = new Kernel({ apiKey: config.kernelApiKey })\n const kernelBrowser = await this.kernelClient.browsers.create({\n stealth: true,\n timeout_seconds: 600,\n ...(config.kernelProxyId ? { proxy_id: config.kernelProxyId } : {}),\n })\n this.kernelSessionId = kernelBrowser.session_id\n this.browser = await playwrightChromium.connectOverCDP(kernelBrowser.cdp_ws_url)\n this.context = this.browser.contexts()[0] ?? await this.browser.newContext()\n await this.installEsbuildHelperShims(this.context)\n this.page = this.context.pages()[0] ?? await this.context.newPage()\n return\n }\n\n const launchOpts = {\n headless: config.headless,\n proxy: config.proxy ? { server: config.proxy } : undefined,\n }\n const ctxOpts = {\n viewport: config.viewport,\n locale: config.locale,\n userAgent: DESKTOP_USER_AGENT,\n }\n if (config.profileDir) {\n this.context = await chromium.launchPersistentContext(config.profileDir, {\n ...launchOpts,\n ...ctxOpts,\n })\n await this.installEsbuildHelperShims(this.context)\n this.page = await this.context.newPage()\n } else {\n this.browser = await chromium.launch(launchOpts)\n this.context = await this.browser.newContext(ctxOpts)\n await this.installEsbuildHelperShims(this.context)\n this.page = await this.context.newPage()\n }\n }\n\n private async installEsbuildHelperShims(context: BrowserContext): Promise<void> {\n await context.addInitScript(() => {\n const g = globalThis as Record<string, unknown>\n if (typeof g.__name !== 'function') g.__name = (fn: unknown) => fn\n if (typeof g.__publicField !== 'function') g.__publicField = (obj: Record<string, unknown>, key: string, value: unknown) => { obj[key] = value; return value }\n })\n }\n\n async navigateToSERP(\n query: string,\n uule: UuleString | null,\n gl: string,\n hl: string,\n ): Promise<{ hasPaa: boolean }> {\n const params = new URLSearchParams({ q: query, gl, hl })\n if (uule) params.set('uule', uule)\n const url = 'https://www.google.com/search?' + params.toString()\n\n try {\n await this.page!.goto(url, { waitUntil: 'domcontentloaded', timeout: 45_000 })\n } catch (err) {\n const diag = await this.captureDiagnostics(url)\n throw new ExtractionError(`page.goto failed: ${(err as Error).message} | ${diag}`)\n }\n\n const captchaCount = await this.page!.locator(PAASelectors.captchaMarker).count()\n if (captchaCount > 0) {\n if (this.kernelClient) {\n try {\n await this.page!.waitForSelector(PAASelectors.container, { timeout: 45_000 })\n return { hasPaa: true }\n } catch {\n throw new CaptchaError(this.captchaMessage())\n }\n }\n throw new CaptchaError(this.captchaMessage())\n }\n\n const fastFound = await this.page!.waitForSelector(PAASelectors.item, { timeout: 4_000 }).catch(() => null)\n if (fastFound) return { hasPaa: true }\n\n const captchaAfter = await this.page!.locator(PAASelectors.captchaMarker).count()\n if (captchaAfter > 0) throw new CaptchaError(this.captchaMessage())\n\n for (let i = 1; i <= 6; i++) {\n await this.page!.evaluate((f: number) => { window.scrollTo(0, document.body.scrollHeight * f) }, i / 6)\n await this.page!.waitForTimeout(600)\n const count = await this.page!.locator(PAASelectors.item).count()\n if (count > 0) return { hasPaa: true }\n }\n\n return { hasPaa: false }\n }\n\n private async captureDiagnostics(intendedUrl: string): Promise<string> {\n try {\n const finalUrl = this.page!.url()\n const title = await this.page!.title().catch(() => '')\n const bodySnippet = await this.page!.evaluate(() => {\n const t = (document.body?.innerText ?? '').replace(/\\s+/g, ' ').trim()\n return t.slice(0, 400)\n }).catch(() => '')\n const consent = /consent\\.google\\./.test(finalUrl) || /before you continue/i.test(bodySnippet)\n const recaptcha = /recaptcha|unusual traffic|are you a robot/i.test(bodySnippet)\n const flags = [\n consent ? 'CONSENT_WALL' : '',\n recaptcha ? 'BOT_CHALLENGE' : '',\n finalUrl !== intendedUrl ? 'REDIRECTED' : '',\n ].filter(Boolean).join(',')\n return `intended=${intendedUrl} | final=${finalUrl} | title=\"${title}\" | flags=[${flags}] | body=\"${bodySnippet}\"`\n } catch (e) {\n return `diagnostics-failed: ${(e as Error).message}`\n }\n }\n\n private captchaMessage(): string {\n return this.kernelClient\n ? 'Google returned a CAPTCHA on this Kernel.sh session — retrying with a fresh session.'\n : RECAPTCHA_INSTRUCTIONS\n }\n\n async navigateTo(url: string): Promise<void> {\n try {\n await this.page!.goto(url, { waitUntil: 'domcontentloaded', timeout: 45_000 })\n } catch (err) {\n const diag = await this.captureDiagnostics(url)\n throw new ExtractionError(`page.goto failed: ${(err as Error).message} | ${diag}`)\n }\n }\n\n async navigateToChannel(channelHandle: string): Promise<void> {\n const url = buildYouTubeChannelVideosUrl(channelHandle)\n try {\n await this.page!.goto(url, { waitUntil: 'networkidle', timeout: 30_000 })\n } catch (err) {\n const diag = await this.captureDiagnostics(url)\n throw new ExtractionError(`navigateToChannel failed: ${(err as Error).message} | ${diag}`)\n }\n }\n\n async evaluate<T>(fn: (...args: unknown[]) => T | Promise<T>, arg?: unknown): Promise<T> {\n return (this.page! as { evaluate(fn: unknown, arg?: unknown): Promise<T> }).evaluate(fn, arg)\n }\n\n getPage(): Page {\n return this.page!\n }\n\n async close(): Promise<void> {\n if (this.browser) {\n const b = this.browser\n const sessionId = this.kernelSessionId\n const client = this.kernelClient\n this.browser = null\n this.context = null\n this.page = null\n this.kernelSessionId = null\n this.kernelClient = null\n try {\n await b.close()\n } finally {\n if (client && sessionId) {\n await client.browsers.deleteByID(sessionId).catch((err: unknown) =>\n console.warn('Kernel session cleanup failed:', err)\n )\n }\n }\n } else if (this.context) {\n const ctx = this.context\n this.context = null\n this.page = null\n await ctx.close()\n }\n }\n}\n","export const PAASelectors = {\n container: '.eJH8qe.adDDi',\n dataInitq: '[data-initq]',\n item: '.related-question-pair',\n itemDataQ: 'data-q',\n itemDataInitQ: 'data-initq',\n itemQuestionEl: '.JlqpRe',\n answerContainer: '.bCOlv',\n sourceTitle: 'h3',\n sourceSite: '.VuuXrf',\n sourceCite: 'cite',\n clickTarget: '.JlqpRe',\n expandedClass: 'aoRk1c',\n captchaMarker: '#captcha-form, #recaptcha, form[action*=\"/sorry/\"], .g-recaptcha, [data-sitekey]',\n} as const\n\nexport const VideoSelectors = {\n container: 'div[jscontroller=\"HWk0Gf\"]',\n sectionHeading: '.mgAbYb[role=\"heading\"]',\n item: 'a.rIRoqf',\n} as const\n\nexport const ShortVideoSelectors = {\n udm: '39',\n item: 'a.rIRoqf',\n durationPattern: /^\\d+:\\d+$/,\n platforms: ['YouTube', 'TikTok', 'Instagram', 'Facebook', 'X'],\n} as const\n\nexport const ForumSelectors = {\n section: '.ULSxyf',\n item: 'a.KYg7td.INpicf',\n title: '.hyYc0c',\n source: '.K4ETW',\n} as const\n\nexport const WhatPeopleSayingSelectors = {\n sectionTag: 'g-section-with-header',\n sectionHeadingText: 'What people are saying',\n card: '.dRzkFf[role=\"listitem\"]',\n cardLink: 'a.WlydOe[jsname=\"YKoRaf\"]',\n titleH1: 'h1.WQWxe',\n titleDiv: '.eAaXgc',\n popularCommentLabel: '.qgdis',\n source: '.sTl1Td',\n platformBadge: '.appd0, .KrMNbf',\n ytChannel: '.sjVJQd',\n ytDate: '.PLq9Je',\n authorNote: '.nDgy9d',\n} as const\n\nexport const AIOverviewSelectors = {\n root: '[data-hveid=\"CBMQAA\"]',\n wrapper: '.Fgyi2e',\n citations: '.Fgyi2e [data-hveid] a[jsname=\"pxBnId\"]',\n} as const\n\nexport const AIModeSelectors = {\n root: '[data-hveid=\"CAUQAA\"]',\n wrapper: '.Fgyi2e',\n citations: '.Fgyi2e [data-hveid] a[jsname=\"pxBnId\"]',\n} as const\n\nexport const OrganicSelectors = {\n result: '.wHYlTd.tF2Cxc',\n title: 'h3.LC20lb',\n siteName: '.VuuXrf',\n cite: 'cite.tjvcx',\n snippet: '.VwiC3b',\n redditCite: 'cite.qLRx3b',\n ratingWrap: '.Y0A0hc',\n ratingValue: '.yi40Hd',\n reviewCount: '.RDApEe',\n} as const\n\nexport const LocalPackSelectors = {\n headingText: 'Businesses',\n card: '.w7Dbne',\n name: '.OSrXXb',\n ratingValue: '.yi40Hd',\n reviewCount: '.RDApEe',\n} as const\n\nexport const SELECTORS_VERSION = '2026-05-07'\n","export const RECAPTCHA_INSTRUCTIONS = 'Google returned a CAPTCHA. Run with --headless=false to re-warm the browser profile, then retry.'\n\nexport class CaptchaError extends Error {\n readonly name = 'CaptchaError'\n constructor(public readonly instructions: string) {\n super(`CAPTCHA detected. ${instructions}`)\n }\n}\n\nexport class ExtractionError extends Error {\n readonly name = 'ExtractionError'\n constructor(message: string, public readonly cause?: unknown) {\n super(message)\n }\n}\n","import type { CanonicalLocationName } from './types.js'\n\nexport const LOCATIONS: Record<string, CanonicalLocationName> = {\n 'austin': 'Austin,Texas,United States',\n 'new york': 'New York,New York,United States',\n 'new york city': 'New York,New York,United States',\n 'nyc': 'New York,New York,United States',\n 'los angeles': 'Los Angeles,California,United States',\n 'la': 'Los Angeles,California,United States',\n 'chicago': 'Chicago,Illinois,United States',\n 'houston': 'Houston,Texas,United States',\n 'phoenix': 'Phoenix,Arizona,United States',\n 'philadelphia': 'Philadelphia,Pennsylvania,United States',\n 'philly': 'Philadelphia,Pennsylvania,United States',\n 'san antonio': 'San Antonio,Texas,United States',\n 'dallas': 'Dallas,Texas,United States',\n 'miami': 'Miami,Florida,United States',\n 'seattle': 'Seattle,Washington,United States',\n 'denver': 'Denver,Colorado,United States',\n 'loveland': 'Loveland,Colorado,United States',\n 'loveland co': 'Loveland,Colorado,United States',\n 'fort collins': 'Fort Collins,Colorado,United States',\n 'boulder': 'Boulder,Colorado,United States',\n 'colorado springs': 'Colorado Springs,Colorado,United States',\n 'boston': 'Boston,Massachusetts,United States',\n 'atlanta': 'Atlanta,Georgia,United States',\n 'san francisco': 'San Francisco,California,United States',\n 'sf': 'San Francisco,California,United States',\n 'portland': 'Portland,Oregon,United States',\n 'las vegas': 'Las Vegas,Nevada,United States',\n 'minneapolis': 'Minneapolis,Minnesota,United States',\n 'detroit': 'Detroit,Michigan,United States',\n 'nashville': 'Nashville,Tennessee,United States',\n 'charlotte': 'Charlotte,North Carolina,United States',\n 'orlando': 'Orlando,Florida,United States',\n 'san diego': 'San Diego,California,United States',\n 'baltimore': 'Baltimore,Maryland,United States',\n 'sacramento': 'Sacramento,California,United States',\n 'columbus': 'Columbus,Ohio,United States',\n 'indianapolis': 'Indianapolis,Indiana,United States',\n 'san jose': 'San Jose,California,United States',\n 'fort worth': 'Fort Worth,Texas,United States',\n 'jacksonville': 'Jacksonville,Florida,United States',\n 'memphis': 'Memphis,Tennessee,United States',\n 'louisville': 'Louisville,Kentucky,United States',\n 'raleigh': 'Raleigh,North Carolina,United States',\n 'richmond': 'Richmond,Virginia,United States',\n 'salt lake city': 'Salt Lake City,Utah,United States',\n 'toronto': 'Toronto,Ontario,Canada',\n 'vancouver': 'Vancouver,British Columbia,Canada',\n 'montreal': 'Montreal,Quebec,Canada',\n 'calgary': 'Calgary,Alberta,Canada',\n 'ottawa': 'Ottawa,Ontario,Canada',\n 'london': 'London,England,United Kingdom',\n 'manchester': 'Manchester,England,United Kingdom',\n 'birmingham': 'Birmingham,England,United Kingdom',\n 'edinburgh': 'Edinburgh,Scotland,United Kingdom',\n 'glasgow': 'Glasgow,Scotland,United Kingdom',\n 'leeds': 'Leeds,England,United Kingdom',\n 'sydney': 'Sydney,New South Wales,Australia',\n 'melbourne': 'Melbourne,Victoria,Australia',\n 'brisbane': 'Brisbane,Queensland,Australia',\n 'perth': 'Perth,Western Australia,Australia',\n 'adelaide': 'Adelaide,South Australia,Australia',\n 'dublin': 'Dublin,Leinster,Ireland',\n}\n","import type { CanonicalLocationName, UuleString } from './types.js'\nimport { LOCATIONS } from './locations.js'\n\nexport function encodeUule(name: CanonicalLocationName): UuleString {\n const encoded = Buffer.from(String.fromCharCode(name.length) + name).toString('base64')\n return `w+CAIQICI${encoded}`\n}\n\nexport function normalizeLocation(input: string): CanonicalLocationName {\n const key = input.toLowerCase().trim()\n return (LOCATIONS[key] ?? input) as CanonicalLocationName\n}\n","const MAX_ANSWER_LENGTH = 1200\n\nconst BOILERPLATE_PATTERNS: RegExp[] = [\n /An AI Overview is not available for this search/gi,\n /Can't generate an AI overview right now\\.?\\s*Try again later\\.?/gi,\n /\\bAI Overview\\b/gi,\n /\\bView all\\b/gi,\n]\n\nconst CUT_MARKERS: RegExp[] = [\n /\\bRelated Links\\b/i,\n /\\bAsk anything in\\s*AI Mode\\b/i,\n /\\bAI can make mistakes\\b/i,\n /\\bThis is for informational purposes only\\b/i,\n /\\bShow more\\b/i,\n /\\b\\d+\\s+sites\\b/i,\n /\\b\\d{1,2}\\s*[msh]\\s*[A-Z][A-Za-z]/,\n /\\b(?:YouTube|Reddit|Facebook|Instagram|TikTok)·/,\n]\n\nfunction normalizeWhitespace(text: string): string {\n return text\n .replace(/\\u00a0/g, ' ')\n .replace(/([.!?])([A-Z])/g, '$1 $2')\n .replace(/([:;])([A-Z])/g, '$1 $2')\n .replace(/([a-z])([A-Z][a-z])/g, '$1 $2')\n .replace(/(\\d)([A-Z][a-z])/g, '$1 $2')\n .replace(/([a-z])(\\d)/g, '$1 $2')\n .replace(/\\s+/g, ' ')\n .trim()\n}\n\nfunction cutAtFirstMarker(text: string): string {\n let cutAt = -1\n for (const marker of CUT_MARKERS) {\n const match = marker.exec(text)\n marker.lastIndex = 0\n if (match && (cutAt === -1 || match.index < cutAt)) cutAt = match.index\n }\n return cutAt === -1 ? text : text.slice(0, cutAt)\n}\n\nfunction cutAtSourceTitle(text: string, sourceTitle?: string): string {\n const title = sourceTitle?.trim()\n if (!title || title.length < 8) return text\n const idx = text.toLowerCase().indexOf(title.toLowerCase())\n return idx > 40 ? text.slice(0, idx) : text\n}\n\nfunction findAttributionCut(beforeUrl: string): number {\n const dateMatch = beforeUrl.match(/[•·]\\s*(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*\\.?\\s+\\d{1,2},\\s+\\d{4}/i)\n if (dateMatch?.index && dateMatch.index > 40) return dateMatch.index\n\n const start = Math.max(0, beforeUrl.length - 260)\n const tail = beforeUrl.slice(start)\n const sentenceBreaks = [...tail.matchAll(/[.!?]\\s*(?=[A-Z][A-Za-z0-9\"'$])/g)]\n for (const match of sentenceBreaks) {\n const remainder = tail.slice(match.index + 1).trim()\n const lead = remainder.slice(0, 160)\n const looksLikeTitle = /^(?:Best|Top|What|How|Why|When|Where|Which|Can|Should|Is|Are|Do|Does)\\b/i.test(remainder)\n if (\n remainder.length > 20 &&\n looksLikeTitle &&\n /(?:\\s[-|]\\s|Heating|Cooling|Company|Services|Blog|Guide|Review)/i.test(lead)\n ) {\n return start + match.index + 1\n }\n }\n const last = sentenceBreaks.at(-1)\n if (last?.index !== undefined) return start + last.index + 1\n\n return beforeUrl.length\n}\n\nfunction cutAtUrlAttribution(text: string): string {\n const urlMatch = text.match(/https?:\\/\\/\\S+/i)\n if (!urlMatch?.index) return text\n\n const beforeUrl = text.slice(0, urlMatch.index)\n return beforeUrl.slice(0, findAttributionCut(beforeUrl))\n}\n\nfunction trimToSentenceLimit(text: string): string {\n if (text.length <= MAX_ANSWER_LENGTH) return text\n const slice = text.slice(0, MAX_ANSWER_LENGTH)\n const lastSentence = Math.max(slice.lastIndexOf('.'), slice.lastIndexOf('!'), slice.lastIndexOf('?'))\n return (lastSentence > 240 ? slice.slice(0, lastSentence + 1) : slice).trim()\n}\n\nexport function cleanPAAAnswerText(\n answer: string | null | undefined,\n question?: string,\n sourceTitle?: string,\n): string | undefined {\n if (!answer) return undefined\n\n let text = normalizeWhitespace(answer)\n const normalizedQuestion = question ? normalizeWhitespace(question) : ''\n if (normalizedQuestion && text.toLowerCase().startsWith(normalizedQuestion.toLowerCase())) {\n text = text.slice(normalizedQuestion.length).trim()\n }\n\n if (/^An error has occurred\\.?\\s*Please try again later\\.?/i.test(text)) {\n return undefined\n }\n\n for (const pattern of BOILERPLATE_PATTERNS) {\n text = text.replace(pattern, ' ')\n }\n text = text\n .replace(/\\b[A-Z][A-Za-z&'\\u2019 -]{2,60}\\+\\d+\\b/g, ' ')\n .replace(/\\b(?:[a-z0-9-]+\\.)+[a-z]{2,}\\+\\d+\\b/gi, ' ')\n\n text = normalizeWhitespace(text)\n text = cutAtFirstMarker(text)\n text = cutAtSourceTitle(text, sourceTitle)\n text = cutAtUrlAttribution(text)\n text = normalizeWhitespace(text)\n text = text.replace(/\\s+(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*\\.?\\s+\\d{1,2},\\s+\\d{4}$/i, '').trim()\n text = trimToSentenceLimit(text)\n\n if (!text) return undefined\n if (/^An error has occurred\\.?\\s*Please try again later\\.?$/i.test(text)) return undefined\n\n return text\n}\n","import type { Page } from 'playwright'\nimport type { IBrowserDriver } from '../driver/IBrowserDriver.js'\nimport type { IProgressReporter } from '../output/IProgressReporter.js'\nimport { PAASelectors, VideoSelectors, ForumSelectors, ShortVideoSelectors, AIOverviewSelectors, AIModeSelectors, WhatPeopleSayingSelectors, OrganicSelectors, LocalPackSelectors } from '../selectors.js'\nimport { encodeUule, normalizeLocation } from '../uule.js'\nimport { RawPAAItemSchema } from '../schemas.js'\nimport { cleanPAAAnswerText } from '../lib/paa-answer-cleanup.js'\nimport type {\n HarvestOptions, HarvestResult, HarvestStats,\n RawPAAItem, PAANode, FlatRow, NormalizedQuestionKey, DriverConfig,\n VideoResult, ForumResult, AIOverviewResult, AIModeResult, GoogleSurface,\n WhatPeopleSayingCard, EntityIds, EntityRecord,\n OrganicResult, LocalPackBusiness,\n} from '../types.js'\nimport type { IPAAExtractor } from './IPAAExtractor.js'\n\nexport class PAAExtractor implements IPAAExtractor {\n constructor(\n private readonly driver: IBrowserDriver,\n private readonly reporter: IProgressReporter,\n ) {}\n\n private normalizeQuestion(q: string): NormalizedQuestionKey {\n return q.toLowerCase().replace(/[^\\w\\s]/g, '').replace(/\\s+/g, ' ').trim() as NormalizedQuestionKey\n }\n\n private async extractVisibleItems(page: Page): Promise<RawPAAItem[]> {\n const sels = PAASelectors\n const raw = await page.evaluate((selectors) => {\n function cleanText(el: Element | null): string {\n if (!el) return ''\n const parts: string[] = []\n for (const n of el.childNodes) {\n if (n.nodeType === Node.TEXT_NODE) {\n const text = n.textContent?.trim()\n if (text) parts.push(text)\n } else if (\n (n as Element).tagName === 'STYLE' ||\n (n as Element).tagName === 'SCRIPT'\n ) {\n continue\n } else {\n const text = cleanText(n as Element)\n if (text) parts.push(text)\n }\n }\n return parts.join(' ').replace(/\\s+/g, ' ').trim()\n }\n return Array.from(document.querySelectorAll(selectors.item)).map((pair) => ({\n question: pair.getAttribute(selectors.itemDataQ) || pair.getAttribute(selectors.itemDataInitQ) || '',\n answer: cleanText(pair.querySelector(selectors.answerContainer)) || undefined,\n sourceTitle: (pair.querySelector(selectors.sourceTitle) as HTMLElement | null)?.innerText?.trim() || undefined,\n sourceSite: (pair.querySelector(selectors.sourceSite) as HTMLElement | null)?.innerText?.trim() || undefined,\n sourceCite: (pair.querySelector(selectors.sourceCite) as HTMLElement | null)?.innerText?.trim() || undefined,\n }))\n }, sels)\n\n return raw.flatMap((item) => {\n const cleaned = {\n ...item,\n answer: cleanPAAAnswerText(item.answer, item.question, item.sourceTitle),\n }\n const result = RawPAAItemSchema.safeParse(cleaned)\n if (!result.success) {\n console.warn('[PAAExtractor] item parse failed:', item.question, result.error.issues[0]?.message)\n return []\n }\n return [result.data]\n })\n }\n\n private async clickItem(page: Page, questionText: string): Promise<void> {\n try {\n const pairLocator = page.locator(\n `${PAASelectors.item}[data-q=\"${questionText}\"], ${PAASelectors.item}[data-initq=\"${questionText}\"]`\n ).first()\n await pairLocator.click()\n } catch { }\n }\n\n private toFlatRow(item: RawPAAItem, depth: number, parentQuestion: string | null, seed: string): FlatRow {\n return {\n seed_query: seed,\n question: item.question,\n answer: item.answer ?? '',\n source_title: item.sourceTitle ?? '',\n source_site: item.sourceSite ?? '',\n source_cite: item.sourceCite ?? '',\n depth,\n parent_question: parentQuestion ?? '',\n extracted_at: new Date().toISOString(),\n }\n }\n\n private async runBFS(page: Page, options: HarvestOptions): Promise<FlatRow[]> {\n const seenKeys = new Set<NormalizedQuestionKey>()\n const seenQs = new Set<string>()\n const depthMap = new Map<string, number>()\n const results: FlatRow[] = []\n\n const readAllQs = (): Promise<string[]> =>\n page.evaluate(\n ({ sel, dataQ, dataInitQ, questionEl }: { sel: string; dataQ: string; dataInitQ: string; questionEl: string }) =>\n Array.from(document.querySelectorAll(sel))\n .map(el =>\n el.getAttribute(dataQ) ||\n el.getAttribute(dataInitQ) ||\n (el.querySelector(questionEl) as HTMLElement | null)?.innerText?.trim() ||\n ''\n )\n .filter(Boolean),\n { sel: PAASelectors.item, dataQ: PAASelectors.itemDataQ, dataInitQ: PAASelectors.itemDataInitQ, questionEl: PAASelectors.itemQuestionEl },\n )\n\n const dupRates: number[] = []\n const orderedQs: string[] = []\n\n for (let round = 0; round < options.depth; round++) {\n this.reporter.onDepth(round + 1)\n\n if (seenQs.size >= options.maxQuestions) break\n\n const beforeQs = await readAllQs()\n if (beforeQs.length >= options.maxQuestions) break\n\n const unexpandedItems = await page.$$(\n `${PAASelectors.item}:not(.${PAASelectors.expandedClass})`\n )\n if (unexpandedItems.length === 0) break\n\n for (const item of unexpandedItems) {\n try {\n await item.scrollIntoViewIfNeeded()\n await item.click({ force: true })\n await page.waitForTimeout(500)\n } catch { }\n }\n await page.waitForTimeout(1500)\n\n const afterQs = await readAllQs()\n const newQs = afterQs.slice(beforeQs.length)\n\n const newDups = newQs.filter(q => seenQs.has(q)).length\n const dupRate = newQs.length > 0 ? newDups / newQs.length : 0\n dupRates.push(dupRate)\n if (dupRates.length > 2) dupRates.shift()\n const rollingDupRate = dupRates.reduce((a, b) => a + b, 0) / dupRates.length\n\n for (const q of afterQs) {\n if (!seenQs.has(q)) { seenQs.add(q); orderedQs.push(q) }\n if (!depthMap.has(q)) depthMap.set(q, round + 1)\n }\n\n if (afterQs.length === beforeQs.length) break\n if (rollingDupRate >= 0.6) break\n }\n\n const itemMap = new Map((await this.extractVisibleItems(page)).map(i => [i.question, i]))\n\n for (const q of orderedQs) {\n if (results.length >= options.maxQuestions) break\n const key = this.normalizeQuestion(q)\n if (seenKeys.has(key)) continue\n seenKeys.add(key)\n const d = depthMap.get(q) ?? 1\n const item = itemMap.get(q)\n if (item) {\n results.push(this.toFlatRow(item, d, null, options.query))\n this.reporter.onQuestion({ question: item.question, answer: item.answer ?? null, sourceTitle: item.sourceTitle ?? null, sourceSite: item.sourceSite ?? null, sourceCite: item.sourceCite ?? null, depth: d, parentQuestion: null, children: [] })\n } else {\n results.push(this.toFlatRow({ question: q, answer: undefined, sourceTitle: undefined, sourceSite: undefined, sourceCite: undefined }, d, null, options.query))\n }\n }\n\n return results\n }\n\n private async extractVideos(page: Page): Promise<VideoResult[]> {\n const vsels = VideoSelectors\n return page.evaluate((sels) => {\n const results: Array<{ type: 'video' | 'short_video'; title: string; channel: string; platform: string; duration: string; url: string }> = []\n const containers = Array.from(document.querySelectorAll(sels.container))\n for (const container of containers) {\n const headingEl = container.querySelector(sels.sectionHeading)\n const headingText = headingEl?.textContent?.trim() ?? ''\n const type: 'video' | 'short_video' = headingText.toLowerCase().includes('short') ? 'short_video' : 'video'\n const items = Array.from(container.querySelectorAll(sels.item))\n for (const a of items) {\n const href = (a as HTMLAnchorElement).href\n if (!href || (!href.includes('youtube') && !href.includes('youtu.be'))) continue\n const raw = a.textContent?.trim() ?? ''\n const ytIdx = raw.indexOf('YouTube')\n if (ytIdx === -1) continue\n const title = raw.slice(0, ytIdx).trim()\n const remainder = raw.slice(ytIdx + 7).replace(/^[·\\s·]+/, '')\n const channelMatch = remainder.match(/^([^·\\n]+)/)\n const channel = channelMatch ? channelMatch[1].trim() : ''\n if (title) results.push({ type, title, channel, platform: 'YouTube', duration: '', url: href })\n }\n }\n return results\n }, vsels)\n }\n\n private async extractForums(page: Page): Promise<ForumResult[]> {\n const fsels = ForumSelectors\n return page.evaluate((sels) => {\n const results: Array<{ title: string; source: string; url: string }> = []\n const sections = Array.from(document.querySelectorAll(sels.section))\n const forumSection = sections.find((s) => s.textContent?.includes('Discussions'))\n if (!forumSection) return results\n const items = Array.from(forumSection.querySelectorAll(sels.item))\n for (const a of items) {\n const href = (a as HTMLAnchorElement).href\n if (!href) continue\n const titleEl = a.querySelector(sels.title)\n const sourceEl = a.querySelector(sels.source)\n const title = titleEl?.textContent?.trim() ?? ''\n const source = sourceEl?.textContent?.trim() ?? ''\n if (title) results.push({ title, source, url: href })\n }\n return results\n }, fsels)\n }\n\n private async extractShortVideos(page: Page, shortUrl: string): Promise<VideoResult[]> {\n try {\n await page.goto(shortUrl, { waitUntil: 'domcontentloaded' })\n await page.waitForTimeout(1500)\n } catch {\n return []\n }\n\n const svSels = {\n item: ShortVideoSelectors.item,\n platforms: [...ShortVideoSelectors.platforms] as string[],\n }\n\n const raw = await page.evaluate((sels) => {\n const seen = new Set<string>()\n const results: Array<{ title: string; channel: string; platform: string; duration: string; url: string }> = []\n const items = Array.from(document.querySelectorAll(sels.item))\n\n const videoHosts = ['youtube.com', 'youtu.be', 'tiktok.com', 'instagram.com', 'facebook.com', 'fb.watch']\n\n const byHref = new Map<string, string[]>()\n for (const a of items) {\n const href = (a as HTMLAnchorElement).href\n if (!href) continue\n if (!videoHosts.some((h) => href.includes(h))) continue\n const text = a.textContent?.trim() ?? ''\n if (!byHref.has(href)) byHref.set(href, [])\n byHref.get(href)!.push(text)\n }\n\n for (const [href, texts] of byHref.entries()) {\n if (seen.has(href)) continue\n seen.add(href)\n\n const duration = texts.find((t) => /^\\d+:\\d+$/.test(t)) ?? ''\n const titleText = texts.find((t) => !/^\\d+:\\d+$/.test(t) && t.length > 5) ?? ''\n if (!titleText) continue\n\n let title = titleText\n let platform = ''\n let channel = ''\n\n for (const p of sels.platforms) {\n let lastIdx = -1\n let search = 0\n while (true) {\n const found = titleText.indexOf(p, search)\n if (found === -1) break\n lastIdx = found\n search = found + 1\n }\n if (lastIdx === -1) continue\n const after = titleText.slice(lastIdx + p.length)\n const isSourceTag = /^[\\s·]/.test(after) || after.trim() === ''\n if (!isSourceTag) continue\n title = titleText.slice(0, lastIdx).trim()\n platform = p\n const stripped = after.replace(/^[\\s·]+/, '')\n const dotIdx = stripped.indexOf('·')\n channel = (dotIdx === -1 ? stripped : stripped.slice(0, dotIdx)).trim()\n break\n }\n\n if (title) results.push({ title, channel, platform, duration, url: href })\n }\n\n return results\n }, svSels)\n\n return raw.map((r) => ({ type: 'short_video' as const, ...r }))\n }\n\n private async extractWhatPeopleSaying(page: Page): Promise<WhatPeopleSayingCard[]> {\n const sels = WhatPeopleSayingSelectors\n return page.evaluate((s) => {\n const section = Array.from(document.querySelectorAll(s.sectionTag))\n .find((el) => el.textContent?.includes(s.sectionHeadingText))\n ?? document.querySelector('.yG4QQe.TBC9ub.NbhJ1c')\n\n if (!section) return []\n\n return Array.from(section.querySelectorAll(s.card)).map((card) => {\n const link = card.querySelector(s.cardLink) as HTMLAnchorElement | null\n const url = link?.href ?? ''\n\n const titleH1 = card.querySelector(s.titleH1)?.textContent?.trim()\n const titleDiv = card.querySelector(s.titleDiv)?.textContent?.trim()\n const title = titleH1 ?? titleDiv ?? ''\n\n const sourceText = card.querySelector(s.source)?.textContent?.trim() ?? ''\n const platformEl = card.querySelector(s.platformBadge)\n const platformText = platformEl?.textContent?.trim() ?? ''\n\n const ytChannel = card.querySelector(s.ytChannel)?.textContent?.trim() ?? ''\n const ytDate = card.querySelector(s.ytDate)?.textContent?.trim() ?? ''\n const authorNote = card.querySelector(s.authorNote)?.textContent?.trim() ?? null\n\n const commentLabelEl = card.querySelector(s.popularCommentLabel)\n let popularComment: string | null = null\n if (commentLabelEl) {\n let next = commentLabelEl.nextSibling\n while (next) {\n const t = next.textContent?.trim()\n if (t) { popularComment = t; break }\n next = next.nextSibling\n }\n }\n\n const allSpans = Array.from(card.querySelectorAll('span'))\n const duration = allSpans.find((s) => /^\\d+:\\d+$/.test(s.textContent?.trim() ?? ''))?.textContent?.trim() ?? null\n const engagementParts = allSpans\n .map((s) => s.textContent?.trim() ?? '')\n .filter((t) =>\n /\\d/.test(t) && (\n t.includes('comment') || t.includes('reaction') ||\n t.includes('view') || t.includes('like') || t.includes('share')\n )\n )\n const engagement = engagementParts[0] ?? ''\n\n const dateCandidates = allSpans\n .map((s) => s.textContent?.trim() ?? '')\n .filter((t) => /\\d+ (day|week|month|year|hour)s? ago|Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec/.test(t))\n const date = ytDate || (dateCandidates[0] ?? '')\n\n const platform = platformText || (ytChannel ? 'YouTube' : '')\n const source = ytChannel || sourceText\n\n let type: 'reddit' | 'facebook' | 'youtube' | 'instagram' | 'tiktok' | 'news' | 'unknown' = 'unknown'\n const pl = platform.toLowerCase()\n const src = source.toLowerCase()\n const srcRaw = sourceText.toLowerCase()\n if (pl.includes('reddit') || src.startsWith('r/')) type = 'reddit'\n else if (pl.includes('facebook') || srcRaw.includes('facebook')) type = 'facebook'\n else if (pl.includes('instagram') || srcRaw.includes('instagram')) type = 'instagram'\n else if (pl.includes('tiktok') || srcRaw.includes('tiktok')) type = 'tiktok'\n else if (pl.includes('youtube') || !!ytChannel) type = 'youtube'\n else type = 'news'\n\n return { type, title, url, source, platform, popularComment, engagement, date, duration, authorNote }\n })\n }, sels)\n }\n\n private async extractOrganicResults(page: Page): Promise<OrganicResult[]> {\n const sels = OrganicSelectors\n return page.evaluate((s) => {\n const out: Array<{ position: number; title: string; url: string; domain: string; cite: string | null; snippet: string | null; isRedditStyle: boolean; inlineRating: { value: string; count: string } | null }> = []\n let pos = 0\n document.querySelectorAll(s.result).forEach(card => {\n const titleEl = card.querySelector(s.title)\n if (!titleEl) return\n const title = titleEl.textContent?.trim() ?? ''\n const linkEl = titleEl.closest('a') as HTMLAnchorElement | null\n const url = linkEl?.href ?? ''\n if (!title || !url) return\n pos++\n const cite = card.querySelector(s.cite)?.textContent?.trim() ?? null\n const snippet = card.querySelector(s.snippet)?.textContent?.trim() ?? null\n const isRedditStyle = !!card.querySelector(s.redditCite)\n const ratingEl = card.querySelector(s.ratingWrap)\n const inlineRating = ratingEl\n ? { value: ratingEl.querySelector(s.ratingValue)?.textContent?.trim() ?? '', count: ratingEl.querySelector(s.reviewCount)?.textContent?.trim() ?? '' }\n : null\n let domain = ''\n try { domain = new URL(url).hostname.replace(/^www\\./, '') } catch { domain = card.querySelector(s.siteName)?.textContent?.trim() ?? '' }\n out.push({ position: pos, title, url, domain, cite, snippet, isRedditStyle, inlineRating })\n })\n return out\n }, sels)\n }\n\n private async extractLocalPack(page: Page): Promise<LocalPackBusiness[]> {\n const sels = LocalPackSelectors\n return page.evaluate((s) => {\n const out: Array<{ position: number; name: string; cid: string | null; rating: string | null; reviewCount: string | null; metadata: string[]; websiteUrl: string | null; directionsUrl: string | null }> = []\n let container: Element | null = null\n document.querySelectorAll('[role=\"heading\"]').forEach(h => {\n if (!container && h.textContent?.includes(s.headingText)) container = h.closest('[data-hveid]')\n })\n if (!container) return out\n ;(container as Element).querySelectorAll(s.card).forEach((card, i) => {\n const name = card.querySelector(s.name)?.textContent?.trim() ?? ''\n if (!name) return\n const rating = card.querySelector(s.ratingValue)?.textContent?.trim() ?? null\n const reviewRaw = card.querySelector(s.reviewCount)?.textContent?.trim() ?? null\n const reviewCount = reviewRaw ? reviewRaw.replace(/[()]/g, '').trim() : null\n let cid = (card.querySelector('a[data-cid]') as HTMLAnchorElement | null)?.getAttribute('data-cid') ?? null\n if (!cid) {\n for (const link of Array.from(card.querySelectorAll('a[href]')) as HTMLAnchorElement[]) {\n const m1 = link.href.match(/[?&]cid=(\\d+)/)\n if (m1) { cid = m1[1]; break }\n const m2 = link.href.match(/!1s0x[0-9a-f]+:0x([0-9a-f]+)/i)\n if (m2) { try { cid = BigInt('0x' + m2[1]).toString() } catch { } if (cid) break }\n }\n }\n const metadata: string[] = []\n card.querySelectorAll('div, span').forEach(el => {\n const text = Array.from(el.childNodes)\n .filter(n => n.nodeType === 3)\n .map(n => n.textContent?.trim() ?? '')\n .filter(t => t.length > 1 && t.length < 120)\n .join(' ')\n if (text && !metadata.includes(text)) metadata.push(text)\n })\n const links = Array.from(card.querySelectorAll('a[href]')) as HTMLAnchorElement[]\n const directionsUrl = links.find(a => a.href.includes('google.com/maps'))?.href ?? null\n const websiteUrl = links.find(a => !a.href.includes('google.com') && a.href.startsWith('http'))?.href ?? null\n out.push({ position: i + 1, name, cid, rating, reviewCount, metadata, websiteUrl, directionsUrl })\n })\n return out\n }, sels)\n }\n\n private async extractEntityIds(page: Page): Promise<EntityIds> {\n return page.evaluate(() => {\n const kgIds = new Set<string>()\n const cids = new Set<string>()\n const gcids = new Set<string>()\n const recordMap = new Map<string, { name: string; kgId: string | null; cid: string | null; gcid: string | null }>()\n\n function nameFromWrapper(el: Element): string {\n const sel = ['.OSrXXb', '.dbg0pd', '.tzt0oe', '[role=\"heading\"]', 'h3']\n for (const s of sel) {\n const found = el.querySelector(s)\n if (found?.textContent?.trim()) return found.textContent.trim()\n }\n return ''\n }\n\n document.querySelectorAll('[id^=\"pv-/g/\"]').forEach(wrapper => {\n const raw = wrapper.getAttribute('id')\n if (!raw) return\n const kgId = raw.replace('pv-', '')\n kgIds.add(kgId)\n const name = nameFromWrapper(wrapper)\n const cidEl = wrapper.querySelector('a[data-cid]')\n const cid = cidEl?.getAttribute('data-cid') ?? null\n if (cid) cids.add(cid)\n if (name) recordMap.set(kgId, { name, kgId, cid, gcid: null })\n })\n\n document.querySelectorAll('[data-mid]').forEach(el => {\n const mid = el.getAttribute('data-mid')\n if (!mid?.startsWith('/g/')) return\n kgIds.add(mid)\n if (!recordMap.has(mid)) {\n const name = nameFromWrapper(el)\n if (name) recordMap.set(mid, { name, kgId: mid, cid: null, gcid: null })\n }\n })\n\n document.querySelectorAll('.w7Dbne').forEach(card => {\n const cidEl = card.querySelector('a[data-cid]')\n const cid = cidEl?.getAttribute('data-cid') ?? null\n if (!cid) return\n cids.add(cid)\n const name = card.querySelector('.OSrXXb')?.textContent?.trim() ?? ''\n if (!name) return\n const kgIdEl = card.querySelector('[id^=\"pv-/g/\"]')\n const kgId = kgIdEl ? kgIdEl.getAttribute('id')!.replace('pv-', '') : null\n const key = kgId ?? `cid:${cid}`\n if (recordMap.has(key)) {\n const existing = recordMap.get(key)!\n if (!existing.cid) recordMap.set(key, { ...existing, cid })\n } else {\n recordMap.set(key, { name, kgId, cid, gcid: null })\n }\n })\n\n document.querySelectorAll('a[data-cid]').forEach(el => {\n const cid = el.getAttribute('data-cid')\n if (!cid) return\n cids.add(cid)\n const alreadyNamed = [...recordMap.values()].some(r => r.cid === cid)\n if (!alreadyNamed) {\n let node: Element | null = el.parentElement\n let name = ''\n for (let i = 0; i < 8 && node; i++) {\n const h = node.querySelector('.OSrXXb, .dbg0pd, [role=\"heading\"], h3')\n if (h?.textContent?.trim()) { name = h.textContent.trim(); break }\n node = node.parentElement\n }\n if (name) recordMap.set(`cid:${cid}`, { name, kgId: null, cid, gcid: null })\n }\n })\n\n const scriptContent = Array.from(document.querySelectorAll('script:not([src])'))\n .map(s => s.textContent ?? '')\n .filter(t => t.length > 10_000)\n .join('\\n')\n\n for (const m of scriptContent.matchAll(/\\/g\\/[a-zA-Z0-9_-]{5,20}/g)) kgIds.add(m[0])\n for (const m of scriptContent.matchAll(/gcid:[a-zA-Z0-9_]+/g)) gcids.add(m[0])\n for (const m of scriptContent.matchAll(/0x[0-9a-f]+:0x([0-9a-f]+)/gi)) {\n try { cids.add(BigInt('0x' + m[1]).toString()) } catch { }\n }\n\n return { entities: [...recordMap.values()], kgIds: [...kgIds], cids: [...cids], gcids: [...gcids] }\n })\n }\n\n private mergeLocalPackIntoEntities(entityIds: EntityIds, localPack: LocalPackBusiness[]): EntityIds {\n const cidSet = new Set<string>(entityIds.cids)\n const records = entityIds.entities.map(r => ({ ...r }))\n\n for (const biz of localPack) {\n if (!biz.cid) continue\n cidSet.add(biz.cid)\n const nameNorm = biz.name.toLowerCase().trim()\n const byName = records.find(r => r.name.toLowerCase().trim() === nameNorm)\n if (byName) {\n if (!byName.cid) byName.cid = biz.cid\n } else if (!records.find(r => r.cid === biz.cid)) {\n records.push({ name: biz.name, kgId: null, cid: biz.cid, gcid: null })\n }\n }\n\n return { ...entityIds, entities: records, cids: [...cidSet] }\n }\n\n private async extractAISurfaces(page: Page): Promise<{\n surface: GoogleSurface\n aiOverview: AIOverviewResult\n aiMode: AIModeResult\n }> {\n const aioSels = AIOverviewSelectors\n const aimSels = AIModeSelectors\n\n return page.evaluate(({ aio, aim }) => {\n const sn: string = (window as unknown as { google?: { sn?: string } }).google?.sn ?? 'unknown'\n const surface: 'web' | 'aim' | 'unknown' =\n sn === 'aim' ? 'aim' : sn === 'web' ? 'web' : 'unknown'\n\n function findAIORoot(): Element | null {\n const primary = document.querySelector(aio.root)\n if (primary) return primary\n const headings = document.querySelectorAll('h1, h2, h3, [role=\"heading\"]')\n for (const h of headings) {\n if (h.textContent?.trim() === 'AI Overview') {\n let el: Element | null = h.parentElement\n for (let i = 0; i < 6 && el; i++) {\n if (el.querySelectorAll('a').length > 1) return el\n el = el.parentElement\n }\n return h.parentElement\n }\n }\n return null\n }\n\n const aioRoot = findAIORoot()\n const aioContainer = aioRoot ? (aioRoot.closest(aio.wrapper) ?? aioRoot) : null\n\n let aioText: string | null = null\n if (aioContainer) {\n const clone = aioContainer.cloneNode(true) as Element\n clone.querySelectorAll('script,style,noscript').forEach((el) => el.remove())\n clone.querySelectorAll('h1,h2,h3,h4,[role=\"heading\"]').forEach((el) => el.remove())\n clone.querySelectorAll('button,[role=\"button\"]').forEach((el) => el.remove())\n clone.querySelectorAll('a').forEach((el) => el.remove())\n const candidate = clone.textContent?.replace(/\\s+/g, ' ').trim() || null\n const isErrorState = !candidate ||\n /not available|try again|can't generate/i.test(candidate)\n aioText = isErrorState ? null : candidate\n }\n\n const aioDetected = !!aioRoot && aioText !== null\n\n const aioCitations = Array.from(aioContainer?.querySelectorAll('a[href]') ?? [])\n .filter((a) => (a as HTMLAnchorElement).href && !(a as HTMLAnchorElement).href.startsWith('javascript'))\n .map((a) => ({\n text: (a as HTMLAnchorElement).textContent?.trim() ?? '',\n href: (a as HTMLAnchorElement).href,\n }))\n .filter((c) => c.text && c.href)\n\n const aimRoot = document.querySelector(aim.root)\n const aimDetected = surface === 'aim' && !!aimRoot\n const aimContainer = aimRoot?.closest(aim.wrapper) ?? null\n\n let aimText: string | null = null\n if (aimContainer) {\n const clone = aimContainer.cloneNode(true) as Element\n clone.querySelectorAll('script,style,noscript').forEach((el) => el.remove())\n clone.querySelectorAll('h1,h2,h3,h4,[role=\"heading\"]').forEach((el) => el.remove())\n clone.querySelectorAll('button,[role=\"button\"]').forEach((el) => el.remove())\n clone.querySelectorAll('a').forEach((el) => el.remove())\n const candidate = clone.textContent?.replace(/\\s+/g, ' ').trim() || null\n const isErrorState = !candidate ||\n /not available|try again|can't generate/i.test(candidate)\n aimText = isErrorState ? null : candidate\n }\n\n const aimCitations = aimDetected\n ? Array.from(aimContainer?.querySelectorAll('a[href]') ?? [])\n .filter((a) => (a as HTMLAnchorElement).href && !(a as HTMLAnchorElement).href.startsWith('javascript'))\n .map((a) => ({\n text: (a as HTMLAnchorElement).textContent?.trim() ?? '',\n href: (a as HTMLAnchorElement).href,\n }))\n .filter((c) => c.text && c.href)\n : []\n\n return {\n surface,\n aiOverview: { detected: aioDetected, text: aioText, citations: aioCitations },\n aiMode: { detected: aimDetected, text: aimText, citations: aimCitations },\n }\n }, { aio: aioSels, aim: aimSels })\n }\n\n private buildTree(flat: FlatRow[], _seed: string): PAANode[] {\n const roots: PAANode[] = []\n const nodeMap = new Map<string, PAANode>()\n\n for (const row of flat) {\n const node: PAANode = {\n question: row.question,\n answer: row.answer || null,\n sourceTitle: row.source_title || null,\n sourceSite: row.source_site || null,\n sourceCite: row.source_cite || null,\n depth: row.depth,\n parentQuestion: row.parent_question || null,\n children: [],\n }\n nodeMap.set(row.question, node)\n }\n\n for (const node of nodeMap.values()) {\n if (node.parentQuestion && nodeMap.has(node.parentQuestion)) {\n nodeMap.get(node.parentQuestion)!.children.push(node)\n } else {\n roots.push(node)\n }\n }\n\n return roots\n }\n\n async extract(options: HarvestOptions): Promise<HarvestResult> {\n const startMs = Date.now()\n const config: DriverConfig = {\n headless: options.headless,\n profileDir: options.profileDir,\n proxy: options.proxy,\n kernelApiKey: options.kernelApiKey,\n kernelProxyId: options.kernelProxyId,\n viewport: { width: 1280, height: 800 },\n locale: `${options.hl}-${options.gl.toUpperCase()}`,\n }\n\n let errorCount = 0\n\n try {\n await this.driver.launch(config)\n const uule = options.location ? encodeUule(normalizeLocation(options.location)) : null\n const { hasPaa } = await this.driver.navigateToSERP(options.query, uule, options.gl, options.hl)\n\n const page = this.driver.getPage() as Page\n\n if (options.serpOnly) {\n const [organicResults, localPack, rawEntityIds] = await Promise.all([\n this.extractOrganicResults(page),\n this.extractLocalPack(page),\n this.extractEntityIds(page),\n ])\n const entityIds = this.mergeLocalPackIntoEntities(rawEntityIds, localPack)\n let allOrganic = organicResults\n if ((options.pages ?? 1) >= 2) {\n const p2params = new URLSearchParams({ q: options.query, gl: options.gl, hl: options.hl, start: '10' })\n if (uule) p2params.set('uule', uule)\n await this.driver.navigateTo('https://www.google.com/search?' + p2params.toString())\n const p2organic = await this.extractOrganicResults(page)\n allOrganic = [...organicResults, ...p2organic.map(r => ({ ...r, position: r.position + 10 }))]\n }\n const stats: HarvestStats = {\n seed: options.query, totalQuestions: 0, maxDepthReached: 0,\n durationMs: Date.now() - startMs, errorCount,\n }\n this.reporter.onComplete(stats)\n return {\n seed: options.query, location: options.location ?? null,\n extractedAt: new Date().toISOString(), totalQuestions: 0,\n surface: 'web' as const,\n aiOverview: { detected: false, text: null, citations: [] },\n aiMode: { detected: false, text: null, citations: [] },\n whatPeopleSaying: [], tree: [], flat: [], videos: [], forums: [],\n organicResults: allOrganic, localPack, entityIds, stats,\n }\n }\n\n const [videos, forums, whatPeopleSaying, rawEntityIds, organicResults, localPack] = await Promise.all([\n this.extractVideos(page),\n this.extractForums(page),\n this.extractWhatPeopleSaying(page),\n this.extractEntityIds(page),\n this.extractOrganicResults(page),\n this.extractLocalPack(page),\n ])\n const entityIds = this.mergeLocalPackIntoEntities(rawEntityIds, localPack)\n this.reporter.onVideos(videos)\n this.reporter.onForums(forums)\n\n if (!hasPaa) {\n let noPaaOrganic = organicResults\n if ((options.pages ?? 1) >= 2) {\n const p2params = new URLSearchParams({ q: options.query, gl: options.gl, hl: options.hl, start: '10' })\n if (uule) p2params.set('uule', uule)\n await this.driver.navigateTo('https://www.google.com/search?' + p2params.toString())\n const p2organic = await this.extractOrganicResults(page)\n noPaaOrganic = [...organicResults, ...p2organic.map(r => ({ ...r, position: r.position + 10 }))]\n }\n const aiSurfaces = await this.extractAISurfaces(page)\n const stats: HarvestStats = {\n seed: options.query, totalQuestions: 0, maxDepthReached: 0,\n durationMs: Date.now() - startMs, errorCount,\n }\n this.reporter.onComplete(stats)\n return {\n seed: options.query, location: options.location ?? null,\n extractedAt: new Date().toISOString(), totalQuestions: 0,\n surface: aiSurfaces.surface,\n aiOverview: aiSurfaces.aiOverview,\n aiMode: aiSurfaces.aiMode,\n whatPeopleSaying, tree: [], flat: [], videos, forums,\n organicResults: noPaaOrganic, localPack, entityIds, stats,\n }\n }\n\n const flat = await this.runBFS(page, options)\n const aiSurfaces = await this.extractAISurfaces(page)\n\n const shortVidsParams = new URLSearchParams({ q: options.query, gl: options.gl, hl: options.hl, udm: ShortVideoSelectors.udm })\n if (uule) shortVidsParams.set('uule', uule)\n const shortVideos = await this.extractShortVideos(page, 'https://www.google.com/search?' + shortVidsParams.toString())\n this.reporter.onVideos(shortVideos)\n\n let allOrganic = organicResults\n if ((options.pages ?? 1) >= 2) {\n const p2params = new URLSearchParams({ q: options.query, gl: options.gl, hl: options.hl, start: '10' })\n if (uule) p2params.set('uule', uule)\n await this.driver.navigateTo('https://www.google.com/search?' + p2params.toString())\n const p2organic = await this.extractOrganicResults(page)\n allOrganic = [...organicResults, ...p2organic.map(r => ({ ...r, position: r.position + 10 }))]\n }\n\n const allVideos = [...videos, ...shortVideos]\n const tree = this.buildTree(flat, options.query)\n\n const stats: HarvestStats = {\n seed: options.query,\n totalQuestions: flat.length,\n maxDepthReached: flat.reduce((m, r) => Math.max(m, r.depth), 0),\n durationMs: Date.now() - startMs,\n errorCount,\n }\n\n this.reporter.onComplete(stats)\n\n return {\n seed: options.query,\n location: options.location ?? null,\n extractedAt: new Date().toISOString(),\n totalQuestions: flat.length,\n surface: aiSurfaces.surface,\n aiOverview: aiSurfaces.aiOverview,\n aiMode: aiSurfaces.aiMode,\n whatPeopleSaying,\n tree,\n flat,\n videos: allVideos,\n forums,\n organicResults: allOrganic,\n localPack,\n entityIds,\n stats,\n }\n } catch (err) {\n errorCount++\n this.reporter.onError(err instanceof Error ? err : new Error(String(err)))\n throw err\n } finally {\n await this.driver.close()\n }\n }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport Papa from 'papaparse'\nimport type { HarvestResult, FlatRow, VideoResult, ForumResult, AICitation, WhatPeopleSayingCard } from '../types.js'\nimport type { IOutputSerializer } from './IOutputSerializer.js'\n\nexport class OutputSerializer implements IOutputSerializer {\n async writeJSON(result: HarvestResult, outputDir: string): Promise<string> {\n await fs.mkdir(outputDir, { recursive: true })\n const slug = result.seed.toLowerCase().replace(/\\W+/g, '-').slice(0, 40)\n const filename = `${slug}-${Date.now()}.json`\n const fullPath = path.join(outputDir, filename)\n await fs.writeFile(fullPath, JSON.stringify(result, null, 2), 'utf8')\n return fullPath\n }\n\n async writeCSV(rows: FlatRow[], outputDir: string): Promise<string> {\n await fs.mkdir(outputDir, { recursive: true })\n const seedRaw = rows[0]?.seed_query ?? 'paa'\n const slug = seedRaw.toLowerCase().replace(/\\W+/g, '-').slice(0, 40)\n const csv = Papa.unparse(rows, { header: true })\n const filename = `${slug}-${Date.now()}.csv`\n const fullPath = path.join(outputDir, filename)\n await fs.writeFile(fullPath, csv, 'utf8')\n return fullPath\n }\n\n async writeVideoCSV(videos: VideoResult[], seed: string, outputDir: string): Promise<string> {\n await fs.mkdir(outputDir, { recursive: true })\n const slug = seed.toLowerCase().replace(/\\W+/g, '-').slice(0, 40)\n const csv = Papa.unparse(videos, { header: true })\n const filename = `${slug}-videos-${Date.now()}.csv`\n const fullPath = path.join(outputDir, filename)\n await fs.writeFile(fullPath, csv, 'utf8')\n return fullPath\n }\n\n async writeForumCSV(forums: ForumResult[], seed: string, outputDir: string): Promise<string> {\n await fs.mkdir(outputDir, { recursive: true })\n const slug = seed.toLowerCase().replace(/\\W+/g, '-').slice(0, 40)\n const csv = Papa.unparse(forums, { header: true })\n const filename = `${slug}-forums-${Date.now()}.csv`\n const fullPath = path.join(outputDir, filename)\n await fs.writeFile(fullPath, csv, 'utf8')\n return fullPath\n }\n\n async writeAIOverviewCSV(citations: AICitation[], text: string | null, seed: string, outputDir: string): Promise<string> {\n await fs.mkdir(outputDir, { recursive: true })\n const slug = seed.toLowerCase().replace(/\\W+/g, '-').slice(0, 40)\n const rows = citations.map((c, i) => ({\n seed_query: seed,\n response_text: i === 0 ? (text ?? '') : '',\n citation_text: c.text,\n citation_href: c.href,\n }))\n const csv = Papa.unparse(rows, { header: true })\n const filename = `${slug}-ai-overview-${Date.now()}.csv`\n const fullPath = path.join(outputDir, filename)\n await fs.writeFile(fullPath, csv, 'utf8')\n return fullPath\n }\n\n async writeAIModeCSV(citations: AICitation[], text: string | null, seed: string, outputDir: string): Promise<string> {\n await fs.mkdir(outputDir, { recursive: true })\n const slug = seed.toLowerCase().replace(/\\W+/g, '-').slice(0, 40)\n const rows = citations.map((c, i) => ({\n seed_query: seed,\n response_text: i === 0 ? (text ?? '') : '',\n citation_text: c.text,\n citation_href: c.href,\n }))\n const csv = Papa.unparse(rows, { header: true })\n const filename = `${slug}-ai-mode-${Date.now()}.csv`\n const fullPath = path.join(outputDir, filename)\n await fs.writeFile(fullPath, csv, 'utf8')\n return fullPath\n }\n\n async writeWhatPeopleSayingCSV(cards: WhatPeopleSayingCard[], seed: string, outputDir: string): Promise<string> {\n await fs.mkdir(outputDir, { recursive: true })\n const slug = seed.toLowerCase().replace(/\\W+/g, '-').slice(0, 40)\n const rows = cards.map((c) => ({ seed_query: seed, ...c }))\n const csv = Papa.unparse(rows, { header: true })\n const filename = `${slug}-what-people-saying-${Date.now()}.csv`\n const fullPath = path.join(outputDir, filename)\n await fs.writeFile(fullPath, csv, 'utf8')\n return fullPath\n }\n}\n","import type { PAANode, HarvestStats, VideoResult, ForumResult } from '../types.js'\nimport type { IProgressReporter } from './IProgressReporter.js'\n\nexport class ProgressReporter implements IProgressReporter {\n onQuestion(node: PAANode): void {\n process.stdout.write(JSON.stringify({ event: 'question', depth: node.depth, question: node.question }) + '\\n')\n }\n\n onDepth(depth: number): void {\n process.stdout.write(JSON.stringify({ event: 'depth', depth }) + '\\n')\n }\n\n onVideos(videos: VideoResult[]): void {\n for (const v of videos) {\n process.stdout.write(JSON.stringify({ event: 'video', type: v.type, platform: v.platform, duration: v.duration, title: v.title, channel: v.channel, url: v.url }) + '\\n')\n }\n }\n\n onForums(forums: ForumResult[]): void {\n for (const f of forums) {\n process.stdout.write(JSON.stringify({ event: 'forum', title: f.title, source: f.source, url: f.url }) + '\\n')\n }\n }\n\n onComplete(stats: HarvestStats): void {\n process.stdout.write(JSON.stringify({ event: 'complete', ...stats }) + '\\n')\n }\n\n onError(err: Error): void {\n process.stderr.write(JSON.stringify({ event: 'error', type: err.constructor.name, message: err.message }) + '\\n')\n }\n}\n","import { HarvestOptionsSchema } from './schemas.js'\nimport type { HarvestOptions, HarvestResult } from './types.js'\nimport { BrowserDriver } from './driver/BrowserDriver.js'\nimport { PAAExtractor } from './extractor/PAAExtractor.js'\nimport { OutputSerializer } from './output/OutputSerializer.js'\nimport { ProgressReporter } from './output/ProgressReporter.js'\nimport { CaptchaError } from './errors.js'\n\nconst MAX_ATTEMPTS = 3\n\nasync function extractOnce(options: HarvestOptions): Promise<HarvestResult> {\n const driver = new BrowserDriver()\n const reporter = new ProgressReporter()\n const extractor = new PAAExtractor(driver, reporter)\n try {\n return await extractor.extract(options)\n } finally {\n await driver.close()\n }\n}\n\nexport async function harvest(rawOptions: unknown): Promise<HarvestResult> {\n const raw = typeof rawOptions === 'object' && rawOptions !== null ? rawOptions : {}\n const merged = {\n kernelApiKey: process.env.KERNEL_API_KEY?.trim(),\n kernelProxyId: process.env.KERNEL_PROXY_ID?.trim(),\n ...raw,\n }\n const options = HarvestOptionsSchema.parse(merged)\n const serializer = new OutputSerializer()\n\n for (let i = 0; i < MAX_ATTEMPTS; i++) {\n try {\n const result = await extractOnce(options)\n if (options.format === 'json' || options.format === 'both') {\n await serializer.writeJSON(result, options.outputDir)\n }\n if (options.format === 'csv' || options.format === 'both') {\n await Promise.all([\n serializer.writeCSV(result.flat, options.outputDir),\n result.videos.length > 0 ? serializer.writeVideoCSV(result.videos, result.seed, options.outputDir) : Promise.resolve(''),\n result.forums.length > 0 ? serializer.writeForumCSV(result.forums, result.seed, options.outputDir) : Promise.resolve(''),\n result.aiOverview.detected ? serializer.writeAIOverviewCSV(result.aiOverview.citations, result.aiOverview.text, result.seed, options.outputDir) : Promise.resolve(''),\n result.aiMode.detected ? serializer.writeAIModeCSV(result.aiMode.citations, result.aiMode.text, result.seed, options.outputDir) : Promise.resolve(''),\n result.whatPeopleSaying.length > 0 ? serializer.writeWhatPeopleSayingCSV(result.whatPeopleSaying, result.seed, options.outputDir) : Promise.resolve(''),\n ])\n }\n return result\n } catch (err) {\n if (err instanceof CaptchaError && i < MAX_ATTEMPTS - 1) {\n continue\n }\n throw err\n }\n }\n const sessionDesc = options.kernelApiKey ? `${MAX_ATTEMPTS} fresh Kernel.sh sessions` : `${MAX_ATTEMPTS} attempts`\n throw new CaptchaError(`CAPTCHA on all ${sessionDesc}. Try again in a few minutes.`)\n}\n","import { execSync } from 'node:child_process'\nimport { readFileSync, writeFileSync, unlinkSync, mkdirSync } from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport { join } from 'node:path'\nimport { fal } from '@fal-ai/client'\nimport { buildClipPrompts } from './promptBuilder.js'\nimport { generateVoiceover, addBackgroundAudio } from './AudioGenerator.js'\nimport { concatenateClips, uploadToFal, overlayVoiceover } from './VideoMixer.js'\n\nexport interface ClipPairOptions {\n resolution?: '480p' | '720p' | '1080p'\n aspectRatio?: '16:9' | '9:16' | '1:1'\n clipDurationSeconds?: number\n generateAudio?: boolean\n seed?: number\n outputDir?: string\n ttsVoice?: string\n}\n\nexport interface ClipPairResult {\n clip1Url: string\n clip2Url: string\n finalVideoPath: string\n seed: number\n promptClip1: string\n promptClip2: string\n voiceover: string\n audioMood: string\n}\n\ninterface VideoOutput { video: { url: string }; seed: number }\n\nconst T2V = 'bytedance/seedance-2.0/text-to-video'\nconst I2V = 'bytedance/seedance-2.0/image-to-video'\n\nfunction buildInput(prompt: string, opts: ClipPairOptions, seed?: number, imageUrl?: string) {\n return {\n prompt,\n resolution: opts.resolution ?? '720p',\n duration: opts.clipDurationSeconds ?? 8,\n aspect_ratio: opts.aspectRatio ?? '16:9',\n generate_audio: false,\n ...(seed !== undefined ? { seed } : {}),\n ...(imageUrl !== undefined ? { image_url: imageUrl } : {}),\n }\n}\n\nasync function generate(model: string, input: Record<string, unknown>): Promise<VideoOutput> {\n const { request_id } = await fal.queue.submit(model, { input })\n console.log(`[fal] submitted ${model} → ${request_id}`)\n while (true) {\n await new Promise(r => setTimeout(r, 5000))\n const s = await fal.queue.status(model, { requestId: request_id, logs: false })\n console.log(`[fal] ${request_id} → ${s.status}`)\n if ((s.status as string) === 'FAILED') throw new Error(`Request ${request_id} failed`)\n if ((s.status as string) !== 'COMPLETED') continue\n const result = await fal.queue.result(model, { requestId: request_id })\n return result.data as VideoOutput\n }\n}\n\nasync function extractLastFrame(videoUrl: string, outDir: string): Promise<string> {\n const ts = Date.now()\n const mp4Path = join(outDir, `clip1-raw-${ts}.mp4`)\n const jpgPath = join(outDir, `last-frame-${ts}.jpg`)\n\n const res = await fetch(videoUrl)\n if (!res.ok) throw new Error(`Failed to download clip 1 (${res.status})`)\n writeFileSync(mp4Path, Buffer.from(await res.arrayBuffer()))\n\n try {\n execSync(`ffmpeg -sseof -0.1 -i \"${mp4Path}\" -vframes 1 -y \"${jpgPath}\" -loglevel error`)\n } finally {\n try { unlinkSync(mp4Path) } catch {}\n }\n return jpgPath\n}\n\nexport class VideoGenerator {\n constructor(apiKey?: string) {\n const key = apiKey ?? process.env['FAL_KEY']\n if (!key) throw new Error('FAL_KEY is required')\n fal.config({ credentials: key })\n }\n\n async generateClipPair(\n question: string,\n answer: string,\n opts: ClipPairOptions = {},\n ): Promise<ClipPairResult> {\n const outDir = opts.outputDir ?? join(tmpdir(), `paa-video-${Date.now()}`)\n mkdirSync(outDir, { recursive: true })\n\n console.log('\\n[1/7] Generating prompts via QWEN 3.6...')\n const prompts = await buildClipPrompts(question, answer)\n console.log(' Voiceover:', prompts.voiceover)\n console.log(' Audio mood:', prompts.audioMood)\n\n console.log('\\n[2/7] Generating clip 1 (text-to-video)...')\n const result1 = await generate(T2V, buildInput(prompts.clip1, opts, opts.seed))\n\n console.log('\\n[3/7] Extracting last frame → clip 2 start...')\n const jpgPath = await extractLastFrame(result1.video.url, outDir)\n const imageBlob = new Blob([readFileSync(jpgPath)], { type: 'image/jpeg' })\n const frameUrl = await fal.storage.upload(imageBlob)\n try { unlinkSync(jpgPath) } catch {}\n\n console.log('\\n[4/7] Generating clip 2 (image-to-video from last frame)...')\n const seed2 = opts.seed !== undefined ? opts.seed + 1 : undefined\n const result2 = await generate(I2V, buildInput(prompts.clip2, opts, seed2, frameUrl))\n\n console.log('\\n[5/7] Concatenating clips + generating voiceover (parallel)...')\n const [combinedPath, voiceoverUrl] = await Promise.all([\n concatenateClips(result1.video.url, result2.video.url, outDir),\n generateVoiceover(prompts.voiceover, opts.ttsVoice),\n ])\n\n console.log('\\n[6/7] Adding background audio via MMAudio V2...')\n const falVideoUrl = await uploadToFal(combinedPath)\n const totalDuration = (opts.clipDurationSeconds ?? 8) * 2\n const videoWithAudioUrl = await addBackgroundAudio(falVideoUrl, prompts.audioMood, totalDuration)\n\n console.log('\\n[7/7] Overlaying voiceover on final video...')\n const videoWithAudioPath = join(outDir, `with-bg-audio-${Date.now()}.mp4`)\n const bgRes = await fetch(videoWithAudioUrl)\n writeFileSync(videoWithAudioPath, Buffer.from(await bgRes.arrayBuffer()))\n const finalVideoPath = await overlayVoiceover(videoWithAudioPath, voiceoverUrl, outDir)\n\n return {\n clip1Url: result1.video.url,\n clip2Url: result2.video.url,\n finalVideoPath,\n seed: result1.seed,\n promptClip1: prompts.clip1,\n promptClip2: prompts.clip2,\n voiceover: prompts.voiceover,\n audioMood: prompts.audioMood,\n }\n }\n}\n","export interface ClipPromptPair {\n clip1: string\n clip2: string\n voiceover: string\n audioMood: string\n}\n\nconst DEEPINFRA_URL = 'https://api.deepinfra.com/v1/openai/chat/completions'\nconst OPENROUTER_URL = 'https://openrouter.ai/api/v1/chat/completions'\nconst QWEN_MODEL = 'Qwen/Qwen3.6-35B-A3B'\n\nconst SYSTEM_PROMPT = `You are a video prompt engineer for Seedance 2.0 text-to-video AI.\n\nIMPORTANT TECHNICAL CONTEXT: Clip 2 will be generated using image-to-video, meaning it will start from the exact last frame of Clip 1. The two clips will be visually seamless — same location, same characters, continuous motion. You must write prompts that make this feel like one uninterrupted 16-second video.\n\nYour job: turn a PAA question and its answer into a complete short-form video with visuals, narration, and a background audio mood.\n\nProduce four things:\n\n1. clip1 (~8s): Show a real person experiencing the situation the question describes. End on a specific frozen moment — a held expression, a paused action — that clip 2 continues from.\n\n2. clip2 (~8s): Continue from that exact frozen frame. Deliver the informational payoff from the answer. Show specific facts playing out visually. Describe motion continuing from clip 1's ending frame, not a new scene.\n\n3. voiceover: A spoken narration that fits in 10 seconds of TTS audio. HARD LIMIT: 22 words maximum. Count every word before finalizing — if it exceeds 22 words, cut it. Starts with the problem, ends with the answer. No filler, no \"in conclusion\". Informational and direct.\n\n4. audioMood: 6-10 words describing INSTRUMENTAL background music only — no vocals, no voice, no lyrics. Describe instruments and mood (e.g. \"warm acoustic guitar, uplifting, professional home service, no vocals\"). Will be passed to an AI audio model.\n\nRules for visuals:\n- No text, captions, graphics, or overlays\n- Photorealistic, natural lighting, specific details\n- Describe exactly what the camera sees\n\nRespond with JSON only:\n{\"clip1\": \"...\", \"clip2\": \"...\", \"voiceover\": \"...\", \"audioMood\": \"...\"}`\n\ninterface ChatResponse {\n choices: Array<{ message: { content: string } }>\n}\n\nasync function callLLM(apiKey: string, baseUrl: string, question: string, answer: string): Promise<ClipPromptPair> {\n const res = await fetch(baseUrl, {\n method: 'POST',\n headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: QWEN_MODEL,\n temperature: 0.7,\n messages: [\n { role: 'system', content: SYSTEM_PROMPT },\n { role: 'user', content: `Question: ${question}\\n\\nAnswer: ${answer.slice(0, 500)}` },\n ],\n }),\n })\n if (!res.ok) throw new Error(`LLM call failed (${res.status}): ${await res.text()}`)\n\n const data = (await res.json()) as ChatResponse\n const raw = data.choices[0]?.message?.content?.trim() ?? ''\n const match = raw.match(/\\{[\\s\\S]*\\}/)\n if (!match) throw new Error(`No JSON in QWEN response: ${raw.slice(0, 200)}`)\n\n const parsed = JSON.parse(match[0]) as Partial<ClipPromptPair>\n if (!parsed.clip1 || !parsed.clip2 || !parsed.voiceover || !parsed.audioMood) {\n throw new Error(`QWEN response missing fields: ${raw.slice(0, 200)}`)\n }\n return parsed as ClipPromptPair\n}\n\nexport async function buildClipPrompts(question: string, answer: string): Promise<ClipPromptPair> {\n const deepinfraKey = process.env['DEEPINFRA_API_KEY']\n const openrouterKey = process.env['OPENROUTER_API_KEY']\n\n if (deepinfraKey) {\n try {\n return await callLLM(deepinfraKey, DEEPINFRA_URL, question, answer)\n } catch (err) {\n console.warn('[promptBuilder] DeepInfra failed, trying OpenRouter:', (err as Error).message)\n }\n }\n if (openrouterKey) {\n return await callLLM(openrouterKey, OPENROUTER_URL, question, answer)\n }\n throw new Error('No LLM key — set DEEPINFRA_API_KEY or OPENROUTER_API_KEY')\n}\n","const TTS_MODEL = 'fal-ai/inworld-tts'\nconst MMAUDIO_MODEL = 'fal-ai/mmaudio-v2'\nconst QUEUE_BASE = 'https://queue.fal.run'\n\ninterface TtsOutput { audio: { url: string } }\ninterface VideoOutput { video: { url: string } }\n\nasync function rawQueueRun(model: string, input: Record<string, unknown>, apiKey: string): Promise<Record<string, unknown>> {\n const headers = { 'Authorization': `Key ${apiKey}`, 'Content-Type': 'application/json' }\n\n const submitRes = await fetch(`${QUEUE_BASE}/${model}`, {\n method: 'POST', headers, body: JSON.stringify(input),\n })\n if (!submitRes.ok) throw new Error(`${model} submit failed (${submitRes.status}): ${await submitRes.text()}`)\n const { request_id } = await submitRes.json() as { request_id: string }\n console.log(`[fal] submitted ${model} → ${request_id}`)\n\n while (true) {\n await new Promise(r => setTimeout(r, 5000))\n const statusRes = await fetch(`${QUEUE_BASE}/${model}/requests/${request_id}/status`, { headers })\n if (!statusRes.ok) continue\n const { status } = await statusRes.json() as { status: string }\n console.log(`[fal] ${request_id} → ${status}`)\n if (status === 'FAILED') throw new Error(`${model} request ${request_id} failed`)\n if (status !== 'COMPLETED') continue\n const resultRes = await fetch(`${QUEUE_BASE}/${model}/requests/${request_id}`, { headers })\n if (!resultRes.ok) throw new Error(`Result fetch failed (${resultRes.status})`)\n return await resultRes.json() as Record<string, unknown>\n }\n}\n\nfunction getKey(): string {\n const key = process.env['FAL_KEY']\n if (!key) throw new Error('FAL_KEY required')\n return key\n}\n\nexport async function generateVoiceover(text: string, voice = 'Serena (en)'): Promise<string> {\n console.log('[AudioGenerator] Generating voiceover...')\n const out = await rawQueueRun(TTS_MODEL, { text, voice, sample_rate_hertz: 48000 }, getKey()) as unknown as TtsOutput\n return out.audio.url\n}\n\nexport async function addBackgroundAudio(videoUrl: string, mood: string, durationSeconds: number): Promise<string> {\n console.log('[AudioGenerator] Adding background audio via MMAudio V2...')\n const out = await rawQueueRun(MMAUDIO_MODEL, {\n video_url: videoUrl,\n prompt: mood,\n negative_prompt: 'speech, voice, talking, dialogue, narration, vocals, singing, human voice, conversation, words, lyrics, announcer, commentary',\n duration: durationSeconds,\n cfg_strength: 4.5,\n }, getKey()) as unknown as VideoOutput\n return out.video.url\n}\n","import { execSync } from 'node:child_process'\nimport { writeFileSync, mkdirSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { fal } from '@fal-ai/client'\n\nasync function download(url: string, destPath: string): Promise<void> {\n const res = await fetch(url)\n if (!res.ok) throw new Error(`Download failed (${res.status}): ${url}`)\n writeFileSync(destPath, Buffer.from(await res.arrayBuffer()))\n}\n\nexport async function concatenateClips(clip1Url: string, clip2Url: string, outDir: string): Promise<string> {\n mkdirSync(outDir, { recursive: true })\n const ts = Date.now()\n const p1 = join(outDir, `clip1-${ts}.mp4`)\n const p2 = join(outDir, `clip2-${ts}.mp4`)\n const out = join(outDir, `combined-${ts}.mp4`)\n\n console.log('[VideoMixer] Downloading clips...')\n await Promise.all([download(clip1Url, p1), download(clip2Url, p2)])\n\n console.log('[VideoMixer] Concatenating...')\n execSync(\n `ffmpeg -i \"${p1}\" -i \"${p2}\" -filter_complex \"[0:v][1:v]concat=n=2:v=1:a=0[v]\" -map \"[v]\" -y \"${out}\" -loglevel error`\n )\n return out\n}\n\nexport async function uploadToFal(localPath: string): Promise<string> {\n const { readFileSync } = await import('node:fs')\n const blob = new Blob([readFileSync(localPath)], { type: 'video/mp4' })\n const url = await fal.storage.upload(blob)\n console.log('[VideoMixer] Uploaded to fal:', url)\n return url\n}\n\nexport async function overlayVoiceover(\n videoPath: string,\n voiceoverUrl: string,\n outDir: string,\n): Promise<string> {\n const ts = Date.now()\n const wav = join(outDir, `voiceover-${ts}.wav`)\n const out = join(outDir, `final-${ts}.mp4`)\n\n console.log('[VideoMixer] Downloading voiceover...')\n await download(voiceoverUrl, wav)\n\n console.log('[VideoMixer] Mixing voiceover over background audio...')\n execSync(\n `ffmpeg -i \"${videoPath}\" -i \"${wav}\" ` +\n `-filter_complex \"[0:a]volume=0.2[bg];[1:a]volume=1.0[vo];[bg][vo]amix=inputs=2:duration=first[a]\" ` +\n `-map 0:v -map \"[a]\" -c:v copy -y \"${out}\" -loglevel error`\n )\n return out\n}\n"],"mappings":"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","names":["StealthPlugin","Kernel","playwrightChromium","s","organicResults","localPack","rawEntityIds","entityIds","allOrganic","stats","aiSurfaces","fs","path","Papa","import_node_child_process","import_node_fs","import_node_path","import_client","import_node_fs","import_node_path","readFileSync"]}
@@ -0,0 +1,210 @@
1
+ import { z } from 'zod';
2
+
3
+ declare const HarvestOptionsSchema: z.ZodObject<{
4
+ query: z.ZodString;
5
+ location: z.ZodOptional<z.ZodString>;
6
+ gl: z.ZodDefault<z.ZodString>;
7
+ hl: z.ZodDefault<z.ZodString>;
8
+ depth: z.ZodDefault<z.ZodNumber>;
9
+ maxQuestions: z.ZodDefault<z.ZodNumber>;
10
+ headless: z.ZodDefault<z.ZodBoolean>;
11
+ profileDir: z.ZodOptional<z.ZodString>;
12
+ proxy: z.ZodOptional<z.ZodString>;
13
+ kernelApiKey: z.ZodOptional<z.ZodString>;
14
+ kernelProxyId: z.ZodOptional<z.ZodString>;
15
+ outputDir: z.ZodDefault<z.ZodString>;
16
+ format: z.ZodDefault<z.ZodEnum<["json", "csv", "both"]>>;
17
+ serpOnly: z.ZodDefault<z.ZodBoolean>;
18
+ pages: z.ZodDefault<z.ZodNumber>;
19
+ }, "strip", z.ZodTypeAny, {
20
+ query: string;
21
+ gl: string;
22
+ hl: string;
23
+ depth: number;
24
+ maxQuestions: number;
25
+ headless: boolean;
26
+ outputDir: string;
27
+ format: "json" | "csv" | "both";
28
+ serpOnly: boolean;
29
+ pages: number;
30
+ location?: string | undefined;
31
+ profileDir?: string | undefined;
32
+ proxy?: string | undefined;
33
+ kernelApiKey?: string | undefined;
34
+ kernelProxyId?: string | undefined;
35
+ }, {
36
+ query: string;
37
+ location?: string | undefined;
38
+ gl?: string | undefined;
39
+ hl?: string | undefined;
40
+ depth?: number | undefined;
41
+ maxQuestions?: number | undefined;
42
+ headless?: boolean | undefined;
43
+ profileDir?: string | undefined;
44
+ proxy?: string | undefined;
45
+ kernelApiKey?: string | undefined;
46
+ kernelProxyId?: string | undefined;
47
+ outputDir?: string | undefined;
48
+ format?: "json" | "csv" | "both" | undefined;
49
+ serpOnly?: boolean | undefined;
50
+ pages?: number | undefined;
51
+ }>;
52
+
53
+ interface HarvestStats {
54
+ seed: string;
55
+ totalQuestions: number;
56
+ maxDepthReached: number;
57
+ durationMs: number;
58
+ errorCount: number;
59
+ }
60
+ interface PAANode {
61
+ question: string;
62
+ answer: string | null;
63
+ sourceTitle: string | null;
64
+ sourceSite: string | null;
65
+ sourceCite: string | null;
66
+ depth: number;
67
+ parentQuestion: string | null;
68
+ children: PAANode[];
69
+ }
70
+ interface FlatRow {
71
+ seed_query: string;
72
+ question: string;
73
+ answer: string;
74
+ source_title: string;
75
+ source_site: string;
76
+ source_cite: string;
77
+ depth: number;
78
+ parent_question: string;
79
+ extracted_at: string;
80
+ }
81
+ interface VideoResult {
82
+ type: 'video' | 'short_video';
83
+ title: string;
84
+ channel: string;
85
+ platform: string;
86
+ duration: string;
87
+ url: string;
88
+ }
89
+ interface ForumResult {
90
+ title: string;
91
+ source: string;
92
+ url: string;
93
+ }
94
+ interface WhatPeopleSayingCard {
95
+ type: 'reddit' | 'facebook' | 'instagram' | 'tiktok' | 'youtube' | 'news' | 'unknown';
96
+ title: string;
97
+ url: string;
98
+ source: string;
99
+ platform: string;
100
+ popularComment: string | null;
101
+ engagement: string;
102
+ date: string;
103
+ duration: string | null;
104
+ authorNote: string | null;
105
+ }
106
+ interface AICitation {
107
+ text: string;
108
+ href: string;
109
+ }
110
+ interface AIOverviewResult {
111
+ detected: boolean;
112
+ text: string | null;
113
+ citations: AICitation[];
114
+ }
115
+ interface AIModeResult {
116
+ detected: boolean;
117
+ text: string | null;
118
+ citations: AICitation[];
119
+ }
120
+ type GoogleSurface = 'web' | 'aim' | 'unknown';
121
+ interface OrganicResult {
122
+ position: number;
123
+ title: string;
124
+ url: string;
125
+ domain: string;
126
+ cite: string | null;
127
+ snippet: string | null;
128
+ isRedditStyle: boolean;
129
+ inlineRating: {
130
+ value: string;
131
+ count: string;
132
+ } | null;
133
+ }
134
+ interface LocalPackBusiness {
135
+ position: number;
136
+ name: string;
137
+ cid: string | null;
138
+ rating: string | null;
139
+ reviewCount: string | null;
140
+ metadata: string[];
141
+ websiteUrl: string | null;
142
+ directionsUrl: string | null;
143
+ }
144
+ interface EntityRecord {
145
+ name: string;
146
+ kgId: string | null;
147
+ cid: string | null;
148
+ gcid: string | null;
149
+ }
150
+ interface EntityIds {
151
+ entities: EntityRecord[];
152
+ kgIds: string[];
153
+ cids: string[];
154
+ gcids: string[];
155
+ }
156
+ interface HarvestResult {
157
+ seed: string;
158
+ location: string | null;
159
+ extractedAt: string;
160
+ totalQuestions: number;
161
+ surface: GoogleSurface;
162
+ aiOverview: AIOverviewResult;
163
+ aiMode: AIModeResult;
164
+ whatPeopleSaying: WhatPeopleSayingCard[];
165
+ tree: PAANode[];
166
+ flat: FlatRow[];
167
+ videos: VideoResult[];
168
+ forums: ForumResult[];
169
+ organicResults: OrganicResult[];
170
+ localPack: LocalPackBusiness[];
171
+ entityIds: EntityIds;
172
+ stats: HarvestStats;
173
+ }
174
+ type HarvestOptions = z.infer<typeof HarvestOptionsSchema>;
175
+
176
+ declare function harvest(rawOptions: unknown): Promise<HarvestResult>;
177
+
178
+ interface ClipPairOptions {
179
+ resolution?: '480p' | '720p' | '1080p';
180
+ aspectRatio?: '16:9' | '9:16' | '1:1';
181
+ clipDurationSeconds?: number;
182
+ generateAudio?: boolean;
183
+ seed?: number;
184
+ outputDir?: string;
185
+ ttsVoice?: string;
186
+ }
187
+ interface ClipPairResult {
188
+ clip1Url: string;
189
+ clip2Url: string;
190
+ finalVideoPath: string;
191
+ seed: number;
192
+ promptClip1: string;
193
+ promptClip2: string;
194
+ voiceover: string;
195
+ audioMood: string;
196
+ }
197
+ declare class VideoGenerator {
198
+ constructor(apiKey?: string);
199
+ generateClipPair(question: string, answer: string, opts?: ClipPairOptions): Promise<ClipPairResult>;
200
+ }
201
+
202
+ interface ClipPromptPair {
203
+ clip1: string;
204
+ clip2: string;
205
+ voiceover: string;
206
+ audioMood: string;
207
+ }
208
+ declare function buildClipPrompts(question: string, answer: string): Promise<ClipPromptPair>;
209
+
210
+ export { type AICitation, type AIModeResult, type AIOverviewResult, type ClipPairOptions, type ClipPairResult, type FlatRow, type GoogleSurface, type HarvestOptions, type HarvestResult, type HarvestStats, type PAANode, VideoGenerator, type WhatPeopleSayingCard, buildClipPrompts, harvest };